1 /// 2 module modbus.protocol.slave.slave; 3 4 import modbus.protocol.base; 5 public import modbus.types; 6 7 import modbus.protocol.slave.model; 8 import modbus.protocol.slave.types; 9 10 import modbus.cbuffer; 11 12 /++ Base class for modbus slave devices 13 14 Iteration and message parsing process 15 16 Define types 17 +/ 18 class ModbusSlave : Modbus 19 { 20 protected: 21 size_t readed; 22 23 void[MAX_BUFFER] responseBuffer; 24 void[MAX_BUFFER*2] findMsgBuf; 25 26 class MBSRW : ResponseWriter 27 { 28 override @property 29 { 30 Backend backend() { return this.outer.be; } 31 protected void[] buffer() { return responseBuffer; } 32 } 33 } 34 35 MBSRW rw; 36 37 StopWatch dt; 38 39 ModbusSlaveModel model; 40 41 /// 42 alias Reaction = ModbusSlaveModel.Reaction; 43 44 /// process message and send result if needed 45 void processMessage(ref const Message msg) 46 { 47 import std.experimental.logger : errorf; 48 49 Response res; 50 try 51 { 52 auto pm = model.checkDeviceNumber(msg.dev); 53 if (pm == Reaction.none) return; 54 res = model.onMessage(rw, msg); 55 if (pm == Reaction.processAndAnswer) 56 this.writeS(msg.dev, msg.fnc | (res.error ? 0x80 : 0), msg.stamp, res.data); 57 } 58 catch (SlaveFuncProcessException e) 59 { 60 errorf("%s", e); 61 this.writeS(msg.dev, msg.fnc | 0x80, msg.stamp, e.code); 62 } 63 catch (Throwable e) 64 { 65 errorf("%s", e); 66 this.writeS(msg.dev, msg.fnc | 0x80, msg.stamp, 67 FunctionErrorCode.slaveDeviceFailure); 68 } 69 } 70 71 CBuffer cbuffer; 72 73 enum MIN_MSG = 4; 74 75 MessageFinder messageFinder; 76 77 public: 78 79 /// 80 static class MessageFinder 81 { 82 Backend backend; 83 84 final bool testMessage(const(void)[] data, ref Message msg) 85 { return backend.parseMessage(data, msg) == backend.ParseResult.success; } 86 87 /// 88 abstract ptrdiff_t[2] findMessage(const(void)[] data, ref Message msg); 89 } 90 91 /// 92 static class SlaveMessageFinder : MessageFinder 93 { 94 override ptrdiff_t[2] findMessage(const(void)[] data, ref Message msg) 95 { 96 assert(backend !is null); 97 if (data.length >= MIN_MSG) 98 foreach (s; 0 .. data.length - MIN_MSG + 1) 99 if (testMessage(data[s..$], msg)) 100 return [s, data.length]; 101 return [-1, -1]; 102 } 103 } 104 105 /// 106 static class SnifferMessageFinder : MessageFinder 107 { 108 override ptrdiff_t[2] findMessage(const(void)[] data, ref Message msg) 109 { 110 if (data.length >= MIN_MSG) 111 foreach (s; 0 .. data.length - MIN_MSG + 1) 112 foreach_reverse (n; s + MIN_MSG .. data.length + 1) 113 if (testMessage(data[s..n], msg)) 114 return [s, n+1]; 115 return [-1, -1]; 116 } 117 } 118 119 /// 120 this(ModbusSlaveModel mdl, Backend be, Connection con, MessageFinder mf=null) 121 { 122 super(be, con); 123 this.model = mdl; 124 con.readTimeout = 10.msecs; 125 126 messageFinder = mf is null ? new SlaveMessageFinder : mf; 127 messageFinder.backend = be; 128 129 rw = new MBSRW; 130 cbuffer = CBuffer(MAX_BUFFER*2); 131 } 132 133 /// 134 void iterate() 135 { 136 auto rdd = con.read(buffer[], con.CanRead.zero); 137 auto df = cbuffer.capacity - cbuffer.length - rdd.length; 138 if (df < 0) cbuffer.popFrontN(-df); 139 cbuffer.put(rdd); 140 auto data = cbuffer.fill(findMsgBuf); 141 142 Message msg; 143 auto se = messageFinder.findMessage(data, msg); 144 if (se[0] == -1) return; 145 processMessage(msg); 146 cbuffer.popFrontN(se[1]); 147 } 148 }