rs232-vcc.cpp
Go to the documentation of this file.
1 //======================================================================
27 //======================================================================
28 
29 //----------------------------------------------------------------------
30 // System Includes - include with <>
31 //----------------------------------------------------------------------
32 
33 #include "iostream"
34 #include <windows.h>
35 
36 //----------------------------------------------------------------------
37 // Project Includes - include with ""
38 //----------------------------------------------------------------------
39 
40 #define _CRT_SECURE_NO_WARNINGS 1
41 
42 #include "rs232-vcc.h"
43 #include "simpletime.h"
44 #include "sdhlibrary_settings.h"
45 #include "util.h"
46 #include "dbg.h"
47 
48 //----------------------------------------------------------------------
49 // Defines, enums, unions, structs
50 //----------------------------------------------------------------------
51 
53 
63 #define SDH_RS232_VCC_DEBUG 1
64 
65 #if SDH_RS232_VCC_DEBUG
66 # define DBG( ... ) \
67  do { \
68  __VA_ARGS__; \
69  } while (0)
70 #else
71 # define DBG( ... )
72 #endif
73 
74 //----------------------------------------------------------------------
75 // Global variables (declarations)
76 //----------------------------------------------------------------------
77 
78 
79 //----------------------------------------------------------------------
80 // External functions and classes (declarations)
81 //----------------------------------------------------------------------
82 
83 
84 //----------------------------------------------------------------------
85 // Function definitions
86 //----------------------------------------------------------------------
87 
88 
89 //----------------------------------------------------------------------
90 // Class member definitions
91 //----------------------------------------------------------------------
92 
93 
94 cRS232::cRS232( int _port, unsigned long _baudrate, double _timeout, char const* _device_format_string )
95 : // init base class and members
96  cSerialBase(),
97 #ifndef RS_232_TEST
98  _hCOM(INVALID_HANDLE_VALUE),
99 #endif
100  port(_port),
101  baudrate(_baudrate),
102  read_timeout_us(-1)
103 {
104  SetTimeout( _timeout );
105 }
106 
108 {
109  if (_hCOM != INVALID_HANDLE_VALUE)
110  Close();
111 }
112 
113 #ifndef RS_232_TEST
114 
115 void cRS232::Open( void )
116 {
117  // see e.g. http://msdn.microsoft.com/de-de/magazine/cc301786(en-us).aspx
118  //
119  char device[] = "\\\\.\\COM00"; // initializer just to get just enough space
120  sprintf(device, "\\\\.\\COM%d", port+1);
121  DBG( dbg << "cRS232-vcc::Open: Opening RS232 device '" << device << "', baudrate: " << baudrate << "\n" );
122 
123  _hCOM = CreateFileA(device, // lpFileName
124  GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess
125  0, // dwShareMode
126  0, // lpSecurityAttributes
127  OPEN_EXISTING, // dwCreationDisposition
129  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // dwFlagsAndAttributes
130 #else
131  FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
132 #endif
133  0); // hTemplateFile
134  if ( _hCOM == INVALID_HANDLE_VALUE )
135  throw new cRS232Exception( cMsg( "Could not create handle to RS232 port %d = COM%d: %s", port, port+1, GetLastErrorMessage() ) );
136 
137 #if SDH_RS232_VCC_ASYNC
138  memset(&o, 0, sizeof(OVERLAPPED));
139 #endif
140  BOOL rc;
141  DCB dcbInitState;
142  dcbInitState.DCBlength = sizeof( DCB );
143 
144  rc = GetCommState(_hCOM, &dcbInitState);
145  if ( rc == 0 )
146  throw new cRS232Exception( cMsg( "Could not get comm state of RS232 port %d = COM%d: %s", port, port+1, GetLastErrorMessage() ) );
147  dcbInitState.DCBlength = sizeof( DCB );
148  dcbInitState.BaudRate = baudrate;
149  dcbInitState.fBinary = 1;
150  dcbInitState.fParity = 0;
151  dcbInitState.fOutxCtsFlow = 0;
152  dcbInitState.fOutxDsrFlow = 0;
153  dcbInitState.fDtrControl = DTR_CONTROL_DISABLE;
154  dcbInitState.fDsrSensitivity = 0;
155  dcbInitState.fTXContinueOnXoff = 1;
156  dcbInitState.fOutX = 0;
157  dcbInitState.fInX = 0;
158  dcbInitState.fErrorChar = 0;
159  dcbInitState.fNull = 0;
160  dcbInitState.fRtsControl = RTS_CONTROL_DISABLE;
161  dcbInitState.fAbortOnError = 0;
162  dcbInitState.ByteSize = 8;
163  dcbInitState.Parity = NOPARITY;
164  dcbInitState.StopBits = ONESTOPBIT;
165  rc = SetCommState(_hCOM, &dcbInitState);
166  if ( rc == 0 )
167  throw new cRS232Exception( cMsg( "Could not set comm state of RS232 port %d = COM%d: %s", port, port+1, GetLastErrorMessage() ) );
168  SleepSec(0.060);
169 
170  rc = GetCommTimeouts( _hCOM, &comm_timeouts );
171  if ( rc == 0 )
172  throw new cRS232Exception( cMsg( "Could not get timeouts of RS232 port %d = COM%d: %s", port, port+1, GetLastErrorMessage() ) );
173 
174  SetTimeout( timeout );
175 }
176 
177 void cRS232::Close()
178 {
179  CloseHandle(_hCOM);
180  _hCOM = INVALID_HANDLE_VALUE;
181 }
182 
183 void cRS232::SetTimeout( double _timeout )
184 {
185  DBG( dbg << "cRS232-vcc::SetTimeout( " << _timeout << ")\n" );
186  if ( _hCOM != INVALID_HANDLE_VALUE )
187  {
188  // we have a valid handle, so set the new timeout
189  // see http://msdn.microsoft.com/en-us/library/aa363194(VS.85).aspx
190 
191  if ( _timeout < 0.0 )
192  {
193  // negative timeout means wait for ever
194  comm_timeouts.ReadIntervalTimeout = 0;
195  comm_timeouts.ReadTotalTimeoutMultiplier = 0;
196  comm_timeouts.ReadTotalTimeoutConstant = 0;
197  }
198  else if ( _timeout == 0.0 )
199  {
200  // we want 0 timeout (return immediately with all there is (even 0))
201  comm_timeouts.ReadIntervalTimeout = MAXDWORD;
202  comm_timeouts.ReadTotalTimeoutMultiplier = 0;
203  comm_timeouts.ReadTotalTimeoutConstant = 0;
204  }
205  else
206  {
207  comm_timeouts.ReadIntervalTimeout = 0;
208  comm_timeouts.ReadTotalTimeoutMultiplier = 0;
209  comm_timeouts.ReadTotalTimeoutConstant = DWORD( _timeout * 1000.0 ); // new timeout in ms
210  }
211 
212  BOOL rc = SetCommTimeouts( _hCOM, &comm_timeouts );
213  if ( !rc )
214  throw new cRS232Exception( cMsg( "Could not set timeouts of RS232 port %d = COM%d: %s", port, port+1, GetLastErrorMessage() ) );
215  }
216  read_timeout_us = long( _timeout * 1000000.0 );
217  cSerialBase::SetTimeout( _timeout );
218 }
219 
220 ssize_t cRS232::Read( void *data, ssize_t size, long timeout_us, bool return_on_less_data )
221 {
222  char* buffer = (char*) data;
223  cSerialBase::cSetTimeoutTemporarily set_timeout_temporarily( this, double( timeout_us ) / 1000000.0 );
224  // previous timeout will be automatically restored when function is left (by return or exception)
225 
226  //memset(data, 0, size*sizeof(unsigned char));
227  DWORD offset=0;
228  DWORD bytes_read;
229  BOOL rc;
230  do
231  {
232 #if SDH_RS232_VCC_ASYNC
233  memset(&o, 0, sizeof(OVERLAPPED));
234  o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
235  rc = ReadFile(_hCOM, buffer + offset, size-offset, &bytes_read, &o); // FIXed: reading all requested bytes in one call gave an extra 5 fps (78 vs 72 fps) in demo-benchmark
236 #else
237  rc = ReadFile(_hCOM, buffer + offset, size-offset, &bytes_read, NULL ); //async , &o); // FIXed: FIXed: reading all requested bytes in one call gave an extra 5 fps (78 vs 72 fps) in demo-benchmark
238 #endif
239  if ( rc == 0 )
240  {
241 #if SDH_RS232_VCC_ASYNC
242  DWORD last_error = GetLastError();
243  if ( last_error == ERROR_IO_PENDING )
244  {
245  DWORD nRetVal;
246  if(return_on_less_data)
247  nRetVal = WaitForSingleObject(o.hEvent, 10);
248  else
249  nRetVal = WaitForSingleObject(o.hEvent, 5000);
250  switch(nRetVal)
251  {
252  case WAIT_OBJECT_0: // ReadFile event
253  break;
254  case WAIT_TIMEOUT:
255  DBG( dbg << "cRS232-vcc::Read: WAIT_TIMEOUT bytes_read = " << bytes_read << "\n" );
256  CloseHandle(o.hEvent);
257  throw new cRS232Exception( cMsg( "Timeout while reading data from RS232 port %d = COM%d", port, port+1 ) );
258  }
259  }
260  else
261  {
262  std::cerr << "error " << last_error << " from ReadFile / GetLastError: " << GetLastErrorMessage() << "\n";
263  }
264 #else
265  throw new cRS232Exception( cMsg( "ReadFile error Timeout while reading data from RS232 port %d = COM%d: %s", port, port+1, GetLastErrorMessage() ) );
266 #endif
267  }
268  DBG( dbg << "cRS232-vcc::Read: Read " << bytes_read << "/" << size << " bytes (hex): " << cHexByteString( buffer + offset, bytes_read ) << "\n" );
269  if ( bytes_read == 0 )
270  {
271  if ( timeout_us == 0 )
272  // no bytes read, but timeout is 0, so break
273  break;
274  // no bytes read but a timeout > 0 is set, so this an unwanted timeout occurred
275  DBG( dbg << "cRS232-vcc::Read timeout! bytes_read = 0\n" );
276 #if SDH_RS232_VCC_ASYNC
277  CloseHandle(o.hEvent);
278 #endif
279  throw new cRS232Exception( cMsg( "Timeout while reading data from RS232 port %d = COM%d", port, port+1 ) );
280  }
281 #if SDH_RS232_VCC_ASYNC
282  CloseHandle(o.hEvent);
283 #endif
284  offset += bytes_read;
285  //if(buffer[offset-1] != eol[0])
286  // SleepSec(0.001);
287  } while( offset < (DWORD) size );
288 
289  return (ssize_t) offset;
290 }
291 
292 char* cRS232::readline(char* line, int size, char* eol, bool return_on_less_data)
293 {
294  memset(line, 0, size*sizeof(char));
295  DWORD offset=0;
296  DWORD bytes_read;
297  BOOL rc;
298  do
299  {
300 #if SDH_RS232_VCC_ASYNC
301  memset(&o, 0, sizeof(OVERLAPPED));
302  o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
303  rc = ReadFile(_hCOM, &line[offset], 1, &bytes_read, &o);
304 #else
305  rc = ReadFile(_hCOM, &line[offset], 1, &bytes_read, NULL);
306 #endif
307  if ( rc == 0 )
308  {
309 #if SDH_RS232_VCC_ASYNC
310  DWORD last_error = GetLastError();
311  if ( last_error == ERROR_IO_PENDING )
312  {
313  DWORD nRetVal;
314  if(return_on_less_data)
315  nRetVal = WaitForSingleObject(o.hEvent, 10);
316  else
317  nRetVal = WaitForSingleObject(o.hEvent, 5000);
318  switch(nRetVal)
319  {
320  case WAIT_OBJECT_0: // ReadFile event
321  break;
322  case WAIT_TIMEOUT:
323  throw new cRS232Exception( cMsg( "Timeout while reading data from RS232 port %d = COM%d", port, port+1 ) );
324  }
325  }
326  else
327  {
328  std::cerr << "error " << last_error << " from ReadFile / GetLastError: " << GetLastErrorMessage() << "\n";
329  }
330 #else
331  throw new cRS232Exception( cMsg( "ReadFile error while reading data from RS232 port %d = COM%d: %s", port, port+1, GetLastErrorMessage() ) );
332 #endif
333  }
334  if ( bytes_read == 0 )
335  throw new cRS232Exception( cMsg( "ReadFile Timeout while reading data from RS232 port %d = COM%d", port, port+1 ) );
336 
337 #if SDH_RS232_VCC_ASYNC
338  CloseHandle(o.hEvent);
339 #endif
340  offset += bytes_read;
341  //if(line[offset-1] != eol[0])
342  // SleepSec(0.001);
343  } while(line[offset-1] != eol[0]);
344 
345  return line;
346 }
347 
348 int cRS232::write(char const *ptr, int len)
349 {
350  if(len == 0)
351  len = static_cast<int>(strlen(ptr));
352 
353  DWORD dwWritten;
354  BOOL rc;
355 #if SDH_RS232_VCC_ASYNC
356  //OVERLAPPED o = {0};
357  o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
358  rc = WriteFile(_hCOM, (LPCVOID)ptr, len, &dwWritten, &o);
359 #else
360  rc = WriteFile(_hCOM, (LPCVOID)ptr, len, &dwWritten, NULL );
361 #endif
362  if ( rc == 0 )
363  throw new cRS232Exception( cMsg( "Could not write %d bytes to RS232 port %d = COM%d: %s", len, port, port+1, GetLastErrorMessage() ) );
364 
365  DBG( dbg << "cRS232::write wrote " << len << "/" << dwWritten << " bytes (hex): " << cHexByteString( ptr, len ) << "\n" );
366 
368  //if(dwWritten != len)
369  // throw new cRS232Exception( cMsg( "Unable to write %d bytes to port %d = COM%d (only %d written)", len, port, port+1, dwWritten ) );
370 
371  //return dwWritten;
372  return len;
373 }
374 
375 #else
376 
377 void cRS232::Open(int port, unsigned long baudrate, double timeout)
378 {
379  _timeout = timeout;
380 }
381 
382 void cRS232::Close()
383 {
384 }
385 
386 char* cRS232::readline(char* line, int size, char* eol, bool return_on_less_data)
387 {
388  std::cout << "EOL size=" << strlen(eol) << std::endl;
389  if(return_on_less_data)
390  throw new cRS232Exception("return_on_less_data");
391 
392  return "cRS232::readline";
393 }
394 
395 int cRS232::write(char const *ptr, int len)
396 {
397  if(len == 0)
398  len = strlen( ptr );
399  std::cout << ">>> " << ptr << std::endl;
400  return len;
401 }
402 
403 #endif
HANDLE _hCOM
Definition: rs232-vcc.h:75
ssize_t Read(void *data, ssize_t size, long timeout_us, bool return_on_less_data)
long read_timeout_us
Definition: rs232-vcc.h:81
Interface of auxilliary utility functions for SDHLibrary-CPP.
~cRS232(void)
Definition: rs232-vcc.cpp:107
#define DBG(...)
Definition: rs232-vcc.cpp:66
#define NULL
Definition: getopt1.c:56
char * readline(char *line, int size, char *eol, bool return_on_less_data)
Definition: rs232-vcc.cpp:292
dummy class for (debug) stream output of bytes as list of hex values
Definition: dbg.h:329
void SleepSec(double t)
Definition: util.cpp:155
void Open(void)
virtual void SetTimeout(double _timeout)
set the timeout for next readline() calls (negative value means: no timeout, wait for ever) ...
Definition: serialbase.h:151
void Close(void)
Close the previously opened rs232 port.
This file contains interface and implementation of class #SDH::cDBG, a class for colorfull debug mess...
helper class to set timeout of _serial_base on construction and reset to previous value on destructio...
Definition: serialbase.h:163
Low-level communication class to access a serial port.
Definition: serialbase.h:105
virtual void SetTimeout(double _timeout)
set the timeout for next readline() calls (negative value means: no timeout, wait for ever) ...
Definition: rs232-vcc.cpp:183
char const * GetLastErrorMessage(void)
return the last error message as string. The string returned will be overwritten by the next call to ...
Definition: serialbase.h:260
int write(char const *ptr, int len=0)
Write data to a previously opened port.
Interface of auxilliary utility functions for SDHLibrary-CPP.
COMMTIMEOUTS comm_timeouts
Definition: rs232-vcc.h:80
cRS232(int _port, unsigned long _baudrate, double _timeout, char const *_device_format_string="/dev/ttyS%d")
#define SDH_RS232_VCC_ASYNC
Definition: rs232-vcc.h:56
#define USING_NAMESPACE_SDH
UInt16 size
Definition: dsa.h:269
int port
the RS232 portnumber to use
Definition: rs232-cygwin.h:89
double timeout
timeout in seconds
Definition: serialbase.h:116
This file contains settings to make the SDHLibrary compile on differen systems:
unsigned long baudrate
the baudrate in bit/s
Definition: rs232-cygwin.h:95
Derived exception class for low-level RS232 related exceptions.
Definition: rs232-cygwin.h:71
Class for short, fixed maximum length text messages.
Definition: sdhexception.h:77
Implementation of class #SDH::cRS232, a class to access serial RS232 port with VCC compiler on Window...
cDBG dbg
A stream object to print colored debug messages.
Definition: serialbase.h:227


sdhlibrary_cpp
Author(s): Dirk Osswald
autogenerated on Sun Aug 18 2019 03:42:20