1 /// 2 module modbus; 3 4 public: 5 import modbus.exception; 6 import modbus.protocol; 7 import modbus.facade; 8 import modbus.backend.connection; 9 import modbus.backend.specrules; 10 11 unittest 12 { 13 static import std.bitmanip; 14 alias bwrite = std.bitmanip.write; 15 alias bread = std.bitmanip.read; 16 import modbus.backend; 17 18 static class ModbusEmulator 19 { 20 align(1) 21 static struct DeviceData 22 { 23 align(1): 24 ushort[4] simpleRegister; // 0..3 25 int intValue; // 4 26 float floatValue; // 6 27 } 28 29 SpecRules sr; 30 DeviceData[size_t] regs; 31 ubyte[256] res; 32 size_t idx; 33 34 this(SpecRules sr) 35 { 36 regs[70000] = DeviceData([1234, 10405, 12, 42], 3^^12, 3.14); 37 regs[1] = DeviceData([2345, 50080, 34, 42], 7^^9, 2.71); 38 this.sr = sr; 39 } 40 41 void write(const(void)[] msg) 42 { 43 idx = 0; 44 auto ubmsg = cast(const(ubyte)[])msg; 45 ulong dev; 46 ubyte fnc; 47 sr.peekDF(ubmsg, dev, fnc); 48 ubmsg = ubmsg[sr.deviceTypeSize+1..$]; 49 50 import std.stdio; 51 52 if (dev !in regs) return; 53 54 res[idx..idx+sr.deviceTypeSize] = cast(ubyte[])sr.packDF(dev, fnc)[0..sr.deviceTypeSize]; 55 idx += sr.deviceTypeSize; 56 57 if (!checkCRC(msg)) 58 storeFail(fnc, FunctionErrorCode.ILLEGAL_DATA_VALUE); 59 else 60 { 61 bwrite(res[], fnc, &idx); 62 63 switch (fnc) 64 { 65 case 4: 66 auto d = (cast(ushort*)(dev in regs))[0..DeviceData.sizeof/2]; 67 auto st = bread!ushort(ubmsg); 68 auto cnt = cast(ubyte)bread!ushort(ubmsg); 69 bwrite(res[], cnt, &idx); 70 foreach (i; 0 .. cnt) 71 bwrite(res[], d[st+i], &idx); 72 break; 73 default: 74 storeFail(fnc, FunctionErrorCode.ILLEGAL_DATA_VALUE); 75 break; 76 } 77 } 78 79 storeCRC(); 80 } 81 82 void[] read(void[] buffer) 83 { 84 buffer[0..idx] = res[0..idx]; 85 return buffer[0..idx]; 86 } 87 88 void storeFail(ubyte fnc, FunctionErrorCode c) 89 { 90 bwrite(res[], cast(ubyte)(fnc|0xF0), &idx); 91 bwrite(res[], cast(ubyte)c, &idx); 92 } 93 94 void storeCRC() 95 { 96 auto crc = crc16(res[0..idx]); 97 bwrite(res[], crc[0], &idx); 98 bwrite(res[], crc[1], &idx); 99 } 100 } 101 102 BasicSpecRules sr = new PilotBMSSpecRules; 103 104 auto com = new ModbusEmulator(sr); 105 106 auto mbus = new Modbus(new RTU(new class Connection{ 107 override: 108 void write(const(void)[] msg) { com.write(msg); } 109 void[] read(void[] buffer) { return com.read(buffer); } 110 }, sr)); 111 112 assert(mbus.readInputRegisters(70000, 0, 1)[0] == 1234); 113 assert(equal(mbus.readInputRegisters(1, 0, 4), [2345, 50080, 34, 42])); 114 }