/// /// Copyright (c) 2013-2019 Sensus Metering Systems /// using System; using System.Collections.Generic; namespace TBF.BenchControl { public class Telegram { const UInt16 crcSeed = 0xFFFF; // Initial crc value const UInt16 crcGP = 0xA001; // Generating polynomial /// /// For standard CRC16 (remainder of division) /// to start a new crc, set CRC16 = SEED /// then for each byte call UpdateCRC(byte, &CRC16); /// CRC16 will contain the result /// (if you calculate all of the incoming data /// INCLUDING the crc, the result should be 0x0000 /// and if you are sending the crc be sure to /// send the bytes in the correct order) /// static void UpdateCRC(byte b, ref UInt16 crc) { crc ^= (UInt16)b; for (int i = 0; i < 8; i++) { bool carry = (crc & 0x0001) != 0; crc >>= 1; if (carry) crc ^= crcGP; } } /// /// Calculates the CRC from a data telegram (an array of bytes). /// A complete telegram including two bytes reserved for the CRC /// must be supplied as an argument. /// /// Data telegram /// Calculated CRC public static UInt16 ClaculateTelegramCRC(byte[] data) { UInt16 crc = crcSeed; for (int i = 0; i < data.Length - 2; i++) UpdateCRC(data[i], ref crc); return crc; } /// /// This function modifies the last 2 bytes in the message buffer /// by the CRC calculated from the remaining first (Lenght - 2) bytes. /// A complete telegram including two bytes reserved for the CRC /// must be supplied as an argument. /// /// Data telegram public static void UpdateTelegramCRC(byte[] data) { int len = data.Length; if (len < 2) return; UInt16 crc = ClaculateTelegramCRC(data); data[len - 2] = (byte)(crc & 0xFF); data[len - 1] = (byte)(crc >> 8); } /// /// This function compares the last 2 bytes in the message buffer /// with the CRC calculated from the remaining first (Lenght - 2) bytes. /// A complete telegram including two bytes reserved for the CRC /// must be supplied as an argument. /// /// Data telegram /// true if the CRC in the telegram is correct public static bool VerifyTelegramCRC(byte[] data) { int len = data.Length; if (len < 2) return false; UInt16 crc = ClaculateTelegramCRC(data); return (data[len - 2] == (byte)(crc & 0xFF)) && (data[len - 1] == (byte)(crc >> 8)); } /// /// Calculates the checksum from a data telegram (an array of bytes). /// A complete telegram including one byte reserved for the checksum /// must be supplied as an argument. /// /// Data telegram /// Calculated checksum public static byte ClaculateTelegramChecksum(byte[] data) { byte checksum = 0; for (int i = 0; i < data.Length - 1; i++) checksum = (byte)(checksum ^ data[i]); return checksum; } /// /// Calculates the checksum from a data telegram (an array of bytes). /// A complete telegram including one bytes reserved for the checksum /// must be supplied as an argument. /// /// Length of HART telegram preamble (FF bytes) /// Data telegram /// Calculated checksum public static byte ClaculateTelegramChecksum(int hartPreambLen, byte[] data) { byte checksum = 0; for (int i = hartPreambLen; i < data.Length - 1; i++) checksum = (byte)(checksum ^ data[i]); return checksum; } /// /// This function modifies the last byte in the message buffer /// by the checksum calculated from the remaining first (Lenght - 1) bytes. /// A complete telegram including one bytes reserved for the checksum /// must be supplied as an argument. /// /// Data telegram public static void UpdateTelegramChecksum(byte[] data) { int len = data.Length; if (len < 1) return; data[len - 1] = ClaculateTelegramChecksum(data); } /// /// This function modifies the last byte in the message buffer /// by the checksum calculated from the preceeding (Lenght - hartPreambLen - 1) bytes. /// First hartPreambLen bytes in the telegram are skipped. /// A complete telegram including preamble and one bytes reserved for the checksum /// after data bytes must be supplied as an argument. /// /// Length of HART telegram preamble (FF bytes) /// Data telegram public static void UpdateTelegramChecksum(int hartPreambLen, byte[] data) { if (data.Length - hartPreambLen < 1) return; data[data.Length - 1] = ClaculateTelegramChecksum(hartPreambLen, data); } /// /// This function compares the last byte in the message buffer /// with the checksum calculated from the remaining first (Lenght - 1) bytes. /// A complete telegram including two bytes reserved for the checksum /// must be supplied as an argument. /// /// Data telegram /// true if the checksum in the telegram is correct public static bool VerifyTelegramChecksum(byte[] data) { int len = data.Length; if (len < 1) return false; return (data[len - 1] == ClaculateTelegramChecksum(data)); } /// /// This function compares the last byte in the message buffer /// with the checksum calculated from the remaining first (Lenght - 1) bytes. /// A complete telegram including two bytes reserved for the checksum /// must be supplied as an argument. /// /// Length of HART telegram preamble (FF bytes) /// Data telegram /// true if the checksum in the telegram is correct public static bool VerifyTelegramChecksum(int hartPreambLen, byte[] data) { if (data.Length - hartPreambLen < 1) return false; return (data[data.Length - 1] == ClaculateTelegramChecksum(hartPreambLen, data)); } public static string LogTelegram(string intro, byte[] data, int from = 0, int len = -1) { System.Text.StringBuilder sb = new System.Text.StringBuilder(256); int length = (len >= 0) ? len : (data.Length - from); sb.Append(intro); sb.Append(length.ToString()); sb.Append(" bytes:"); for (int i = from; i < from + length; i++) { byte b = data[i]; sb.Append(" "); sb.Append(((int)b).ToString("X2")); } return sb.ToString(); } public static string LogTelegram(string intro, IList data, int from = 0, int len = -1) { System.Text.StringBuilder sb = new System.Text.StringBuilder(256); int length = (len >= 0) ? len : (data.Count - from); sb.Append(intro); sb.Append(length.ToString()); sb.Append(" bytes:"); for (int i = from; i < from + length; i++) { byte b = data[i]; sb.Append(" "); sb.Append(((int)b).ToString("X2")); } return sb.ToString(); } public static string LogTelegram(string intro, string data) { System.Text.StringBuilder sb = new System.Text.StringBuilder(80); sb.Append(intro); sb.Append(data.Length.ToString()); sb.Append(" bytes:"); foreach (var d in data) { sb.Append(" "); sb.Append(((int)d).ToString("X2")); } return sb.ToString(); } } }