1 ///
2 module modbus.protocol.base;
3 
4 public import std.bitmanip : BitArray;
5 public import std.exception : enforce;
6 public import std.datetime.stopwatch;
7 public import std.conv : to;
8 
9 version (modbus_verbose)
10     public import std.experimental.logger;
11 
12 public import modbus.exception;
13 public import modbus.connection;
14 public import modbus.backend;
15 public import modbus.types;
16 public import modbus.func;
17 
18 package enum MAX_BUFFER = 260;
19 
20 ///
21 class Modbus
22 {
23 protected:
24     void[MAX_BUFFER] buffer;
25 
26     Backend be;
27 
28     void delegate(Duration) sleepFunc;
29 
30     void sleep(Duration dur)
31     {
32         import core.thread;
33 
34         if (sleepFunc !is null) sleepFunc(dur);
35         else
36         {
37             if (auto fiber = Fiber.getThis)
38             {
39                 auto dt = StopWatch(AutoStart.yes);
40                 while (dt.peek.to!Duration < dur)
41                     fiber.yield();
42             }
43             else Thread.sleep(dur);
44         }
45     }
46 
47     ///
48     Duration writeStepPause() @property
49     { return (cast(ulong)(1e7 * 10 / 9600.0)).hnsecs; }
50 
51 public:
52 
53     ///
54     this(Backend be, void delegate(Duration) sf=null)
55     {
56         this.be = enforce(be, modbusException("backend is null"));
57         this.sleepFunc = sf;
58     }
59 
60     ///
61     Backend backend() @property { return be; }
62 
63     ///
64     Duration writeTimeout=10.msecs;
65     /// time for waiting message
66     Duration readTimeout=1.seconds;
67 
68     /++ Write to serial port
69 
70         Params:
71             dev = modbus device address (number)
72             fnc = function number
73             args = writed data in native endian
74         Returns:
75             sended message
76      +/
77     const(void)[] write(Args...)(ulong dev, ubyte fnc, Args args)
78     {
79         auto buf = be.buildMessage(buffer, dev, fnc, args);
80 
81         size_t cnt = be.connection.write(buf);
82         if (cnt == buf.length) return buf;
83 
84         auto dt = StopWatch(AutoStart.yes);
85         while (cnt != buf.length)
86         {
87             cnt += be.connection.write(buf[cnt..$]);
88             this.sleep(writeStepPause);
89             if (dt.peek.to!Duration > writeTimeout)
90                 throw modbusTimeoutException("write", dev, fnc, writeTimeout);
91         }
92 
93         return buf;
94     }
95 
96     ///
97     void setSleepFunc(void delegate(Duration) f) { sleepFunc = f; }
98 }