Garmin Fleet Management Controller  2.19.0
SerialPort.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 *
3 * MODULE NAME:
4 * SerialPort.cpp
5 *
6 * Copyright 2008-2016 by Garmin Ltd. or its subsidiaries.
7 *---------------------------------------------------------------------
8 * $NoKeywords$
9 *********************************************************************/
10 
11 #include "stdafx.h"
12 #include "SerialPort.h"
13 #include "LinkLayer.h"
14 #include "Logger.h"
15 #include "GarminLinkLayer.h"
16 
18 #define RX_QUEUE_SIZE ( 0x4000 )
19 
21 #define TX_QUEUE_SIZE ( 0x1000 )
22 
24 #define DEFAULT_BAUD_RATE ( 9600 )
25 
27 
28 //----------------------------------------------------------------------
35 //----------------------------------------------------------------------
37 {
38  if( sInstance == NULL )
39  {
40  sInstance = new SerialPort();
42  }
43 
44  return sInstance;
45 }
46 
47 //----------------------------------------------------------------------
49 //----------------------------------------------------------------------
51 {
52  delete sInstance;
53  sInstance = NULL;
54 }
55 
56 //----------------------------------------------------------------------
59 //----------------------------------------------------------------------
60 void SerialPort::getPortList( std::list<CString> &aList )
61 {
62  aList.clear();
63 
64  // Registry method is faster and gets all ports, when it works...
66  {
67  // but if it doesn't, fall back to testing which ports can be opened
68  aList.clear();
70  }
71 
72  // Add the TCP socket option
73  CString tcpSocket( TCP_PORT_NAME );
74  aList.push_back( tcpSocket );
75 }
76 
77 //----------------------------------------------------------------------
81 //----------------------------------------------------------------------
83 {
84  mComPortHandle = INVALID_HANDLE_VALUE;
85  mLinkLayer = NULL;
86 }
87 
88 //----------------------------------------------------------------------
94 //----------------------------------------------------------------------
96  (
97  const CString& port
98  )
99 {
100  // Only clear the log if it isn't already open.
101  // Reinitializing the com port shouldn't clear the log.
102  if( !Logger::isLogOpen() )
104 
105  if( sInstance )
106  {
107  sInstance->close();
108  }
109 
110  sInstance = new SerialPort();
112 
113  return sInstance->init( port );
114 }
115 
116 //----------------------------------------------------------------------
122 //----------------------------------------------------------------------
123 bool SerialPort::init
124  (
125  const CString& port
126  )
127 {
128  COMMTIMEOUTS timeouts;
129  CString portDeviceFile;
130 
131  portDeviceFile.Format( _T("\\\\.\\%s"), port );
132  mComPortHandle = CreateFile
133  (
134  portDeviceFile.GetString(),
135  GENERIC_READ | GENERIC_WRITE,
136  0, /* exclusive access */
137  NULL, /* no security attributes */
138  OPEN_EXISTING,
139  FILE_ATTRIBUTE_NORMAL,
140  NULL
141  );
142 
143  if( mComPortHandle == INVALID_HANDLE_VALUE )
144  {
145  recordErrorText( _T("opening port") );
146  return false;
147  }
148 
150  {
151  return false;
152  }
153 
154  if( !SetupComm( mComPortHandle, RX_QUEUE_SIZE, TX_QUEUE_SIZE ) )
155  {
156  recordErrorText( _T("setting up buffers") );
157  close();
158  return false;
159  }
160 
161  timeouts.ReadIntervalTimeout = 0;
162  timeouts.ReadTotalTimeoutMultiplier = 0;
163  timeouts.ReadTotalTimeoutConstant = 0;
164  timeouts.WriteTotalTimeoutMultiplier = 0;
165  timeouts.WriteTotalTimeoutConstant = 0;
166 
167  if( !SetCommTimeouts( mComPortHandle, &timeouts ) )
168  {
169  recordErrorText( _T("setting timeouts") );
170  close();
171  return false;
172  }
173 
174  if( !PurgeComm( mComPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR ) )
175  {
176  recordErrorText( _T("clearing buffers") );
177  close();
178  return false;
179  }
180 
181  mPortName = port;
182 
183  return true;
184 }
185 
186 //----------------------------------------------------------------------
190 //----------------------------------------------------------------------
192 {
193  if( isOpen() )
194  {
195  CloseHandle( mComPortHandle );
196  mComPortHandle = INVALID_HANDLE_VALUE;
197  mPortName = "";
198  }
199 }
200 
201 //----------------------------------------------------------------------
203 //----------------------------------------------------------------------
205 {
206  /*----------------------------------------------------------
207  Local Variables
208  ----------------------------------------------------------*/
209  uint8 readBuffer[ 256 ];
210  int readSize;
211  DWORD error;
212  COMSTAT status;
213 
214  //check for error
215  ClearCommError( mComPortHandle, &error, &status );
216  if( error != 0 )
217  {
218  PurgeComm( mComPortHandle, PURGE_RXABORT | PURGE_RXCLEAR );
219  return;
220  }
221 
222  DWORD remainder = status.cbInQue;
223  while( remainder > 0 )
224  {
225  //check read size...if zero return because nothing to do
226  readSize = minval( remainder, sizeof( readBuffer ) );
227 
228  if( ReadFile( mComPortHandle, readBuffer, readSize, (LPDWORD)&readSize, NULL ) == 0 )
229  {
230  ClearCommError( mComPortHandle, &error, &status );
231  if( ( error & CE_OVERRUN ) ||
232  ( error & CE_RXOVER ) )
233  {
234  PurgeComm( mComPortHandle, PURGE_RXABORT | PURGE_RXCLEAR );
235  }
236  return;
237  }
238  if( readSize == 0 )
239  return;
240 
241  // Push the received bytes up to the link layer
242  if( mLinkLayer )
243  {
244  mLinkLayer->rx( readBuffer, readSize );
245  }
246 
247  remainder -= readSize;
248  }
249 }
250 
251 //----------------------------------------------------------------------
256 //----------------------------------------------------------------------
257 bool SerialPort::tx
258  (
259  uint8 * aData,
260  uint16 aSize
261  )
262 {
263  DWORD error;
264  DWORD writeCount;
265  COMSTAT status;
266 
267  ASSERT( mComPortHandle != INVALID_HANDLE_VALUE );
268  ASSERT( aData != NULL );
269  ASSERT( aSize != 0 );
270 
271  if( WriteFile( mComPortHandle, aData, aSize, (LPDWORD)&writeCount, NULL ) == 0 )
272  {
273  ClearCommError( mComPortHandle, &error, &status );
274  if( error & CE_TXFULL )
275  {
276  PurgeComm( mComPortHandle, PURGE_TXABORT | PURGE_TXCLEAR );
277  }
278  return false;
279  }
280  return true;
281 }
282 
283 //----------------------------------------------------------------------
291 //----------------------------------------------------------------------
293  (
294  std::list<CString> &aList
295  )
296 {
297  HKEY hKey; // handle for the key being queried
298  DWORD numValues; // number of values for key
299  DWORD maxValueLen; // longest value name
300  DWORD maxDataLen; // longest value data
301  DWORD dataType; // out: code indicating type of data
302  BYTE *dataBuf; // out: data buffer
303  DWORD dataLen; // out: number of bytes
304  DWORD i, retCode;
305 
306  TCHAR *valueBuf;
307  DWORD valueLen;
308 
309  bool retval = false;
310 
311  if( RegOpenKeyEx
312  (
313  HKEY_LOCAL_MACHINE,
314  TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
315  0,
316  KEY_READ,
317  &hKey
318  ) == ERROR_SUCCESS )
319  {
320  // Get the class name and the value count.
321  retCode = RegQueryInfoKey
322  (
323  hKey, // key handle
324  NULL, NULL, // buffer and size of class name, don't care
325  NULL, // reserved
326  NULL, NULL, // number and length of subkeys, don't care
327  NULL, // longest class string, don't care
328  &numValues, // number of values for this key
329  &maxValueLen, // longest value name
330  &maxDataLen, // longest value data
331  NULL, NULL // security descriptor, last write time, don't care
332  );
333 
334  // Enumerate the values and data under this key.
335  if( numValues )
336  {
337  valueBuf = new TCHAR[maxValueLen + 1];
338  dataBuf = new BYTE[maxDataLen + 1];
339  retval = true;
340 
341  for( i = 0, retCode = ERROR_SUCCESS; i < numValues; i++ )
342  {
343  valueLen = maxValueLen + 1;
344  dataLen = maxDataLen + 1;
345  valueBuf[0] = '\0';
346  retCode = RegEnumValue
347  (
348  hKey,
349  i,
350  valueBuf,
351  &valueLen,
352  NULL,
353  &dataType,
354  dataBuf,
355  &dataLen
356  );
357  if( retCode == ERROR_SUCCESS )
358  {
359  if( dataType == REG_SZ )
360  aList.push_back( CString( (TCHAR*)dataBuf ) );
361  }
362  else
363  retval = false;
364 
365  } // end of for loop
366 
367  delete[] valueBuf;
368  delete[] dataBuf;
369  } // end of if( numValues )
370 
371  } // end of if( RegOpenKey )
372 
373  RegCloseKey( hKey );
374  return retval;
375 }
376 
377 //----------------------------------------------------------------------
380 //----------------------------------------------------------------------
382  (
383  std::list<CString> &aList
384  )
385 {
386  getInstance()->close();
387 
388  for( int portNum = 1; portNum <= 256; portNum++ )
389  {
390  CString portDeviceFile; // Device filename
391  CString portName; // Display/"friendly" name
392  HANDLE hPort;
393  portName.Format( _T("COM%u"), portNum );
394  portDeviceFile.Format( _T("\\\\.\\%s"), portName );
395 
396  hPort = CreateFile
397  (
398  portDeviceFile,
399  GENERIC_READ | GENERIC_WRITE,
400  0,
401  NULL,
402  OPEN_EXISTING,
403  0,
404  NULL
405  );
406  if( hPort != INVALID_HANDLE_VALUE )
407  {
408  aList.push_back( portName );
409  ::CloseHandle( hPort );
410  }
411 #if defined( _DEBUG )
412  else
413  {
414  TRACE( "Failed to open port %s, error was %d\n", portName.GetBuffer(), GetLastError() );
415  }
416 #endif
417  }
418 }
419 
420 //----------------------------------------------------------------------
422 //----------------------------------------------------------------------
423 const CString& SerialPort::getLastError() const
424 {
425  return mLastErrorText;
426 }
427 
428 //----------------------------------------------------------------------
432 //----------------------------------------------------------------------
434 {
435  if( isOpen() )
436  pumpRx();
437 }
438 
439 //----------------------------------------------------------------------
441 //----------------------------------------------------------------------
443 {
444  if( mLinkLayer )
445  {
446  mLinkLayer->setPhysicalLayer( NULL );
447  }
448  close();
449 }
450 
451 //----------------------------------------------------------------------
454 //----------------------------------------------------------------------
456  (
457  const CString& aOperation
458  )
459 {
460  LPTSTR pszMessage;
461  DWORD errorCode = GetLastError();
462 
463  ASSERT( errorCode != ERROR_SUCCESS );
464 
465  FormatMessage
466  (
467  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
468  NULL,
469  errorCode,
470  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
471  (LPTSTR)&pszMessage,
472  0,
473  NULL
474  );
475  mLastErrorText.Format( _T("%s: %s"), aOperation, CString( pszMessage ) );
476  LocalFree( pszMessage );
477 }
478 
479 //----------------------------------------------------------------------
483 //----------------------------------------------------------------------
484 const CString& SerialPort::getPortName() const
485 {
486  return mPortName;
487 }
488 
489 //----------------------------------------------------------------------
492 //----------------------------------------------------------------------
493 bool SerialPort::isOpen() const
494 {
495  return mComPortHandle != INVALID_HANDLE_VALUE;
496 }
497 
498 //----------------------------------------------------------------------
502 //----------------------------------------------------------------------
504  (
505  uint32 aBaudRate
506  )
507 {
508  DCB dcb;
509 
510  ASSERT( mComPortHandle != INVALID_HANDLE_VALUE );
511 
512  dcb.DCBlength = sizeof( DCB );
513  if( !GetCommState( mComPortHandle, &dcb ) )
514  {
515  recordErrorText( _T("getting port state") );
516  close();
517  return false;
518  }
519 
520  dcb.fBinary = TRUE;
521  dcb.BaudRate = aBaudRate;
522  dcb.ByteSize = 8;
523  dcb.StopBits = ONESTOPBIT;
524  dcb.Parity = NOPARITY;
525  dcb.fParity = FALSE;
526  dcb.fAbortOnError = FALSE;
527  dcb.fOutxCtsFlow = FALSE;
528  dcb.fOutxDsrFlow = FALSE;
529  dcb.fDtrControl = DTR_CONTROL_DISABLE;
530  dcb.fRtsControl = RTS_CONTROL_DISABLE;
531  dcb.fDsrSensitivity = FALSE;
532  dcb.fTXContinueOnXoff = FALSE;
533  dcb.fOutX = FALSE;
534  dcb.fInX = FALSE;
535  dcb.fNull = FALSE;
536 
537  if( !SetCommState( mComPortHandle, &dcb ) )
538  {
539  recordErrorText( _T("setting serial port parameters") );
540  close();
541  return false;
542  }
543 
544  mBaudRate = aBaudRate;
545 
546  return true;
547 }
548 //----------------------------------------------------------------------
551 //----------------------------------------------------------------------
553  {
554  return mBaudRate;
555  }
virtual bool setBaudRate(uint32 aBaudRate)
Set the baud rate.
Definition: SerialPort.cpp:504
void recordErrorText(const CString &aOperation)
Store a textual description of the last error that occurred.
Definition: SerialPort.cpp:456
CString mPortName
Display name of the serial port being used for communication.
Definition: SerialPort.h:108
virtual void close()
Close the COM port if one is in use.
Definition: SerialPort.cpp:191
static void clearLog()
Empties the packet log.
Definition: Logger.cpp:83
#define TCP_PORT_NAME
Definition: SerialPort.h:23
static bool initSerialPort(const CString &aPortName)
Initializes the port passed in.
Definition: SerialPort.cpp:96
static void getPortListEnum(std::list< CString > &aList)
Find the COM ports on the system by opening each in turn.
Definition: SerialPort.cpp:382
virtual uint32 getBaudRate() const
Return the last successfully applied baud rate .
Definition: SerialPort.cpp:552
static SerialPort * sInstance
The one and only instance of this object.
Definition: SerialPort.h:95
static GarminLinkLayer * getInstance()
Get the one and only link layer object.
#define FALSE
Definition: garmin_types.h:46
HANDLE mComPortHandle
File handle for the com port that is open, or INVALID_HANDLE_VALUE if the port is not open...
Definition: SerialPort.h:102
static bool getPortListFromRegistry(std::list< CString > &aList)
Get the list of com ports on the system by enumerating the device map in the Windows registry...
Definition: SerialPort.cpp:293
virtual const CString & getPortName() const
Get the name of the serial port that is open.
Definition: SerialPort.cpp:484
SerialPort()
Construct the SerialPort.
Definition: SerialPort.cpp:82
bool init(const CString &aPortName)
Initializes the port passed in.
Definition: SerialPort.cpp:124
virtual bool tx(uint8 *aData, uint16 aSize)
Transmit bytes on the serial port.
Definition: SerialPort.cpp:258
#define TRUE
Definition: garmin_types.h:45
#define RX_QUEUE_SIZE
The size of Windows&#39; RX queue for the com port, in bytes.
Definition: SerialPort.cpp:18
virtual ~SerialPort()
Destructor. Close the serial port.
Definition: SerialPort.cpp:442
void resetPhysicalLayer(PhysicalLayer *aPort)
Reset the physical layer.
#define minval(_x, _y)
The smaller of _x and _y.
Definition: util_macros.h:95
const CString & getLastError() const
Return a description of the last error that occurred.
Definition: SerialPort.cpp:423
LinkLayer * mLinkLayer
The link layer that is one level up from this serial port.
Definition: PhysicalLayer.h:47
static SerialPort * getInstance()
Get the one and only serial port object.
Definition: SerialPort.cpp:36
#define DEFAULT_BAUD_RATE
The default baud rate for the serial port.
Definition: SerialPort.cpp:24
static void getPortList(std::list< CString > &aList)
Get the list of serial ports.
Definition: SerialPort.cpp:60
unsigned short int uint16
16-bit unsigned integer
Definition: garmin_types.h:64
virtual void rx(uint8 const *const aData, uint32 const aSize)=0
Receive data from the physical layer.
unsigned char uint8
8-bit unsigned integer
Definition: garmin_types.h:62
void setPhysicalLayer(PhysicalLayer *aPort)
Set the physical layer.
Definition: LinkLayer.cpp:41
CString mLastErrorText
String containing the last communication error.
Definition: SerialPort.h:113
virtual bool isOpen() const
Indicate whether the port is open.
Definition: SerialPort.cpp:493
static bool isLogOpen()
Returns true if the log file is open.
Definition: Logger.cpp:111
unsigned long int uint32
32-bit unsigned integer
Definition: garmin_types.h:66
virtual void pumpRx()
Receive and process any data.
Definition: SerialPort.cpp:204
void onTimer()
Timer callback.
Definition: SerialPort.cpp:433
Physical layer implementation for a serial port.
Definition: SerialPort.h:30
#define TX_QUEUE_SIZE
The size of Windows&#39; TX queue for the com port, in bytes.
Definition: SerialPort.cpp:21
uint32 mBaudRate
The last successfully applied baud rate.
Definition: SerialPort.h:116
static void destroyInstance()
Destroy the one and only serial port object.
Definition: SerialPort.cpp:50