1 module modbus.protocol.slave.device.simple;
2 
3 import modbus.protocol.slave.device.base;
4 
5 class SimpleModbusSlaveDevice : ModbusSlaveDevice
6 {
7 protected:
8     ulong _number;
9     ushort[0x7D] vals;
10 
11 public:
12 
13     this(ulong numb) { _number = numb; }
14 
15     override
16     {
17         ulong number() @property { return _number; }
18 
19         Response onMessage(ResponseWriter rw, ref const Message msg)
20         {
21             alias FC = FunctionCode;
22 
23             auto st = cast(ushort[])msg.data[0..$/2*2];
24             auto addr = rw.backend.unpackTT(st[0]);
25             auto voc = rw.backend.unpackTT(st[1]);
26 
27             auto mltData()
28             {
29                 auto umd = cast(ushort[])msg.data[5..$];
30                 foreach (i, v; umd) vals[i] = rw.backend.unpackTT(v);
31                 return vals[0..umd.length];
32             }
33 
34             switch (msg.fnc)
35             {
36                 case FC.readCoils:
37                     return onReadCoils(rw, addr, voc);
38                 case FC.readDiscreteInputs:
39                     return onReadDiscreteInputs(rw, addr, voc);
40                 case FC.readHoldingRegisters:
41                     return onReadHoldingRegisters(rw, addr, voc);
42                 case FC.readInputRegisters:
43                     return onReadInputRegisters(rw, addr, voc);
44                 case FC.writeSingleCoil:
45                     return onWriteSingleCoil(rw, addr, voc);
46                 case FC.writeSingleRegister:
47                     return onWriteSingleRegister(rw, addr, voc);
48                 case FC.writeMultipleCoils:
49                     return onWriteMultipleCoils(rw, addr, mltData);
50                 case FC.writeMultipleRegisters:
51                     return onWriteMultipleRegisters(rw, addr, mltData);
52                 default:
53                     return onOtherFunction(rw, msg.fnc, msg.data);
54             }
55         }
56     }
57 
58     Response onReadCoils(ResponseWriter rw, ushort addr, ushort count)
59     { return Response.illegalFunction; }
60 
61     Response onReadDiscreteInputs(ResponseWriter rw, ushort addr, ushort count)
62     { return Response.illegalFunction; }
63 
64     Response onReadHoldingRegisters(ResponseWriter rw, ushort addr, ushort count)
65     { return Response.illegalFunction; }
66 
67     Response onReadInputRegisters(ResponseWriter rw, ushort addr, ushort count)
68     { return Response.illegalFunction; }
69 
70     Response onWriteSingleCoil(ResponseWriter rw, ushort addr, ushort value)
71     { return Response.illegalFunction; }
72 
73     Response onWriteSingleRegister(ResponseWriter rw, ushort addr, ushort value)
74     { return Response.illegalFunction; }
75 
76     Response onWriteMultipleCoils(ResponseWriter rw, ushort addr, const(ushort)[] values)
77     { return Response.illegalFunction; }
78 
79     Response onWriteMultipleRegisters(ResponseWriter rw, ushort addr, const(ushort)[] values)
80     { return Response.illegalFunction; }
81 
82     Response onOtherFunction(ResponseWriter rw, ubyte func, const(void)[] data)
83     { return Response.illegalFunction; }
84 }
85 
86 version (unittest):
87 
88 class TestModbusSlaveDevice : SimpleModbusSlaveDevice
89 {
90     static struct Data
91     {
92         align(1):
93         uint value1; // 0 - 1
94         uint value2; // 2 - 3
95         char[16] str; // 4 - 11
96         float value3; // 12 - 13
97         ushort[12] usv; // 14 - 26
98     }
99 
100     Data data;
101 
102     this(ulong number)
103     {
104         super(number);
105         rndData(data);
106     }
107 
108     void rndData(ref Data tdd)
109     {
110         import std.random : uniform;
111 
112         tdd.value1 = uniform(0, uint.max);
113         tdd.value2 = uniform(0, uint.max);
114         tdd.str[] = cast(char)0;
115         tdd.str[0..5] = "hello"[];
116         tdd.value3 = 3.1415;
117         foreach (ref v; tdd.usv)
118             v = uniform(ushort(0), ushort.max);
119     }
120 
121     ushort[] buf() @property
122     { return cast(ushort[])((cast(void*)&data)[0..data.sizeof]); }
123 
124 override:
125 
126     Response onReadInputRegisters(ResponseWriter rw, ushort addr, ushort count)
127     {
128         if (count > 0x7D || count == 0)
129             return Response.illegalDataValue;
130         if (addr >= buf.length || addr+count > buf.length)
131             return Response.illegalDataAddress;
132         return rw.packArray(buf[addr..addr+count]);
133     }
134 
135     Response onReadHoldingRegisters(ResponseWriter rw, ushort addr, ushort count)
136     { return onReadInputRegisters(rw, addr, count); }
137 
138     Response onWriteSingleRegister(ResponseWriter rw, ushort addr, ushort value)
139     {
140         if (addr > buf.length)
141             return Response.illegalDataAddress;
142         buf[addr] = value;
143         return rw.pack(addr, value);
144     }
145 
146     Response onWriteMultipleRegisters(ResponseWriter rw, ushort addr, const(ushort)[] values)
147     {
148         if (values.length > 0x7D || values.length == 0)
149             return Response.illegalDataValue;
150         if (addr >= buf.length || addr+values.length > buf.length)
151             return Response.illegalDataAddress;
152         buf[addr..addr+values.length] = values[];
153         return rw.pack(addr, cast(ushort)values.length);
154     }
155 }