1 /// 2 module modbus.backend.rtu; 3 4 import std.datetime : Clock; 5 6 import modbus.backend.base; 7 8 /// 9 class RTU : BaseBackend 10 { 11 protected: 12 enum lengthOfCRC = 2; 13 ulong stamp; 14 15 public: 16 /// 17 this(SpecRules s=null) { super(s, lengthOfCRC, 0); } 18 19 protected override: 20 void startMessage(void[] buf, ref size_t idx, ulong dev, ubyte fnc, ulong stamp) 21 { appendDF(buf, idx, dev, fnc); } 22 23 void finalizeMessage(void[] buf, ref size_t idx) 24 { appendBytes(buf, idx, cast(void[])crc16(buf[0..idx])); } 25 26 bool check(const(void)[] data) { return checkCRC(data); } 27 28 ulong getStamp(const(void)[] data) 29 { 30 // TODO: rework 31 return stamp++; 32 } 33 34 size_t endDataSplit() @property { return lengthOfCRC; } 35 } 36 37 unittest 38 { 39 import std.algorithm; 40 import std.bitmanip; 41 42 void[100] data = void; 43 44 auto rtu = new RTU(); 45 enum C1 = ushort(10100); 46 enum C2 = ushort(12345); 47 auto buf = cast(ubyte[])rtu.buildMessage(data, 1, 6, 0, C1, C2); 48 assert(equal(buf[0..$-2], cast(ubyte[])[1, 6] ~ 49 nativeToBigEndian(C1) ~ 50 nativeToBigEndian(C2))); 51 52 auto crc = cast(ubyte[])crc16(buf[0..$-2]).dup; 53 assert(crc[0] == (cast(ubyte[])buf)[$-2]); 54 assert(crc[1] == (cast(ubyte[])buf)[$-1]); 55 } 56 57 /++ Check CRC16 of data 58 Params: 59 data = last two bytes used as CRC16 60 +/ 61 bool checkCRC(const(void)[] data) pure nothrow @trusted @nogc 62 { 63 auto msg = cast(const(ubyte[]))data; 64 auto a = msg[$-2..$]; 65 auto b = crc16(msg[0..$-2]); 66 return a[0] == b[0] && a[1] == b[1]; 67 } 68 69 @safe unittest 70 { 71 immutable ubyte[] d1 = [0x02, 0x03, 0x00, 0x00, 0x00, 0x05, 0x85, 0xFA]; 72 immutable ubyte[] d2 = [0x01, 0x04, 0x02, 0xFF, 0xFF, 0xB8, 0x80]; 73 immutable ubyte[] d3 = [0x01, 0x04, 0x02, 0xFF, 0xFF, 0xB8, 0x00]; // invalid frame 74 75 assert(d1.checkCRC); 76 assert(d2.checkCRC); 77 assert(!d3.checkCRC); 78 } 79 80 /++ Calculate CRC16 81 Params: 82 data = input data for calculation CRC16 83 +/ 84 ubyte[2] crc16(const(void)[] data) pure nothrow @trusted @nogc 85 { 86 ubyte hi = 0xFF; 87 ubyte lo = 0xFF; 88 89 size_t idx; 90 91 foreach (val; cast(ubyte[])data) 92 { 93 idx = lo ^ val; 94 lo = hi ^ tblLo[idx]; 95 hi = tblHi[idx]; 96 } 97 98 return [lo, hi]; 99 } 100 101 @safe unittest 102 { 103 immutable ubyte[] data = [0x02, 0x03, 0x00, 0x00, 0x00, 0x05]; 104 assert(crc16(data)[1] == 0xFA); 105 assert(crc16(data)[0] == 0x85); 106 } 107 108 private: 109 static immutable ubyte[256] tblLo = [ 110 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 111 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 112 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 113 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 114 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 115 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 116 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 117 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 118 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 119 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 120 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 121 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 122 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 123 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 124 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 125 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 126 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 127 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 128 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 129 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 130 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 131 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 132 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 133 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 134 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 135 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40]; 136 137 static immutable ubyte[256] tblHi = [ 138 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 139 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 140 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 141 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 142 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 143 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 144 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 145 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 146 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 147 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 148 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 149 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 150 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 151 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 152 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 153 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 154 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 155 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 156 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 157 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 158 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 159 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 160 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 161 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 162 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 163 0x43, 0x83, 0x41, 0x81, 0x80, 0x40];