1 ///
2 module serialport.block;
3 
4 import serialport.base;
5 
6 ///
7 class SerialPortBlk : SerialPort
8 {
9 public:
10     /++ Construct SerialPortBlk
11 
12         See_Also: SerialPort.this
13      +/
14     this(string exmode) { super(exmode); }
15 
16     /// ditto
17     this(string port, string mode) { super(port, mode); }
18 
19     /// ditto
20     this(string port, uint baudRate) { super(port, baudRate); }
21 
22     /// ditto
23     this(string port, uint baudRate, string mode)
24     { super(port, baudRate, mode); }
25 
26     /// ditto
27     this(string port, Config conf) { super(port, conf); }
28 
29     @property
30     {
31         const
32         {
33             ///
34             Duration readTimeout() { return _readTimeout; }
35             ///
36             Duration readTimeoutMult() { return _readTimeoutMult; }
37             ///
38             Duration writeTimeout() { return _writeTimeout; }
39             ///
40             Duration writeTimeoutMult() { return _writeTimeoutMult; }
41         }
42 
43         ///
44         void readTimeout(Duration tm)
45         {
46             _readTimeout = tm;
47             version (Windows) updTimeouts();
48         }
49 
50         ///
51         void readTimeoutMult(Duration tm)
52         {
53             _readTimeoutMult = tm;
54             version (Windows) updTimeouts();
55         }
56 
57         ///
58         void writeTimeout(Duration tm)
59         {
60             _writeTimeout = tm;
61             version (Windows) updTimeouts();
62         }
63 
64         ///
65         void writeTimeoutMult(Duration tm)
66         {
67             _writeTimeout = tm;
68             version (Windows) updTimeouts();
69         }
70     }
71 
72     override void[] read(void[] buf)
73     {
74         if (closed) throw new PortClosedException(port);
75 
76         version (Posix)
77         {
78             fd_set sset;
79             FD_ZERO(&sset);
80             FD_SET(_handle, &sset);
81 
82             Duration ttm = buf.length * readTimeoutMult + readTimeout;
83 
84             timeval ctm;
85             ctm.tv_sec = cast(int)(ttm.total!"seconds");
86             enum US_PER_MS = 1000;
87             ctm.tv_usec = cast(int)(ttm.split().msecs * US_PER_MS);
88 
89             const rv = select(_handle + 1, &sset, null, null, &ctm);
90             if (rv == -1)
91                 throw new SysCallException("select", errno);
92             else if (rv == 0)
93                 throw new TimeoutException(port);
94 
95             const res = posixRead(handle, buf.ptr, buf.length);
96             if (res < 0)
97                 throw new ReadException(port, text("errno ", errno));
98         }
99         else
100         {
101             uint res;
102 
103             if (!ReadFile(handle, buf.ptr, cast(uint)buf.length, &res, null))
104                 throw new ReadException(port, text("error ", GetLastError()));
105 
106             if (res == 0)
107                 throw new TimeoutException(port);
108         }
109 
110         return buf[0..res];
111     }
112 
113     override ptrdiff_t write(const(void[]) arr)
114     {
115         if (closed) throw new PortClosedException(port);
116 
117         version (Posix)
118         {
119             size_t written;
120             const ttm = arr.length * writeTimeoutMult + writeTimeout;
121             const full = StopWatch(AutoStart.yes);
122             while (written < arr.length)
123             {
124                 if (full.peek > ttm)
125                     throw new TimeoutException(port);
126 
127                 const res = posixWrite(_handle, arr[written..$].ptr, arr.length - written);
128 
129                 if (res < 0)
130                     throw new WriteException(port, text("errno ", errno));
131 
132                 written += res;
133             }
134         }
135         else
136         {
137             uint written;
138 
139             if (!WriteFile(_handle, arr.ptr, cast(uint)arr.length, &written, null))
140                 throw new WriteException(port, text("error ", GetLastError()));
141 
142             if (arr.length != written)
143                 throw new TimeoutException(port);
144         }
145 
146         return written;
147     }
148 
149 protected:
150 
151     Duration _writeTimeout = 1.seconds,
152              _writeTimeoutMult = Duration.zero,
153              _readTimeout = 1.seconds,
154              _readTimeoutMult = Duration.zero
155              ;
156 
157     version (Windows)
158     {
159         override void updTimeouts()
160         {
161             setTimeouts(0, cast(DWORD)readTimeoutMult.total!"msecs",
162                            cast(DWORD)readTimeout.total!"msecs",
163                            cast(DWORD)writeTimeoutMult.total!"msecs",
164                            cast(DWORD)writeTimeout.total!"msecs");
165         }
166     }
167 
168     version (Posix)
169     {
170         override void posixSetup(Config conf)
171         {
172             openPort();
173 
174             if (fcntl(_handle, F_SETFL, 0) == -1)  // disable O_NONBLOCK
175                 throw new SysCallException("fcntl", errno);
176 
177             initialConfig(conf);
178         }
179     }
180 }