1 /// 2 module modbus.backend.tcp; 3 4 import modbus.backend.base; 5 6 /// 7 class TCP : BaseBackend!260 8 { 9 protected: 10 // transaction id size + protocol id size + packet length size 11 enum packedServiceData = ushort.sizeof * 3; 12 enum packedLengthOffset = ushort.sizeof * 2; 13 public: 14 /// 15 this(Connection c, SpecRules s=null) 16 { super(c, s, packedServiceData, packedServiceData); } 17 18 override: 19 20 /// 21 void start(ulong dev, ubyte func) 22 { 23 short zero = 0; 24 // transaction id 25 append(zero); 26 // protocol id 27 append(zero); 28 // packet length (change in send) 29 append(zero); 30 appendDF(dev, func); 31 } 32 33 /// 34 void send() 35 { 36 import std.bitmanip : nativeToBigEndian; 37 scope (exit) idx = 0; 38 auto dsize = cast(ushort)(idx - packedServiceData); 39 enum plo = packedLengthOffset; 40 buffer[plo..plo+ushort.sizeof] = nativeToBigEndian(dsize); 41 conn.write(buffer[0..idx]); 42 43 version (modbus_verbose) 44 .trace("write bytes: ", buffer[0..idx]); 45 } 46 47 /// 48 Response read(size_t expectedBytes) 49 { 50 import std.bitmanip : bigEndianToNative; 51 52 auto res = baseRead(expectedBytes, true); 53 auto tmp = cast(ubyte[])res.data; 54 55 auto plen = bigEndianToNative!ushort(cast(ubyte[2])tmp[4..6]); 56 57 if (tmp.length != plen+packedServiceData) 58 throw readDataLengthException(res.dev, res.fnc, 59 plen+packedServiceData, tmp.length); 60 61 res.data = tmp[devOffset+sr.deviceTypeSize+functionTypeSize..$]; 62 63 return res; 64 } 65 } 66 67 unittest 68 { 69 import std.array : appender; 70 auto buf = appender!(ubyte[]); 71 auto tcp = new TCP(new class Connection 72 { 73 override void write(const(void)[] data) 74 { buf.put(cast(const(ubyte)[])data); } 75 override void[] read(void[] buffer) 76 { return buffer[0..1]; } 77 }); 78 tcp.start(1,2); 79 int xx = 123; 80 tcp.append(xx); 81 tcp.send(); 82 assert (buf.data == [0,0, 0,0, 0,6, 1, 2, 0,0,0,123]); 83 }