using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; //***************************************************************************** // Copyright 2020 Sensus GmbH Ludwigshafen. All rights reserved. // Author: Venkat, Rajeshwar //***************************************************************************** namespace Sensus.iPerl.NfcHandler { public static class Tools { public static bool ByteArrayCompare(byte[] a1, byte[] a2) { // thanks to https://stackoverflow.com/questions/43289/comparing-two-byte-arrays-in-net if (a1.Length != a2.Length) return false; for (int i = 0; i < a1.Length; i++) if (a1[i] != a2[i]) return false; return true; } public static string SwapHex(string sHex) { string sResult = ""; int iPos = sHex.Length - 2; while (iPos >= 0) { sResult += sHex.Substring(iPos, 2); sHex = sHex.Remove(iPos, 2); iPos = sHex.Length - 2; } return sResult; } public static string DecimalToHexString(string value, int size = 1) { try { long Lval = long.Parse(value); if (size == 1) return Lval.ToString("X2"); if (size == 2) return Lval.ToString("X4"); if (size == 4) return Lval.ToString("X8"); } catch (Exception) { if (size == 1) return "00"; if (size == 2) return "0000"; if (size == 4) return "00000000"; } return "00"; } public static string ByteToHexString(byte data) { List val = new List(); val.Add(data); byte[] arr = val.ToArray(); return BytesToHex(arr); } public static string BytesToHex(byte[] data) { StringBuilder sb = new StringBuilder(); foreach (byte b in data) sb.Append(b.ToString("X2")); return sb.ToString(); } public static byte[] HexStringToByteArray(String hexString) { int numberChars = hexString.Length; byte[] bytes = new byte[numberChars / 2]; for (int i = 0; i < numberChars; i += 2) { bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); } return bytes; } public enum InitialCrcValue { Zeros, NonZero1 = 0xffff, NonZero2 = 0x1D0F } public class Crc16Ccitt { private const ushort poly = 0x1021; ushort[] table = new ushort[256]; ushort initialValue = 0; public ushort ComputeChecksum(byte[] bytes) { ushort crc = this.initialValue; for (int i = 0; i < bytes.Length; ++i) { crc = (ushort)((crc << 8) ^ table[((crc >> 8) ^ (0xff & bytes[i]))]); } return crc; } public byte[] ComputeChecksumBytes(byte[] bytes) { ushort crc = ComputeChecksum(bytes); return BitConverter.GetBytes(crc); } public Crc16Ccitt(InitialCrcValue initialValue) { this.initialValue = (ushort) initialValue; ushort temp, a; for (int i = 0; i < table.Length; ++i) { temp = 0; a = (ushort) (i << 8); for (int j = 0; j < 8; ++j) { if (((temp ^ a) & 0x8000) != 0) { temp = (ushort) ((temp << 1) ^ poly); } else { temp <<= 1; } a <<= 1; } table[i] = temp; } } public byte[] calcCRCfromMessage(byte[] message) { // CRC calculation goes from MessageID to Password // For Read this means MsgID (1) + Offset (2) + PayloadLength (1) + Password (2) = 6 // for write the length of the payload comes on top. // STX(1), length(1), CRC(2) and ETX(1) are excluded, in total 5 bytes. // // the method works both for sending messages (where the CRC and ETX are not in message) // and for receiving messages (where the CRC and ETX are included at the end) byte[] crc_msg = new byte[message[1]]; // message length is 2nd byte Array.Copy(message, 2, crc_msg, 0, crc_msg.Length); return ComputeChecksumBytes(crc_msg); } public string commentCRC(byte[] crc_meter, byte[] crc_computed) { bool crc_do_match = Tools.ByteArrayCompare(crc_meter, crc_computed); string crcComment = crc_do_match ? "ok." : "CRC DOESN'T MATCH!!"; return "CRC Meter: " + Tools.BytesToHex(crc_meter) + (crc_do_match ? " == " : " != ") + "CRC Computed: " + Tools.BytesToHex(crc_computed) + ". " + crcComment; } public bool crc_do_match(byte[] a, byte[] b) { return ByteArrayCompare(a, b); } } } }