comparison host/tools/Utils/common/eCosSerial.cpp @ 82:6736c52df507 ecos-sw-2000-04-14

Merge from eCos master repository on 2000-04-14-13:35:46-BST
author jlarmour
date Tue, 18 Apr 2000 21:51:55 +0000
parents
children 6ed91473a1cd
comparison
equal deleted inserted replaced
81:89fef2181d7d 82:6736c52df507
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
48 CeCosSerial::CeCosSerial():
49 m_nErr(0),
50 m_pHandle(0),
51 m_nDataBits(8),
52 m_nStopBits(ONE_STOP_BIT),
53 m_bParity(false),
54 m_nBaud(0),
55 m_nTotalReadTimeout(10*1000),
56 m_nTotalWriteTimeout(10*1000),
57 m_nInterCharReadTimeout(500),
58 m_nInterCharWriteTimeout(500),
59 m_bBlockingReads(true)
60 {
61 }
62
63 CeCosSerial::~CeCosSerial()
64 {
65 Close();
66 }
67
68 CeCosSerial::CeCosSerial(LPCTSTR pszPort,int nBaud):
69 m_nErr(0),
70 m_pHandle(0),
71 m_nDataBits(8),
72 m_nStopBits(ONE_STOP_BIT),
73 m_bParity(false),
74 m_nTotalReadTimeout(10*1000),
75 m_nTotalWriteTimeout(10*1000),
76 m_nInterCharReadTimeout(500),
77 m_nInterCharWriteTimeout(500),
78 m_bBlockingReads(true)
79 {
80 Open(pszPort,nBaud);
81 }
82
83 bool CeCosSerial::SetBlockingReads(bool b,bool bApplySettingsNow/*=true*/)
84 {
85 m_bBlockingReads=b;
86 return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
87 }
88
89 bool CeCosSerial:: SetBaud(unsigned int nBaud,bool bApplySettingsNow/*=true*/)
90 {
91 m_nBaud=nBaud;
92 return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
93 }
94
95 bool CeCosSerial:: SetParity(bool bParityOn,bool bApplySettingsNow/*=true*/)
96 {
97 m_bParity=bParityOn;
98 return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
99 }
100
101 bool CeCosSerial:: SetDataBits(int n,bool bApplySettingsNow/*=true*/)
102 {
103 m_nDataBits=n;
104 return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
105 }
106
107 bool CeCosSerial:: SetStopBits(StopBitsType n,bool bApplySettingsNow/*=true*/)
108 {
109 m_nStopBits=n;
110 return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
111 }
112
113 bool CeCosSerial:: SetReadTimeOuts(int nTotal,int nBetweenChars,bool bApplySettingsNow/*=true*/) // mSec
114 {
115 m_nTotalReadTimeout=nTotal;
116 m_nInterCharReadTimeout=nBetweenChars;
117
118 return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
119 }
120
121 bool CeCosSerial:: SetWriteTimeOuts(int nTotal,int nBetweenChars,bool bApplySettingsNow/*=true*/) // mSec
122 {
123 m_nTotalWriteTimeout=nTotal;
124 m_nInterCharWriteTimeout=nBetweenChars;
125 return 0==m_pHandle || !bApplySettingsNow || ApplySettings();
126 }
127
128 #ifdef _WIN32
129 bool CeCosSerial::Open(LPCTSTR pszPort,int nBaud)
130 {
131 bool rc=false;
132 m_nBaud=nBaud,
133 m_strPort=pszPort;
134 HANDLE hCom=::CreateFile(pszPort,GENERIC_READ|GENERIC_WRITE, 0,NULL,OPEN_EXISTING,0,NULL);
135 SaveError();
136 if (INVALID_HANDLE_VALUE==hCom) {
137 ERROR(_T("Failed to open port %s - %s\n"),pszPort,(LPCTSTR)ErrString());
138 } else {
139 m_pHandle=(void *)hCom;
140 if(ApplySettings()){
141 Flush();
142 rc=true;
143 } else {
144 Close();
145 }
146 }
147 return rc;
148 }
149
150 bool CeCosSerial::Close()
151 {
152 bool rc=false;
153 if(m_pHandle){
154 try {
155 rc=(TRUE==CloseHandle((HANDLE)m_pHandle));
156 }
157 catch(...) {
158 TRACE(_T("!!! Exception caught closing serial handle %08x\n"),m_pHandle);
159 }
160 m_pHandle=0;
161 } else {
162 rc=true;
163 }
164 return rc;
165 }
166
167 bool CeCosSerial::ApplySettings()
168 {
169 bool rc=false;
170 try {
171 DCB dcb;
172
173 ZeroMemory(&dcb,sizeof dcb);
174 dcb.DCBlength=sizeof dcb;
175 dcb.BaudRate=m_nBaud;
176 dcb.fBinary=true;
177 dcb.fParity=true;
178 dcb.Parity=(BYTE) ((m_bParity) ? EVENPARITY : NOPARITY);
179 dcb.StopBits=(BYTE)m_nStopBits;
180 dcb.ByteSize=(BYTE)m_nDataBits;
181 LPCTSTR arpszStopbits[3]={_T("1"),_T("1.5"),_T("2")};
182 TRACE(_T("Applysettings baud=%d Parity=%d stopbits=%s databits=%d\n"),
183 dcb.BaudRate,
184 dcb.Parity,
185 arpszStopbits[dcb.StopBits],
186 dcb.ByteSize);
187
188 // No control over the following yet
189 dcb.fDtrControl=DTR_CONTROL_ENABLE;
190 dcb.fTXContinueOnXoff=1;
191 dcb.fRtsControl=RTS_CONTROL_ENABLE;
192 dcb.fAbortOnError=1;
193 dcb.XonLim=2048;
194 dcb.XoffLim=512;
195 dcb.XonChar=17;
196 dcb.XoffChar=19;
197
198 HANDLE hCom=(HANDLE)m_pHandle;
199 if (!SetCommState(hCom, &dcb)) {
200 SaveError();
201 ERROR(_T("Failed to set comm state - port %s handle=%d err=%d\n"),(LPCTSTR)m_strPort,hCom,GetLastError());
202 } else {
203 COMMTIMEOUTS commtimeouts;
204 if(m_bBlockingReads){
205 commtimeouts.ReadIntervalTimeout=m_nInterCharReadTimeout;
206 commtimeouts.ReadTotalTimeoutMultiplier=0;
207 commtimeouts.ReadTotalTimeoutConstant=m_nTotalReadTimeout;
208 } else {
209 commtimeouts.ReadIntervalTimeout=MAXDWORD;
210 commtimeouts.ReadTotalTimeoutMultiplier=0;
211 commtimeouts.ReadTotalTimeoutConstant=0;
212 }
213 commtimeouts.WriteTotalTimeoutMultiplier=m_nTotalWriteTimeout;
214 commtimeouts.WriteTotalTimeoutConstant=m_nInterCharWriteTimeout;
215
216 if (SetCommTimeouts(hCom, &commtimeouts)) {
217 rc=true;
218 } else {
219 SaveError();
220 ERROR(_T("Failed to set comm timeouts - port %s\n"),(LPCTSTR)m_strPort);
221 }
222 }
223 }
224 catch(...)
225 {
226 TRACE(_T("!!! Exception caught in CeCosSerial::ApplySettings!!!\n"));
227 }
228 return rc;
229 }
230
231 bool CeCosSerial::Read (void *pBuf,unsigned int nSize,unsigned int &nRead)
232 {
233 bool rc=(TRUE==ReadFile((HANDLE)m_pHandle,pBuf,nSize,(LPDWORD)&nRead,0));
234 SaveError();
235 return rc;
236 }
237
238 bool CeCosSerial::Write(void *pBuf,unsigned int nSize,unsigned int &nWritten)
239 {
240 bool rc=(TRUE==WriteFile((HANDLE)m_pHandle,pBuf,nSize,(LPDWORD)&nWritten,0));
241 SaveError();
242 return rc;
243 }
244
245 bool CeCosSerial::ClearError()
246 {
247 DWORD dwErrors;
248 bool rc=(TRUE==ClearCommError(HANDLE(m_pHandle),&dwErrors,0));
249 if(dwErrors&CE_BREAK)TRACE(_T("The hardware detected a break condition.\n"));
250 if(dwErrors&CE_DNS)TRACE(_T("Windows 95 and Windows 98: A parallel device is not selected.\n"));
251 if(dwErrors&CE_FRAME)TRACE(_T("The hardware detected a framing error.\n"));
252 if(dwErrors&CE_IOE)TRACE(_T("An I/O error occurred during communications with the device.\n"));
253 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"));
254 if(dwErrors&CE_OOP)TRACE(_T("Windows 95 and Windows 98: A parallel device signaled that it is out of paper.\n"));
255 if(dwErrors&CE_OVERRUN)TRACE(_T("A character-buffer overrun has occurred. The next character is lost.\n"));
256 if(dwErrors&CE_PTO)TRACE(_T("Windows 95 and Windows 98: A time-out occurred on a parallel device.\n"));
257 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"));
258 if(dwErrors&CE_RXPARITY)TRACE(_T("The hardware detected a parity error.\n"));
259 if(dwErrors&CE_TXFULL)TRACE(_T("The application tried to transmit a character, but the output buffer was full.\n"));
260 return rc;
261 }
262
263 bool CeCosSerial::Flush (void)
264 {
265 bool rc=(TRUE==PurgeComm ((HANDLE)m_pHandle,PURGE_TXCLEAR|PURGE_RXCLEAR));
266 SaveError();
267 return rc;
268 }
269
270 String CeCosSerial::ErrString() const
271 {
272 String str;
273 LPVOID lpMsgBuf;
274 FormatMessage(
275 FORMAT_MESSAGE_ALLOCATE_BUFFER |
276 FORMAT_MESSAGE_FROM_SYSTEM |
277 FORMAT_MESSAGE_IGNORE_INSERTS,
278 NULL,
279 m_nErr,
280 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
281 (LPTSTR) &lpMsgBuf,
282 0,
283 NULL
284 );
285 str=(LPCTSTR)lpMsgBuf;
286 // Free the buffer.
287 LocalFree( lpMsgBuf );
288 return str;
289 }
290
291 #else // UNIX
292
293 String CeCosSerial::ErrString() const
294 {
295 return strerror(errno);
296 }
297
298 bool CeCosSerial::Close()
299 {
300 bool rc=m_pHandle && (-1!=close((int)m_pHandle));
301 m_pHandle=0;
302 return rc;
303 }
304
305 bool CeCosSerial::Open(LPCTSTR pszPort,int nBaud)
306 {
307 bool rc=false;
308 m_nBaud=nBaud,
309 m_strPort=pszPort;
310 int fd = open(pszPort,O_RDWR|O_NONBLOCK);
311 if (-1==fd) {
312 ERROR(_T("Failed to open port %s\n"),pszPort);
313 return false;
314 } else {
315 m_pHandle=(void *)fd;
316 if(ApplySettings()){
317 rc=true;
318 } else {
319 Close();
320 ERROR(_T("Failed to apply settings.\n"));
321 return false;
322 }
323 }
324 return rc;
325 }
326
327 bool CeCosSerial::ApplySettings()
328 {
329 struct termios buf, buf_verify;
330 int rate;
331
332 // Clear the two structures so we can make a binary comparison later on.
333 memset(&buf, 0, sizeof(buf));
334 memset(&buf_verify, 0, sizeof(buf_verify));
335
336 LPCTSTR arpszStopbits[3]={_T("1"),_T("1.5"),_T("2")};
337 TRACE(_T("Applysettings baud=%d bParity=%d stopbits=%s databits=%d\n"),
338 m_nBaud,
339 m_bParity,
340 arpszStopbits[m_nStopBits],
341 m_nDataBits);
342
343 switch(m_nBaud) {
344 case 110:
345 rate = B110;
346 break;
347 case 150:
348 rate = B150;
349 break;
350 case 300:
351 rate = B300;
352 break;
353 case 600:
354 rate = B600;
355 break;
356 case 1200:
357 rate = B1200;
358 break;
359 case 2400:
360 rate = B2400;
361 break;
362 case 4800:
363 rate = B4800;
364 break;
365 case 9600:
366 rate = B9600;
367 break;
368 case 19200:
369 rate = B19200;
370 break;
371 case 38400:
372 rate = B38400;
373 break;
374 case 57600:
375 rate = B57600;
376 break;
377 case 115200:
378 rate = B115200;
379 break;
380 default:
381 return false;
382 };
383
384 TRACE(_T("Changing configuration...\n"));
385
386 // Get current settings.
387 if (tcgetattr((int) m_pHandle, &buf)) {
388 fprintf(stderr, _T("Error: tcgetattr\n"));
389 return false;
390 }
391
392 // Reset to raw.
393 buf.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
394 |INLCR|IGNCR|ICRNL|IXON);
395 buf.c_oflag &= ~OPOST;
396 buf.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
397 buf.c_cflag &= ~(CSIZE|PARENB);
398 buf.c_cflag |= CS8;
399
400 // Set baud rate.
401 cfsetispeed(&buf, rate);
402 cfsetospeed(&buf, rate);
403
404 // Set data bits.
405 {
406 int data_bits[9] = {0, 0, 0, 0, 0, CS5, CS6, CS7, CS8};
407
408 buf.c_cflag &= ~CSIZE;
409 buf.c_cflag |= data_bits[m_nDataBits];
410 }
411
412 // Set stop bits.
413 {
414 buf.c_cflag &= ~CSTOPB;
415 if (ONE_STOP_BIT != m_nStopBits)
416 buf.c_cflag |= CSTOPB;
417 }
418
419 // Set parity.
420 {
421 buf.c_cflag &= ~(PARENB | PARODD); // no parity.
422 if (m_bParity) // even parity.
423 buf.c_cflag |= PARENB;
424 }
425
426 // Set the new settings
427 if (tcsetattr((int) m_pHandle, TCSADRAIN, &buf)) {
428 fprintf(stderr, _T("Error: tcsetattr\n"));
429 return false;
430 }
431
432 // Now read back the settings. On SunOS tcsetattr only returns
433 // error if _all_ settings fail. If just a few settings are not
434 // supported, the call returns true while the hardware is set to a
435 // combination of old and new settings.
436 if (tcgetattr((int) m_pHandle, &buf_verify)) {
437 fprintf(stderr, _T("Error: tcgetattr\n"));
438 return false;
439 }
440 if (memcmp(&buf, &buf_verify, sizeof(buf))) {
441 fprintf(stderr, _T("Error: termios verify failed\n"));
442 return false;
443 }
444
445 // A slight delay to allow things to settle.
446 CeCosThreadUtils::Sleep(10);
447
448 TRACE(_T("Done.\n"));
449
450 return true;
451 }
452
453 bool CeCosSerial::Flush (void)
454 {
455 return 0==tcflush((int) m_pHandle, TCIOFLUSH);
456 }
457
458 bool CeCosSerial::Read (void *pBuf,unsigned int nSize,unsigned int &nRead)
459 {
460
461 if (!m_bBlockingReads) {
462 nRead = 0;
463 int n = read((int)m_pHandle, pBuf, nSize);
464 if (-1 == n) {
465 if (EAGAIN == errno)
466 return true;
467 ERROR(_T("Read failed: %d\n"), errno);
468 return false;
469 }
470 nRead = n;
471 return true;
472 }
473
474 // Blocking reads: emulate the Windows semantics:
475 // If m_nTotalReadTimeout elapses before we see the first TCHAR,
476 // return.
477 // If m_nInterCharReadTimeout elapses after reading any
478 // subsequent TCHAR, return.
479
480 fd_set rfds;
481 FD_ZERO(&rfds);
482 FD_SET((int)m_pHandle, &rfds);
483
484 // Start with total timeout.
485 struct timeval tv;
486 tv.tv_sec = m_nTotalReadTimeout / 1000;
487 tv.tv_usec = (m_nTotalReadTimeout % 1000) * 1000;
488
489 unsigned char* pData = (unsigned char*) pBuf;
490 nRead = 0;
491 while (nSize) {
492 switch(select((int)m_pHandle + 1, &rfds, NULL, NULL, &tv)) {
493 case 1:
494 {
495 int n = read((int)m_pHandle, pData, nSize);
496 if (-1 == n && EAGAIN != errno) {
497 ERROR(_T("Read failed: %d\n"), errno);
498 return false; // FAILED
499 }
500 nRead += n;
501 pData += n;
502 nSize -= n;
503
504 // Now use inter-char timeout.
505 tv.tv_sec = m_nInterCharReadTimeout / 1000;
506 tv.tv_usec = (m_nInterCharReadTimeout % 1000) * 1000;
507 }
508 break;
509 case 0:
510 return true; // Timeout
511 case -1:
512 ERROR(_T("Select failed: %d\n"), errno);
513 return false;
514 }
515 }
516
517 return true;
518 }
519
520 bool CeCosSerial::Write(void *pBuf,unsigned int nSize,unsigned int &nWritten)
521 {
522 bool rc;
523 int n=write((int)m_pHandle,pBuf,nSize);
524 if(-1==n){
525 nWritten=0;
526 if (errno == EAGAIN)
527 rc = true;
528 else
529 rc=false;
530 } else {
531 nWritten=n;
532 rc=true;
533 }
534 return rc;
535 }
536
537 bool CeCosSerial::ClearError()
538 {
539 return false;
540 }
541
542 #endif