1 /// modbus with back end
2 module modbus.facade;
3 
4 import modbus.backend;
5 import modbus.protocol;
6 
7 version(Have_serialport)
8 {
9     public import std.datetime : Duration, dur, hnsecs, nsecs, msecs, seconds;
10     public import serialport;
11 
12     /// Modbus with RTU backend constructs from existing serial port object
13     class ModbusRTU : Modbus
14     {
15     protected:
16         SerialPort _com;
17 
18         class C : Connection
19         {
20         override:
21             void write(const(void)[] msg)
22             { _com.write(msg, writeTimeout); }
23 
24             void[] read(void[] buffer)
25             { return _com.read(buffer, readTimeout, readFrameGap); }
26         }
27 
28     public:
29 
30         ///
31         Duration writeTimeout = 100.msecs,
32                  readTimeout = 1.seconds,
33                  readFrameGap = 4.msecs;
34 
35         ///
36         this(SerialPort sp, SpecRules sr=null)
37         {
38             import std.exception : enforce;
39             _com = enforce(sp, "serial port is null");
40             super(new RTU(new C, sr));
41         }
42 
43         @property
44         {
45             ///
46             SerialPort com() { return _com; }
47             ///
48             const(SerialPort) com() const { return _com; }
49         }
50 
51         ~this() { _com.destroy(); }
52     }
53 }
54 
55 import std.socket;
56 public import std.socket : Address, InternetAddress, Internet6Address;
57 version (Posix) public import std.socket : UnixAddress;
58 
59 /// Modbus with TCP backend based on TcpSocket from std.socket
60 class ModbusTCP : Modbus
61 {
62 protected:
63     TcpSocket _socket;
64 
65     void delegate() yieldFunc;
66     private void yield() { if (yieldFunc !is null) yieldFunc(); }
67 
68     class C : Connection
69     {
70     override:
71         void write(const(void)[] msg)
72         {
73             size_t sent;
74 
75             while (sent != msg.length)
76             {
77                 const res = _socket.send(msg[sent..$]);
78                 if (res == Socket.ERROR)
79                     throw modbusException("error while send data to tcp socket");
80 
81                 sent += res;
82                 yield();
83             }
84         }
85 
86         void[] read(void[] buffer)
87         {
88             size_t received;
89             ptrdiff_t res = -1;
90             while (res != 0)
91             {
92                 res = _socket.receive(buffer[received..$]);
93                 if (res == Socket.ERROR)
94                     throw modbusException("error while receive data from tcp socket");
95 
96                 received += res;
97                 yield();
98             }
99 
100             return buffer[0..received];
101         }
102     }
103 
104 public:
105 
106     ///
107     this(Address addr, void delegate() yieldFunc=null, SpecRules sr=null)
108     {
109         _socket = new TcpSocket(addr);
110 
111         if (yieldFunc !is null)
112         {
113             _socket.blocking(false);
114             this.yieldFunc = yieldFunc;
115         }
116 
117         super(new TCP(new C, sr));
118     }
119 
120     @property
121     {
122         ///
123         TcpSocket socket() { return _socket; }
124         ///
125         const(TcpSocket) socket() const { return _socket; }
126     }
127 
128     ~this() { _socket.close(); }
129 }