1 ///
2 module serialport.block;
3 
4 import serialport.base;
5 
6 /// Blocking work serialport
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     override void[] read(void[] buf, CanRead cr=CanRead.allOrNothing)
30     {
31         if (closed) throwPortClosedException(port);
32 
33         version (Posix)
34         {
35             if (cr == CanRead.allOrNothing)
36                 setCC([cast(ubyte)min(buf.length, 255), 0]);
37             else setCC([1, 0]);
38 
39             ssize_t res = 0;
40             auto ttm = buf.length * readTimeoutMult + readTimeout;
41             auto sw = StopWatch(AutoStart.yes);
42             while (ttm > Duration.zero)
43             {
44                 ttm -= sw.peek;
45                 sw.reset();
46 
47                 fd_set sset;
48                 FD_ZERO(&sset);
49                 FD_SET(_handle, &sset);
50 
51                 timeval ctm;
52                 ctm.tv_sec = cast(int)(ttm.total!"seconds");
53                 enum US_PER_MS = 1000;
54                 ctm.tv_usec = cast(int)(ttm.split().msecs * US_PER_MS);
55 
56                 const rv = select(_handle + 1, &sset, null, null, &ctm);
57                 if (rv < 0) throwSysCallException(port, "select", errno);
58 
59                 if (rv == 0) break;
60 
61                 const r = posixRead(_handle, buf.ptr+res, buf.length-res);
62                 if (r < 0) throwReadException(port, "posix read", errno);
63                 res += r;
64                 if (res == buf.length) return buf;
65             }
66         }
67         else
68         {
69             uint res;
70 
71             if (!ReadFile(handle, buf.ptr, cast(uint)buf.length, &res, null))
72                 throwReadException(port, "win read", GetLastError());
73         }
74 
75         checkAbility(cr, res, buf.length);
76 
77         return buf[0..res];
78     }
79 
80     override void write(const(void[]) arr)
81     {
82         if (closed) throwPortClosedException(port);
83 
84         version (Posix)
85         {
86             size_t written;
87             const ttm = arr.length * writeTimeoutMult + writeTimeout;
88             const full = StopWatch(AutoStart.yes);
89             while (written < arr.length)
90             {
91                 if (full.peek > ttm)
92                     throwTimeoutException(port, "write timeout");
93 
94                 const res = posixWrite(_handle, arr[written..$].ptr, arr.length - written);
95 
96                 if (res < 0)
97                     throwWriteException(port, "posix write", errno);
98 
99                 written += res;
100             }
101         }
102         else
103         {
104             uint written;
105 
106             if (!WriteFile(_handle, arr.ptr, cast(uint)arr.length, &written, null))
107                 throwWriteException(port, "win write", GetLastError());
108 
109             if (arr.length != written)
110                 throwTimeoutException(port, "write timeout");
111         }
112     }
113 
114 protected:
115 
116     override void[] m_read(void[]) @nogc
117     { assert(0, "disable m_read for blocking"); }
118     override size_t m_write(const(void)[]) @nogc
119     { assert(0, "disable m_write for blocking"); }
120 
121     override void updateTimeouts() @nogc { version (Windows) updTimeouts(); }
122 
123     version (Windows)
124     {
125         override void updTimeouts() @nogc
126         {
127             setTimeouts(0, cast(DWORD)readTimeoutMult.total!"msecs",
128                            cast(DWORD)readTimeout.total!"msecs",
129                            cast(DWORD)writeTimeoutMult.total!"msecs",
130                            cast(DWORD)writeTimeout.total!"msecs");
131         }
132     }
133 
134     version (Posix)
135     {
136         override void posixSetup(Config conf)
137         {
138             openPort();
139 
140             if (fcntl(_handle, F_SETFL, 0) == -1)  // disable O_NONBLOCK
141                 throwSysCallException(port, "fcntl", errno);
142 
143             setCC([1,0]);
144 
145             initialConfig(conf);
146         }
147     }
148 }