1 /// 2 module modbus.backend.base; 3 4 version (modbus_verbose) 5 public import std.experimental.logger; 6 7 import modbus.protocol; 8 public import modbus.exception; 9 public import modbus.backend.connection; 10 public import modbus.backend.specrules; 11 12 /++ Basic functionality of Modbus.Backend 13 14 Params: 15 BUFFER_SIZE = static size of message buffer 16 +/ 17 class BaseBackend(size_t BUFFER_SIZE) : Modbus.Backend 18 { 19 protected: 20 enum functionTypeSize = 1; 21 Connection conn; 22 SpecRules sr; 23 24 ubyte[BUFFER_SIZE] buffer; 25 size_t idx; 26 immutable size_t minimumMsgLength; 27 immutable size_t devOffset; 28 immutable size_t serviceData; 29 30 public: 31 32 /++ 33 Params: 34 c = connection 35 s = rules for pack N-byte data to sending package 36 serviceData = size of CRC for RTU, protocol id for TCP etc 37 deviceOffset = offset of device number (address) in message 38 +/ 39 this(Connection c, SpecRules s, size_t serviceData, size_t deviceOffset) 40 { 41 if (c is null) 42 throw modbusException("connection is null"); 43 conn = c; 44 sr = s !is null ? s : new BasicSpecRules; 45 this.serviceData = serviceData; 46 devOffset = deviceOffset; 47 48 minimumMsgLength = serviceData + sr.deviceTypeSize + functionTypeSize; 49 } 50 51 abstract override 52 { 53 void start(ulong dev, ubyte func); 54 void send(); 55 Response read(size_t expectedBytes); 56 } 57 58 override 59 { 60 void append(byte v) { append(sr.pack(v)); } 61 void append(short v) { append(sr.pack(v)); } 62 void append(int v) { append(sr.pack(v)); } 63 void append(long v) { append(sr.pack(v)); }; 64 void append(float v) { append(sr.pack(v)); }; 65 void append(double v) { append(sr.pack(v)); }; 66 67 void append(const(void)[] v) 68 { 69 scope (failure) idx = 0; 70 auto inc = v.length; 71 if (idx + inc + serviceData >= buffer.length) 72 throw modbusException("many args"); 73 buffer[idx..idx+inc] = cast(ubyte[])v; 74 idx += inc; 75 version (modbus_verbose) 76 .trace("append msg buffer data: ", buffer[0..idx]); 77 } 78 79 bool messageComplite() const @property { return idx == 0; } 80 const(void)[] tempBuffer() const @property { return buffer[0..idx]; } 81 } 82 83 protected: 84 85 void appendDF(ulong dev, ubyte fnc) { append(sr.packDF(dev, fnc)); } 86 87 Response baseRead(size_t expectedBytes, bool allocateOnlyExpected=false) 88 { 89 expectedBytes += minimumMsgLength; 90 version (modbus_verbose) .tracef("start read %d bytes", expectedBytes); 91 92 auto buf = buffer[]; 93 if (allocateOnlyExpected) buf = buf[0..expectedBytes]; 94 auto tmp = cast(ubyte[])conn.read(buf); 95 version (modbus_verbose) .trace(" readed bytes: ", tmp); 96 97 if (tmp.length < devOffset+sr.deviceTypeSize+functionTypeSize) 98 throw readDataLengthException(0, 0, expectedBytes, tmp.length); 99 100 Response res; 101 sr.peekDF(tmp[devOffset..$], res.dev, res.fnc); 102 res.data = tmp; 103 104 if (tmp.length < minimumMsgLength+1) 105 throw readDataLengthException(res.dev, res.fnc, expectedBytes, tmp.length); 106 107 if (res.data.length > expectedBytes) 108 { 109 version (modbus_verbose) 110 .warningf("receive more bytes what expected (%d): %(0x%02x %)", 111 expectedBytes, tmp[expectedBytes..$]); 112 113 res.data = res.data[0..expectedBytes]; 114 } 115 116 return res; 117 } 118 }