source: SVN/cambria/redboot/host/tools/Utils/common/eCosSerial.cpp @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 16.0 KB
Line 
1//####COPYRIGHTBEGIN####
2//                                                                         
3// ----------------------------------------------------------------------------
4// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5//
6// This program is part of the eCos host tools.
7//
8// This program is free software; you can redistribute it and/or modify it
9// under the terms of the GNU General Public License as published by the Free
10// Software Foundation; either version 2 of the License, or (at your option)
11// any later version.
12//
13// This program is distributed in the hope that it will be useful, but WITHOUT
14// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16// more details.
17//
18// You should have received a copy of the GNU General Public License along with
19// this program; if not, write to the Free Software Foundation, Inc.,
20// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21//
22// ----------------------------------------------------------------------------
23//                                                                         
24//####COPYRIGHTEND####
25//=================================================================
26//
27//        eCosSerial.cpp
28//
29//        Serial test class
30//
31//=================================================================
32//=================================================================
33//#####DESCRIPTIONBEGIN####
34//
35// Author(s):     sdf
36// Contributors:  sdf
37// Date:          1999-04-01
38// Description:   This class abstracts the serial port for use in the testing infrastructure
39// Usage:
40//
41//####DESCRIPTIONEND####
42
43#include "eCosStd.h"
44#include "eCosSerial.h"
45#include "eCosThreadUtils.h"
46#include "eCosTrace.h"
47
48CeCosSerial::CeCosSerial():
49  m_nErr(0),
50  m_pHandle(0),
51  m_nDataBits(8),
52  m_nStopBits(ONE_STOP_BIT),
53  m_bXONXOFFFlowControl(0),
54  m_bRTSCTSFlowControl(0),
55  m_bDSRDTRFlowControl(0),
56  m_bParity(false),
57  m_nBaud(0),
58  m_nTotalReadTimeout(10*1000),
59  m_nTotalWriteTimeout(10*1000),
60  m_nInterCharReadTimeout(500),
61  m_nInterCharWriteTimeout(500),
62  m_bBlockingReads(true)
63{
64}
65
66CeCosSerial::~CeCosSerial()
67{
68  Close();
69}
70
71CeCosSerial::CeCosSerial(LPCTSTR pszPort,int nBaud):
72  m_nErr(0),
73  m_pHandle(0),
74  m_nDataBits(8),
75  m_nStopBits(ONE_STOP_BIT),
76  m_bXONXOFFFlowControl(0),
77  m_bRTSCTSFlowControl(0),
78  m_bDSRDTRFlowControl(0),
79  m_bParity(false),
80  m_nTotalReadTimeout(10*1000),
81  m_nTotalWriteTimeout(10*1000),
82  m_nInterCharReadTimeout(500),
83  m_nInterCharWriteTimeout(500),
84  m_bBlockingReads(true)
85{
86  Open(pszPort,nBaud);
87}
88
89bool CeCosSerial::SetBlockingReads(bool b,bool bApplySettingsNow/*=true*/)
90{
91  m_bBlockingReads=b;
92  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
93}
94
95bool CeCosSerial:: SetBaud(unsigned int nBaud,bool bApplySettingsNow/*=true*/)
96{
97  m_nBaud=nBaud;
98  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
99}
100
101bool CeCosSerial:: SetParity(bool bParityOn,bool bApplySettingsNow/*=true*/)
102{
103  m_bParity=bParityOn;
104  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
105}
106
107bool CeCosSerial:: SetDataBits(int n,bool bApplySettingsNow/*=true*/)
108{
109  m_nDataBits=n;
110  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
111}
112
113bool CeCosSerial:: SetStopBits(StopBitsType n,bool bApplySettingsNow/*=true*/)
114{
115  m_nStopBits=n;
116  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
117}
118
119bool CeCosSerial:: SetXONXOFFFlowControl(bool b,bool bApplySettingsNow/*=true*/)
120{
121  m_bXONXOFFFlowControl=b;
122  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
123}
124
125bool CeCosSerial:: SetRTSCTSFlowControl(bool b,bool bApplySettingsNow/*=true*/)
126{
127  m_bRTSCTSFlowControl=b;
128  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
129}
130
131bool CeCosSerial:: SetDSRDTRFlowControl(bool b,bool bApplySettingsNow/*=true*/)
132{
133  m_bDSRDTRFlowControl=b;
134  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
135}
136
137bool CeCosSerial:: SetReadTimeOuts(int nTotal,int nBetweenChars,bool bApplySettingsNow/*=true*/) // mSec
138{
139  m_nTotalReadTimeout=nTotal;
140  m_nInterCharReadTimeout=nBetweenChars;
141 
142  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
143}
144
145bool CeCosSerial:: SetWriteTimeOuts(int nTotal,int nBetweenChars,bool bApplySettingsNow/*=true*/) // mSec
146{
147  m_nTotalWriteTimeout=nTotal;
148  m_nInterCharWriteTimeout=nBetweenChars;
149  return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
150}
151
152#ifdef _WIN32
153bool CeCosSerial::Open(LPCTSTR pszPort,int nBaud)
154{
155  bool rc=false;
156  m_nBaud=nBaud,
157    m_strPort=pszPort;
158  HANDLE hCom=::CreateFile(pszPort,GENERIC_READ|GENERIC_WRITE, 0,NULL,OPEN_EXISTING,0,NULL);
159  SaveError();
160  if (INVALID_HANDLE_VALUE==hCom) { 
161    ERROR(_T("Failed to open port %s - %s\n"),pszPort,(LPCTSTR)ErrString());
162  } else {
163    m_pHandle=(void *)hCom;
164    if(ApplySettings()){
165      Flush();
166      rc=true;
167    } else {
168      Close();
169    }
170  }
171  return rc;
172}
173
174bool CeCosSerial::Close()
175{
176  bool rc=false;
177  if(m_pHandle){
178    try {
179      rc=(TRUE==CloseHandle((HANDLE)m_pHandle));
180    }
181    catch(...) {
182      TRACE(_T("!!! Exception caught closing serial handle %08x\n"),m_pHandle);
183    }
184    m_pHandle=0;
185  } else {
186    rc=true;
187  }
188  return rc;
189}
190
191bool CeCosSerial::ApplySettings()
192{
193  bool rc=false;
194  try {
195    DCB dcb;
196   
197    ZeroMemory(&dcb,sizeof dcb);
198    dcb.DCBlength=sizeof dcb;
199    dcb.BaudRate=m_nBaud;
200    dcb.fBinary=true;
201    dcb.fParity=true;
202    dcb.Parity=(BYTE) ((m_bParity) ? EVENPARITY : NOPARITY);
203    dcb.StopBits=(BYTE)m_nStopBits;
204    dcb.ByteSize=(BYTE)m_nDataBits;
205    LPCTSTR arpszStopbits[3]={_T("1"),_T("1.5"),_T("2")};
206    TRACE(_T("Applysettings baud=%d Parity=%d stopbits=%s databits=%d\n"),
207      dcb.BaudRate, 
208      dcb.Parity, 
209      arpszStopbits[dcb.StopBits],
210      dcb.ByteSize);
211   
212    if (m_bDSRDTRFlowControl) {
213        dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
214        dcb.fOutxDsrFlow = 1;
215    } else {
216        dcb.fDtrControl = DTR_CONTROL_ENABLE;
217        dcb.fOutxDsrFlow = 0;
218    }
219   
220    if (m_bRTSCTSFlowControl) {
221        dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
222        dcb.fOutxCtsFlow = 1;
223    } else {
224        dcb.fRtsControl = RTS_CONTROL_ENABLE;
225        dcb.fOutxCtsFlow = 0;
226    }
227
228    dcb.fTXContinueOnXoff=1;
229    dcb.XonChar=17;
230    dcb.XoffChar=19;
231    if (m_bXONXOFFFlowControl) {
232        dcb.XonLim=512;
233        dcb.XoffLim=512;
234        dcb.fOutX=1;
235        dcb.fInX=1;
236    } else {
237        dcb.XonLim=2048;
238        dcb.XoffLim=512;
239        dcb.fOutX=0;
240        dcb.fInX=0;
241    }
242    dcb.fAbortOnError=1;
243   
244    HANDLE hCom=(HANDLE)m_pHandle;
245    if (!SetCommState(hCom, &dcb)) { 
246      SaveError();
247                    ERROR(_T("Failed to set comm state - port %s handle=%d err=%d\n"),(LPCTSTR)m_strPort,hCom,GetLastError());
248    } else {
249                    COMMTIMEOUTS commtimeouts;
250        if(m_bBlockingReads){           
251                        commtimeouts.ReadIntervalTimeout=m_nInterCharReadTimeout;
252            commtimeouts.ReadTotalTimeoutMultiplier=0;
253            commtimeouts.ReadTotalTimeoutConstant=m_nTotalReadTimeout;
254        } else {
255                        commtimeouts.ReadIntervalTimeout=MAXDWORD;
256            commtimeouts.ReadTotalTimeoutMultiplier=0;
257            commtimeouts.ReadTotalTimeoutConstant=0;
258        }
259        commtimeouts.WriteTotalTimeoutMultiplier=m_nTotalWriteTimeout;
260        commtimeouts.WriteTotalTimeoutConstant=m_nInterCharWriteTimeout;
261       
262        if (SetCommTimeouts(hCom, &commtimeouts)) { 
263          rc=true;
264        } else {
265          SaveError();
266          ERROR(_T("Failed to set comm timeouts - port %s\n"),(LPCTSTR)m_strPort);
267        }
268    }
269  }
270  catch(...)
271  {
272    TRACE(_T("!!! Exception caught in CeCosSerial::ApplySettings!!!\n"));
273  }
274  return rc;
275}
276
277bool CeCosSerial::Read (void *pBuf,unsigned int nSize,unsigned int &nRead)
278{
279  bool rc=(TRUE==ReadFile((HANDLE)m_pHandle,pBuf,nSize,(LPDWORD)&nRead,0));
280  SaveError();
281  return rc;
282}
283
284bool CeCosSerial::Write(void *pBuf,unsigned int nSize,unsigned int &nWritten)
285{
286  bool rc=(TRUE==WriteFile((HANDLE)m_pHandle,pBuf,nSize,(LPDWORD)&nWritten,0));
287  SaveError();
288  return rc;
289}
290
291bool CeCosSerial::ClearError()
292{
293  DWORD dwErrors;
294  bool rc=(TRUE==ClearCommError(HANDLE(m_pHandle),&dwErrors,0));
295  if(dwErrors&CE_BREAK)TRACE(_T("The hardware detected a break condition.\n"));
296  if(dwErrors&CE_DNS)TRACE(_T("Windows 95 and Windows 98: A parallel device is not selected.\n"));
297  if(dwErrors&CE_FRAME)TRACE(_T("The hardware detected a framing error.\n"));
298  if(dwErrors&CE_IOE)TRACE(_T("An I/O error occurred during communications with the device.\n"));
299  if(dwErrors&CE_MODE)TRACE(_T("The requested mode is not supported, or the hFile parameter is invalid. If this value is specified, it is the only valid error.\n"));
300  if(dwErrors&CE_OOP)TRACE(_T("Windows 95 and Windows 98: A parallel device signaled that it is out of paper.\n"));
301  if(dwErrors&CE_OVERRUN)TRACE(_T("A character-buffer overrun has occurred. The next character is lost.\n"));
302  if(dwErrors&CE_PTO)TRACE(_T("Windows 95 and Windows 98: A time-out occurred on a parallel device.\n"));
303  if(dwErrors&CE_RXOVER)TRACE(_T("An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character.\n"));
304  if(dwErrors&CE_RXPARITY)TRACE(_T("The hardware detected a parity error.\n"));
305  if(dwErrors&CE_TXFULL)TRACE(_T("The application tried to transmit a character, but the output buffer was full.\n"));
306  return rc;
307}
308
309bool CeCosSerial::Flush (void)
310{
311  bool rc=(TRUE==PurgeComm ((HANDLE)m_pHandle,PURGE_TXCLEAR|PURGE_RXCLEAR));
312  SaveError();
313  return rc;
314}
315
316String CeCosSerial::ErrString() const
317{
318  String str;
319  LPVOID lpMsgBuf;
320  FormatMessage( 
321    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
322    FORMAT_MESSAGE_FROM_SYSTEM | 
323    FORMAT_MESSAGE_IGNORE_INSERTS,
324    NULL,
325    m_nErr,
326    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
327    (LPTSTR) &lpMsgBuf,
328    0,
329    NULL 
330    );
331  str=(LPCTSTR)lpMsgBuf;
332  // Free the buffer.
333  LocalFree( lpMsgBuf );
334  return str;
335}
336
337#else // UNIX
338
339String CeCosSerial::ErrString() const
340{
341  return strerror(errno);
342}
343
344bool CeCosSerial::Close()
345{
346  bool rc=m_pHandle && (-1!=close((int)m_pHandle));
347  m_pHandle=0;
348  return rc;
349}
350
351bool CeCosSerial::Open(LPCTSTR pszPort,int nBaud)
352{
353  bool rc=false;
354  m_nBaud=nBaud,
355    m_strPort=pszPort;
356  int fd = open(pszPort,O_RDWR|O_NONBLOCK);
357  if (-1==fd) { 
358    ERROR(_T("Failed to open port %s\n"),pszPort);
359    return false;
360  } else {
361    m_pHandle=(void *)fd;
362    if(ApplySettings()){
363      rc=true;
364    } else {
365      Close();
366      ERROR(_T("Failed to apply settings.\n"));
367      return false;
368    }
369  }
370  return rc;
371}
372
373bool CeCosSerial::ApplySettings()
374{
375  struct termios buf, buf_verify;
376  int rate;
377 
378  // Clear the two structures so we can make a binary comparison later on.
379  memset(&buf, 0, sizeof(buf));
380  memset(&buf_verify, 0, sizeof(buf_verify));
381 
382  LPCTSTR arpszStopbits[3]={_T("1"),_T("1.5"),_T("2")};
383  TRACE(_T("Applysettings baud=%d bParity=%d stopbits=%s databits=%d\n"),
384    m_nBaud, 
385    m_bParity, 
386    arpszStopbits[m_nStopBits],
387    m_nDataBits);
388 
389  switch(m_nBaud) {
390  case 110:
391    rate = B110;
392    break;
393  case 150:
394    rate = B150;
395    break;
396  case 300:
397    rate = B300;
398    break;
399  case 600:
400    rate = B600;
401    break;
402  case 1200:
403    rate = B1200;
404    break;
405  case 2400:
406    rate = B2400;
407    break;
408  case 4800:
409    rate = B4800;
410    break;
411  case 9600:
412    rate = B9600;
413    break;
414  case 19200:
415    rate = B19200;
416    break;
417  case 38400:
418    rate = B38400;
419    break;
420  case 57600:
421    rate = B57600;
422    break;
423  case 115200:
424    rate = B115200;
425    break;
426  default:
427    return false;
428  };
429 
430  TRACE(_T("Changing configuration...\n"));
431 
432  // Get current settings.
433  if (tcgetattr((int) m_pHandle, &buf)) {
434    fprintf(stderr, _T("Error: tcgetattr\n"));
435    return false;
436  }
437 
438  // Reset to raw.
439  buf.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
440    |INLCR|IGNCR|ICRNL|IXON);
441  buf.c_oflag &= ~OPOST;
442  buf.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
443  buf.c_cflag &= ~(CSIZE|PARENB);
444  buf.c_cflag |= CS8;
445 
446  // Set baud rate.
447  cfsetispeed(&buf, rate);
448  cfsetospeed(&buf, rate);
449 
450  // Set data bits.
451  {
452    int data_bits[9] = {0, 0, 0, 0, 0, CS5, CS6, CS7, CS8};
453   
454    buf.c_cflag &= ~CSIZE;
455    buf.c_cflag |= data_bits[m_nDataBits];
456  }
457 
458  // Set stop bits.
459  {
460    buf.c_cflag &= ~CSTOPB;
461    if (ONE_STOP_BIT != m_nStopBits)
462      buf.c_cflag |= CSTOPB;
463  }
464 
465  // Set parity.
466  {
467    buf.c_cflag &= ~(PARENB | PARODD); // no parity.
468    if (m_bParity)                  // even parity.
469      buf.c_cflag |= PARENB;
470  }
471
472  // Set flow control
473  {
474      buf.c_iflag &= ~(IXON|IXOFF);
475#ifdef CRTSCTS
476      buf.c_cflag &= ~CRTSCTS;
477#endif
478      if ( m_bXONXOFFFlowControl ) {
479          buf.c_iflag |= (IXON|IXOFF);
480      }
481      if ( m_bRTSCTSFlowControl ) {
482#ifdef CRTSCTS
483          buf.c_cflag |= CRTSCTS;
484#else
485          return false;
486#endif
487      }
488      if ( m_bDSRDTRFlowControl ) {
489#ifdef CDSRDTR
490          buf.c_cflag |= CDSRDTR;
491#else
492          return false;
493#endif
494      }
495     
496     
497  }
498 
499  // Set the new settings
500  if (tcsetattr((int) m_pHandle, TCSADRAIN, &buf)) {
501    fprintf(stderr, _T("Error: tcsetattr\n"));
502    return false;
503  }
504 
505  // Now read back the settings. On SunOS tcsetattr only returns
506  // error if _all_ settings fail. If just a few settings are not
507  // supported, the call returns true while the hardware is set to a
508  // combination of old and new settings.
509  if (tcgetattr((int) m_pHandle, &buf_verify)) {
510    fprintf(stderr, _T("Error: tcgetattr\n"));
511    return false;
512  }
513  if (memcmp(&buf, &buf_verify, sizeof(buf))) {
514    fprintf(stderr, _T("Error: termios verify failed\n"));
515    return false;
516  }
517 
518  // A slight delay to allow things to settle.
519  CeCosThreadUtils::Sleep(10);
520 
521  TRACE(_T("Done.\n"));
522 
523  return true;
524}
525
526bool CeCosSerial::Flush (void)
527{
528  return 0==tcflush((int) m_pHandle, TCIOFLUSH);
529}
530
531bool CeCosSerial::Read (void *pBuf,unsigned int nSize,unsigned int &nRead)
532{
533 
534  if (!m_bBlockingReads) {
535    nRead = 0;
536    int n = read((int)m_pHandle, pBuf, nSize);
537    if (-1 == n) {
538      if (EAGAIN == errno)
539        return true;
540      ERROR(_T("Read failed: %d\n"), errno);
541      return false;
542    }
543    nRead = n;
544#if 0
545    if (n>0) {
546        unsigned int i;
547        fprintf(stderr, "%d:", nRead);
548        for (i = 0; i < nRead; i++)
549            fprintf(stderr, "%02x!", ((unsigned char *)pBuf)[i]);
550        fprintf(stderr, "\n");
551    }
552#endif
553    return true;
554  }
555 
556  // Blocking reads: emulate the Windows semantics:
557  //  If m_nTotalReadTimeout elapses before we see the first TCHAR,
558  //   return.
559  //  If m_nInterCharReadTimeout elapses after reading any
560  //   subsequent TCHAR, return.
561 
562  fd_set rfds;
563  FD_ZERO(&rfds);
564  FD_SET((int)m_pHandle, &rfds);
565 
566  // Start with total timeout.
567  struct timeval tv;
568  tv.tv_sec = m_nTotalReadTimeout / 1000;
569  tv.tv_usec = (m_nTotalReadTimeout % 1000) * 1000;
570 
571  unsigned char* pData = (unsigned char*) pBuf;
572  nRead = 0;
573  while (nSize) {
574    switch(select((int)m_pHandle + 1, &rfds, NULL, NULL, &tv)) {
575    case 1:
576      {
577        int n = read((int)m_pHandle, pData, nSize);
578        if (-1 == n && EAGAIN != errno) {
579          ERROR(_T("Read failed: %d\n"), errno);
580          return false;           // FAILED
581        }
582        else if (n > 0) {
583#if 0
584            unsigned int i;
585            fprintf(stderr, "%d:", nRead);
586            for (i = 0; i < nRead; i++)
587                fprintf(stderr, "%02x!", ((unsigned char *)pBuf)[i]);
588            fprintf(stderr, "\n");
589#endif
590            nRead += n;
591            pData += n;
592            nSize -= n;
593        }
594       
595        // Now use inter-char timeout.
596        tv.tv_sec = m_nInterCharReadTimeout / 1000;
597        tv.tv_usec = (m_nInterCharReadTimeout % 1000) * 1000;
598      }
599      break;
600    case 0:
601      return true;                // Timeout
602    case -1:
603      ERROR(_T("Select failed: %d\n"), errno);
604      return false;
605    }
606  }
607 
608  return true;
609}
610
611bool CeCosSerial::Write(void *pBuf,unsigned int nSize,unsigned int &nWritten)
612{
613  bool rc;
614  int n=write((int)m_pHandle,pBuf,nSize);
615  if(-1==n){
616    nWritten=0;
617    if (errno == EAGAIN)
618      rc = true;
619    else
620      rc=false;
621  } else {
622    nWritten=n;
623    rc=true;
624  }
625  return rc;
626}
627
628bool CeCosSerial::ClearError()
629{
630  return false;
631}
632
633#endif
Note: See TracBrowser for help on using the repository browser.