Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
wserial.cpp
Go to the documentation of this file.
1 // Copyright (C) 2008-2011 David Sugar, Tycho Softworks.
2 //
3 // This file is part of GNU Bayonne.
4 //
5 // GNU Bayonne is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // GNU Bayonne is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with GNU Bayonne. If not, see <http://www.gnu.org/licenses/>.
17 
18 #include <config.h>
19 #include <ucommon/ucommon.h>
20 #include <ucommon/export.h>
21 #include <bayonne.h>
22 
23 #ifdef _MSWINDOWS_
24 #include <io.h>
25 
26 #define ASCII_XON 0x11
27 #define ASCII_XOFF 0x13
28 
29 using namespace BAYONNE_NAMESPACE;
30 using namespace UCOMMON_NAMESPACE;
31 
32 class __LOCAL serial : public Serial
33 {
34 private:
35  HANDLE fd;
36  DCB original, current;
37 
38  void restore(void);
39  bool set(const char *format);
40  size_t get(void *addr, size_t len);
41  size_t put(void *addr, size_t len);
42  void dtr(timeout_t toggle_time);
43  void bin(size_t size, timeout_t timeout);
44  void text(char nl1, char nl2);
45  void clear(void);
46  bool flush(timeout_t timeout);
47  bool wait(timeout_t timeout);
48  void sync(void);
49 
50  operator bool();
51  bool operator!();
52 
53 public:
54  serial(const char *name);
55  ~serial();
56 };
57 
58 serial::serial(const char *name) : Serial()
59 {
60  fd = CreateFile(name,
61  GENERIC_READ | GENERIC_WRITE,
62  0, // exclusive access
63  NULL, // no security attrs
64  OPEN_EXISTING,
65  FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING,
66  NULL);
67 
68  if(fd == INVALID_HANDLE_VALUE) {
69  return;
70  }
71 
72  current.DCBlength = sizeof(DCB);
73  original.DCBlength = sizeof(DCB);
74 
75  GetCommState(fd, &original);
76  GetCommState(fd, &current);
77 
78  current.DCBlength = sizeof(DCB);
79  current.BaudRate = 1200;
80  current.Parity = NOPARITY;
81  current.ByteSize = 8;
82 
83  current.XonChar = ASCII_XON;
84  current.XoffChar = ASCII_XOFF;
85  current.XonLim = 100;
86  current.XoffLim = 100;
87  current.fOutxDsrFlow = 0;
88  current.fDtrControl = DTR_CONTROL_ENABLE;
89  current.fOutxCtsFlow = 1;
90  current.fRtsControl = RTS_CONTROL_ENABLE;
91  current.fInX = current.fOutX = 0;
92 
93  current.fBinary = true;
94  current.fParity = true;
95 
96  SetCommState(fd, &current);
97 }
98 
99 serial::~serial()
100 {
101  if(fd == INVALID_HANDLE_VALUE)
102  return;
103 
104  restore();
105  CloseHandle(fd);
106  fd = INVALID_HANDLE_VALUE;
107 }
108 
109 serial::operator bool()
110 {
111  if(fd == INVALID_HANDLE_VALUE)
112  return false;
113 
114  return true;
115 }
116 
117 bool serial::operator!()
118 {
119  if(fd == INVALID_HANDLE_VALUE)
120  return true;
121 
122  return false;
123 }
124 
125 void serial::restore(void)
126 {
127  if(fd == INVALID_HANDLE_VALUE)
128  return;
129 
130  memcpy(&current, &original, sizeof(current));
131  SetCommState(fd, &current);
132 }
133 
134 bool serial::set(const char *format)
135 {
136  assert(format != NULL);
137 
138  if(fd == INVALID_HANDLE_VALUE)
139  return false;
140 
141  unsigned long opt;
142  char buf[256];
143  String::set(buf, sizeof(buf), format);
144 
145  char *cp = strtok(buf, ",");
146  while(cp) {
147  switch(*cp) {
148  case 'n':
149  case 'N':
150  current.Parity = NOPARITY;
151  break;
152  case 'e':
153  case 'E':
154  current.Parity = EVENPARITY;
155  break;
156  case 'o':
157  case 'O':
158  current.Parity = ODDPARITY;
159  break;
160  case 's':
161  case 'S':
162  current.fInX = current.fOutX = TRUE;
163  current.fOutxCtsFlow = FALSE;
164  current.fRtsControl = FALSE;
165  break;
166  case 'H':
167  case 'h':
168  current.fInX = current.fOutX = FALSE;
169  current.fOutxCtsFlow = TRUE;
170  current.fRtsControl = RTS_CONTROL_HANDSHAKE;
171  break;
172  case 'b':
173  case 'B':
174  current.fInX = current.fOutX = TRUE;
175  current.fOutxCtsFlow = TRUE;
176  current.fRtsControl = RTS_CONTROL_HANDSHAKE;
177  break;
178  case '0':
179  case '1':
180  case '2':
181  case '3':
182  case '4':
183  case '5':
184  case '6':
185  case '7':
186  case '8':
187  case '9':
188  opt = atol(cp);
189  switch(opt) {
190  case 1:
191  current.StopBits = ONESTOPBIT;
192  break;
193  case 2:
194  current.StopBits = TWOSTOPBITS;
195  break;
196  case 5:
197  case 6:
198  case 7:
199  case 8:
200  current.ByteSize = (unsigned char)opt;
201  break;
202  default:
203  current.BaudRate = opt;
204  break;
205  }
206  break;
207  default:
208  error = EINVAL;
209  return false;
210  }
211  cp = strtok(NULL, ",");
212  }
213  current.DCBlength = sizeof(DCB);
214  SetCommState(fd, &current);
215  return true;
216 }
217 
218 size_t serial::get(void *data, size_t len)
219 {
220  DWORD dwLength = 0, dwError, dwReadLength;
221  COMSTAT cs;
222  OVERLAPPED ol;
223 
224  // Return zero if handle is invalid
225  if(fd == INVALID_HANDLE_VALUE)
226  return 0;
227 
228  // Read max length or only what is available
229  ClearCommError(fd, &dwError, &cs);
230 
231  // If not requiring an exact byte count, get whatever is available
232  if(len > (size_t)cs.cbInQue)
233  dwReadLength = cs.cbInQue;
234  else
235  dwReadLength = len;
236 
237  memset(&ol, 0, sizeof(OVERLAPPED));
238  ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
239 
240  if(dwReadLength > 0) {
241  if(ReadFile(fd, data, dwReadLength, &dwLength, &ol) == FALSE) {
242  if(GetLastError() == ERROR_IO_PENDING) {
243  WaitForSingleObject(ol.hEvent, INFINITE);
244  GetOverlappedResult(fd, &ol, &dwLength, TRUE);
245  }
246  else
247  ClearCommError(fd, &dwError, &cs);
248  }
249  }
250 
251  if(ol.hEvent != INVALID_HANDLE_VALUE)
252  CloseHandle(ol.hEvent);
253 
254  return dwLength;
255 }
256 
257 size_t serial::put(void *data, size_t len)
258 {
259  COMSTAT cs;
260  unsigned long dwError = 0;
261  OVERLAPPED ol;
262 
263  // Clear the com port of any error condition prior to read
264  ClearCommError(fd, &dwError, &cs);
265 
266  unsigned long retSize = 0;
267 
268  memset(&ol, 0, sizeof(OVERLAPPED));
269  ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
270 
271  if(WriteFile(fd, data, len, &retSize, &ol) == FALSE) {
272  if(GetLastError() == ERROR_IO_PENDING) {
273  WaitForSingleObject(ol.hEvent, INFINITE);
274  GetOverlappedResult(fd, &ol, &retSize, TRUE);
275  }
276  else
277  ClearCommError(fd, &dwError, &cs);
278  }
279 
280  if(ol.hEvent != INVALID_HANDLE_VALUE)
281  CloseHandle(ol.hEvent);
282 
283  return retSize;
284 }
285 
286 bool serial::wait(timeout_t timeout)
287 {
288  unsigned long dwError;
289  COMSTAT cs;
290 
291  if(fd == INVALID_HANDLE_VALUE)
292  return false;
293 
294  ClearCommError(fd, &dwError, &cs);
295 
296  if(timeout == 0)
297  return (0 != cs.cbInQue);
298 
299  OVERLAPPED ol;
300  DWORD dwMask;
301  DWORD dwEvents = 0;
302  BOOL suc;
303 
304  memset(&ol, 0, sizeof(OVERLAPPED));
305  ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
306  dwMask = EV_RXCHAR;
307  SetCommMask(fd, dwMask);
308  // let's wait for event or timeout
309  if((suc = WaitCommEvent(fd, &dwEvents, &ol)) == FALSE) {
310  if(GetLastError() == ERROR_IO_PENDING) {
311  DWORD transferred;
312 
313  dwError = WaitForSingleObject(ol.hEvent, timeout);
314  if (dwError != WAIT_OBJECT_0)
315  SetCommMask(fd, 0);
316 
317  suc = GetOverlappedResult(fd, &ol, &transferred, TRUE);
318  if (suc)
319  suc = (dwEvents & dwMask) ? TRUE : FALSE;
320  }
321  else
322  ClearCommError(fd, &dwError, &cs);
323  }
324 
325  if(ol.hEvent != INVALID_HANDLE_VALUE)
326  CloseHandle(ol.hEvent);
327 
328  if(suc == FALSE)
329  return false;
330  return true;
331 }
332 
333 bool serial::flush(timeout_t timeout)
334 {
335  unsigned long dwError;
336  COMSTAT cs;
337 
338  if(fd == INVALID_HANDLE_VALUE)
339  return false;
340 
341  ClearCommError(fd, &dwError, &cs);
342 
343  if(timeout == 0 && cs.cbOutQue > 0) {
344  PurgeComm(fd, PURGE_TXABORT | PURGE_TXCLEAR);
345  return true;
346  }
347 
348  if(cs.cbOutQue == 0)
349  return false;
350 
351  OVERLAPPED ol;
352  DWORD dwMask;
353  DWORD dwEvents = 0;
354  BOOL suc;
355 
356  memset(&ol, 0, sizeof(OVERLAPPED));
357  ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
358  dwMask = EV_TXEMPTY;
359  SetCommMask(fd, dwMask);
360  // let's wait for event or timeout
361  if((suc = WaitCommEvent(fd, &dwEvents, &ol)) == FALSE) {
362  if(GetLastError() == ERROR_IO_PENDING) {
363  DWORD transferred;
364 
365  dwError = WaitForSingleObject(ol.hEvent, timeout);
366  if (dwError != WAIT_OBJECT_0)
367  SetCommMask(fd, 0);
368 
369  suc = GetOverlappedResult(fd, &ol, &transferred, TRUE);
370  if (suc)
371  suc = (dwEvents & dwMask) ? TRUE : FALSE;
372  }
373  else
374  ClearCommError(fd, &dwError, &cs);
375  }
376 
377  if(ol.hEvent != INVALID_HANDLE_VALUE)
378  CloseHandle(ol.hEvent);
379 
380  if(suc == TRUE)
381  return false;
382 
383  PurgeComm(fd, PURGE_TXABORT | PURGE_TXCLEAR);
384  return true;
385 }
386 
387 void serial::clear(void)
388 {
389  PurgeComm(fd, PURGE_RXABORT | PURGE_RXCLEAR);
390 }
391 
392 void serial::sync(void)
393 {
394 }
395 
396 void serial::bin(size_t size, timeout_t timeout)
397 {
398 }
399 
400 void serial::text(char nl1, char nl2)
401 {
402 }
403 
404 void serial::dtr(timeout_t timeout)
405 {
406  EscapeCommFunction(fd, CLRDTR);
407  if(timeout) {
408  Thread::sleep(timeout);
409  EscapeCommFunction(fd, SETDTR);
410  }
411 }
412 
413 Serial *Serial::create(const char *name)
414 {
415  char buf[65];
416 
417  String::set(buf, sizeof(buf), name);
418 
419  char *cp = strchr(buf, ':');
420  if(cp)
421  *cp = 0;
422 
423  serial_t dev = new serial(buf);
424  name = strchr(name, ':');
425  if(dev && name)
426  dev->set(++name);
427 
428  return dev;
429 }
430 
431 stringpager *Serial::list(void)
432 {
433  DWORD index = 0;
434  TCHAR keyname[4096];
435  DWORD size = sizeof(keyname);
436  stringpager *list = new stringpager;
437  HKEY reg;
438  FILETIME fTime;
439 
440  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &reg) == ERROR_SUCCESS) {
441  while(RegEnumKeyEx(reg, index++, keyname, &size, NULL, NULL, NULL, &fTime) == ERROR_SUCCESS) {
442  list->add(keyname);
443  }
444  RegCloseKey(reg);
445  }
446  return list;
447 }
448 
449 #endif
450 
#define BAYONNE_NAMESPACE
Definition: bayonne.h:25
GNU Bayonne library namespace.