libserial  1.6.2
RoadNarrows Roboitics Serial Library
serdev.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: RCB3
4 //
5 // Library: libserial
6 //
7 // File: serdev.c
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-02-24 12:58:53 -0700 (Tue, 24 Feb 2015) $
12  * $Rev: 3870 $
13  *
14  * \brief RS-232 serial device communication definitions.
15  *
16  * Ported from ipserddev.c (RoadNarrows)
17  *
18  * \author Robin Knight (robin.knight@roadnarrows.com)
19  *
20  * \copyright
21  * \h_copy 2006-2017. RoadNarrows LLC.\n
22  * http://www.roadnarrows.com\n
23  * All Rights Reserved
24  */
25 /*
26  * @EulaBegin@
27 // Permission is hereby granted, without written agreement and without
28 // license or royalty fees, to use, copy, modify, and distribute this
29 // software and its documentation for any purpose, provided that
30 // (1) The above copyright notice and the following two paragraphs
31 // appear in all copies of the source code and (2) redistributions
32 // including binaries reproduces these notices in the supporting
33 // documentation. Substantial modifications to this software may be
34 // copyrighted by their authors and need not follow the licensing terms
35 // described here, provided that the new terms are clearly indicated in
36 // all files where they apply.
37 //
38 // IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
39 // OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
40 // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
41 // DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
42 // EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
43 // THE POSSIBILITY OF SUCH DAMAGE.
44 //
45 // THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
46 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
47 // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
48 // "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
49 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
50  * @EulaEnd@
51  */
52 //
53 ////////////////////////////////////////////////////////////////////////////////
54 
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <sys/time.h>
58 #include <sys/ioctl.h>
59 #include <limits.h>
60 #include <fcntl.h>
61 #include <termios.h>
62 #include <unistd.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <stdarg.h>
66 #include <time.h>
67 #include <errno.h>
68 #include <string.h>
69 
70 #include "rnr/rnrconfig.h"
71 #include "rnr/log.h"
72 #include "rnr/new.h"
73 #include "rnr/serdev.h"
74 
75 
76 
77 // ---------------------------------------------------------------------------
78 // Private Interface
79 // ---------------------------------------------------------------------------
80 
81 /*!
82  * \brief Bitwise complement.
83  *
84  * \param bits Bits.
85  */
86 #define NOTBITS(bits) ~((uint_t)(bits))
87 
88 PRAGMA_IGNORED(sign-conversion)
89 /*!
90  * \brief FD_SET() wrapper with no annoying warnings.
91  * \param fd File descriptor to add to set.
92  * \param pset Pointer to fd set.
93  */
94 static inline void fdset_nowarn(int fd, fd_set *pset)
95 {
96  FD_SET(fd, pset);
97 }
98 PRAGMA_WARNING(sign-conversion)
99 
100 // ...........................................................................
101 // SerDev Specific Logging
102 // ...........................................................................
103 
104 #undef SERDEV_DEBUG // define for more debugging
105 
106 #ifdef LOG
107 /*!
108  * \brief Log read/written bytes to log stream.
109  * \param buffer Buffer of bytes.
110  * \param size Number of bytes in buffer to log.
111  * \param bNewLine Do [not] output trailing newline.
112  */
113 #define SERDEVLOG(buffer, size, bNewLine) \
114  {if(LOGABLE(LOG_LEVEL_DIAG4)) {SerDevLogBytes(buffer, size, bNewLine);}}
115 
116 /*!
117  * \brief Write newline character to log stream.
118  */
119 #define SERDEVLOGNL() \
120  {if(LOGABLE(LOG_LEVEL_DIAG4)) {fprintf(LOG_GET_LOGFP(), "\n");}}
121 
122 #else
123 #define SERDEVLOG(buffer, size, bNewLine) ///< no logging facilities - noop
124 
125 #define SERDEVLOGNL() ///< no logging facilities - noop
126 
127 #endif // LOG
128 
129 
130 #ifdef LOG
131 /*!
132  * \brief Log read/written bytes to log stream.
133  *
134  * \param buffer Buffer of bytes.
135  * \param size Number of bytes in buffer to log.
136  * \param bNewLine Do [not] output trailing newline.
137  */
138 static void SerDevLogBytes(byte_t buffer[], size_t size, bool_t bNewLine)
139 {
140  size_t n;
141  FILE *fp;
142  char *sep = " ";
143 
144  if( size == 0 )
145  {
146  return;
147  }
148 
149  fp = LOG_GET_LOGFP();
150 
151  for(n=0; n<size; ++n)
152  {
153  fprintf(fp, "%s0x%02x", sep, buffer[n]);
154  }
155 
156  if( bNewLine )
157  {
158  fprintf(fp, "\n");
159  }
160 }
161 #endif // LOG
162 
163 
164 // ...........................................................................
165 // Timer Utilities
166 // ...........................................................................
167 
168 /*!
169  * \brief Mark the current time. Resolution is microseconds.
170  *
171  * \param pTvMark Pointer to timeval structure to be populated with
172  * the current system seconds and useconds.
173  */
174 static inline void timer_mark(struct timeval *pTvMark)
175 {
176  if( gettimeofday(pTvMark, NULL) != OK )
177  {
178  LOGSYSERROR("gettimeofday()");
179  timerclear(pTvMark);
180  }
181 }
182 
183 /*!
184  * \brief Calculate the elapsed time between the given time mark and this call.
185  *
186  * \param pTvMark Pointer to timeval holding time mark.
187  *
188  * \return
189  * Number of microseconds elasped. If the marked time is invalid or the current
190  * time cannot be ascertained, UINT_MAX is returned.
191  */
192 static uint_t timer_elapsed(struct timeval *pTvMark)
193 {
194  struct timeval tvEnd, tvDelta;
195 
196  timer_mark(&tvEnd);
197 
198  if( !timerisset(pTvMark) || !timerisset(&tvEnd) )
199  {
200  return UINT_MAX;
201  }
202 
203  tvDelta.tv_sec = tvEnd.tv_sec - pTvMark->tv_sec;
204  if( tvEnd.tv_usec < pTvMark->tv_usec )
205  {
206  tvDelta.tv_sec--;
207  tvEnd.tv_usec += 1000000;
208  }
209  tvDelta.tv_usec = tvEnd.tv_usec - pTvMark->tv_usec;
210 
211  return (uint_t)(tvDelta.tv_sec * 1000000 + tvDelta.tv_usec);
212 }
213 
214 // ...........................................................................
215 // RS-232 Serial Device I/O Controll and Configuration
216 // ...........................................................................
217 
218 //
219 // Ioctl commands and values. If not defined in termios.h, then use
220 // linux defaults
221 //
222 #ifdef FIONREAD
223 #define SERDEV_FIONREAD FIONREAD ///< number in input queue
224 #else
225 #define SERDEV_FIONREAD 0x541b ///< number in input queue
226 #endif
227 
228 #define SERDEV_NO_ATTR 0xffffffff ///< Special "No Attribute" value.
229 
230 /*!
231  * \brief Serial Device Attribute Key - Value Pair structure.
232  */
233 typedef struct
234 {
235  void *m_pKey; ///< attribute key
236  unsigned int m_uVal; ///< attribute value
238 
239 /*!
240  * \brief Serial device attribute macros.
241  * \param attr Attribute define.
242  */
243 #define SERDEV_ATTR_ENTRY(attr) { (void *)#attr , attr }
244 
245 /*!
246  * \brief Get I/O defined attribute value.
247  * \param attr Attribute define.
248  */
249 #define SERDEV_GET_ATTR(attr) \
250  SerDevAttrLookup(SerDevOptAttrTbl, \
251  arraysize(SerDevOptAttrTbl), (void *)#attr, SerDevOptAttrCmp)
252 
253 /*!
254  * \brief Serial option attribute comparator
255  * \param pKey1 Attribute key 1
256  * \param pKey2 Attribute key 2
257  */
258 static inline int SerDevOptAttrCmp(const void *pKey1, const void *pKey2)
259 {
260  return strcmp((const char *)pKey1, (const char *)pKey2);
261 }
262 
263 /*!
264  * \brief SerDevOptAttr table.
265  * Dynamic method to determine serial device optional defined attributes
266  * for each plaform architecture.
267  */
269 {
270 #ifdef ECHOCTL
271  SERDEV_ATTR_ENTRY(ECHOCTL),
272 #endif
273 #ifdef ECHOKE
274  SERDEV_ATTR_ENTRY(ECHOKE),
275 #endif
276 #ifdef IOCLC
277  SERDEV_ATTR_ENTRY(IOCLC),
278 #endif
279 #ifdef PARMRK
280  SERDEV_ATTR_ENTRY(PARMRK),
281 #endif
282 #ifdef IXANY
283  SERDEV_ATTR_ENTRY(IXANY),
284 #endif
285 #ifdef CRTSCTS
286  SERDEV_ATTR_ENTRY(CRTSCTS),
287 #endif
288 #ifdef CNEW_RTSCTS // try it with alternate constant name
289  SERDEV_ATTR_ENTRY(CNEW_RTSCTS),
290 #endif
291  {(void *)"*noattr*", SERDEV_NO_ATTR} // make sure something is in the table
292 };
293 
294 /*!
295  * \brief Serial device supported baudrate macros.
296  * \param baudrate Integer baudrate.
297  */
298 #define SERDEV_BAUDRATE_ENTRY(baudrate) \
299  { (void *)((unsigned long)baudrate), B##baudrate }
300 
301 /*!
302  * \brief Get baudrate defined value.
303  * \param baudrate Integer baudrate.
304  */
305 #define SERDEV_GET_BAUDRATE(baudrate) \
306  SerDevAttrLookup(SerDevBaudRateTbl, arraysize(SerDevBaudRateTbl), \
307  (void *)((unsigned long)baudrate), SerDevBaudRateCmp)
308 
309 /*!
310  * \brief BaudRate attribute comparator
311  * \param pKey1 Attribute key 1
312  * \param pKey2 Attribute key 2
313  */
314 static inline int SerDevBaudRateCmp(const void *pKey1, const void *pKey2)
315 {
316  return (unsigned long)pKey1 == (unsigned long)pKey2? 0: 1;
317 }
318 
319 /*!
320  * \brief SerDevBaudRate table.
321  * Dynamic method to determine Serial device supported baud rates
322  * for each plaform architecture.
323  */
325 {
326 #ifdef B50
328 #endif
329 #ifdef B75
331 #endif
332 #ifdef B110
334 #endif
335 #ifdef B134
337 #endif
338 #ifdef B150
340 #endif
341 #ifdef B200
343 #endif
344 #ifdef B300
346 #endif
347 #ifdef B600
349 #endif
350 #ifdef B1200
351  SERDEV_BAUDRATE_ENTRY(1200),
352 #endif
353 #ifdef B1800
354  SERDEV_BAUDRATE_ENTRY(1800),
355 #endif
356 #ifdef B2400
357  SERDEV_BAUDRATE_ENTRY(2400),
358 #endif
359 #ifdef B4800
360  SERDEV_BAUDRATE_ENTRY(4800),
361 #endif
362 #ifdef B9600
363  SERDEV_BAUDRATE_ENTRY(9600),
364 #endif
365 #ifdef B19200
366  SERDEV_BAUDRATE_ENTRY(19200),
367 #endif
368 #ifdef B38400
369  SERDEV_BAUDRATE_ENTRY(38400),
370 #endif
371 #ifdef B57600
372  SERDEV_BAUDRATE_ENTRY(57600),
373 #endif
374 #ifdef B115200
375  SERDEV_BAUDRATE_ENTRY(115200),
376 #endif
377 #ifdef B230400
378  SERDEV_BAUDRATE_ENTRY(230400),
379 #endif
380 #ifdef B460800
381  SERDEV_BAUDRATE_ENTRY(460800),
382 #endif
383 #ifdef B500000
384  SERDEV_BAUDRATE_ENTRY(500000),
385 #endif
386 #ifdef B576000
387  SERDEV_BAUDRATE_ENTRY(576000),
388 #endif
389 #ifdef B921600
390  SERDEV_BAUDRATE_ENTRY(921600),
391 #endif
392 #ifdef B1000000
393  SERDEV_BAUDRATE_ENTRY(1000000),
394 #endif
395 #ifdef B1152000
396  SERDEV_BAUDRATE_ENTRY(1152000),
397 #endif
398 #ifdef B1500000
399  SERDEV_BAUDRATE_ENTRY(1500000),
400 #endif
401 #ifdef B2000000
402  SERDEV_BAUDRATE_ENTRY(2000000),
403 #endif
404 #ifdef B2250000
405  SERDEV_BAUDRATE_ENTRY(2250000),
406 #endif
407 #ifdef B2500000
408  SERDEV_BAUDRATE_ENTRY(2500000),
409 #endif
410 #ifdef B3000000
411  SERDEV_BAUDRATE_ENTRY(3000000),
412 #endif
413 #ifdef B3500000
414  SERDEV_BAUDRATE_ENTRY(3500000),
415 #endif
416 #ifdef B4000000
417  SERDEV_BAUDRATE_ENTRY(4000000),
418 #endif
419 };
420 
421 /*!
422  * \brief Lookup the attribute value associated with the key.
423  *
424  * \param tbl[] Attribute Key-Value Pair table.
425  * \param nTblEntries Number of Key-Value Pair table entries.
426  * \param pKey Key to lookup.
427  * \param cmp Attribute key comparator function.
428  *
429  * \return
430  * The associated attribute value on success, or SERDEV_NO_ATTR if the search
431  * failed.
432  */
433 static unsigned int SerDevAttrLookup(SerDevAttrKvp_T tbl[], size_t nTblEntries,
434  const void *pKey, int (*cmp)(const void *, const void *))
435 {
436  int i;
437 
438  for(i=0; i<nTblEntries; ++i)
439  {
440  if( !cmp(tbl[i].m_pKey, pKey) )
441  {
442  return tbl[i].m_uVal;
443  }
444  }
445  return SERDEV_NO_ATTR;
446 }
447 
448 /*!
449  * \brief (Re)configure a serial device attibutes.
450  *
451  * \param fd File descriptor to the opened serial device.
452  * \param nBaudRate Baud rate.
453  * \param nByteSize Bytes size in bits 5...8.
454  * \param cParity Parity. One of: 'N', 'E', 'O'
455  * \param nStopBits Number of stop bits 1, 2
456  * \param bRtsCts Do [not] use hardware flow control.
457  * \param bXonXoff Do [not] use software flow control.
458  *
459  * \return
460  * Returns OK(0) on success.
461  * \n On failure, errno is set and RC_ERROR(-1) is returned.
462  */
463 static int SerDevConfigure(int fd,
464  int nBaudRate,
465  int nByteSize,
466  int cParity,
467  int nStopBits,
468  bool_t bRtsCts,
469  bool_t bXonXoff)
470 {
471  struct termios tios;
472  speed_t ospeed, ispeed;
473  uint_t attr;
474 
475  if( fd < 0 )
476  {
477  LOGERROR("Invalid serial device file descriptor: %d", fd);
478  errno = EBADF;
479  return RC_ERROR;
480  }
481 
482  // get the current device attributes
483  if( tcgetattr(fd, &tios) == -1 )
484  {
485  LOGSYSERROR("tcgetattr(%d,...) failed", fd);
486  return RC_ERROR;
487  }
488 
489  // set up raw mode / no echo / binary
490  tios.c_cflag |= (CLOCAL|CREAD);
491  tios.c_lflag &= NOTBITS(ICANON|ECHO|ECHOE|ECHOK|ECHONL|ISIG|IEXTEN);
492  // |ECHOPRT
493  if( (attr = SERDEV_GET_ATTR(ECHOCTL)) != SERDEV_NO_ATTR )
494  {
495  tios.c_lflag &= NOTBITS(attr);
496  }
497  if( (attr = SERDEV_GET_ATTR(ECHOKE)) != SERDEV_NO_ATTR )
498  {
499  tios.c_lflag &= NOTBITS(attr);
500  }
501 
502  tios.c_oflag &= NOTBITS(OPOST);
503 
504  tios.c_iflag &= NOTBITS(INLCR|IGNCR|ICRNL|IGNBRK);
505  if( (attr = SERDEV_GET_ATTR(IOCLC)) != SERDEV_NO_ATTR )
506  {
507  tios.c_iflag &= NOTBITS(attr);
508  }
509  if( (attr = SERDEV_GET_ATTR(PARMRK)) != SERDEV_NO_ATTR )
510  {
511  tios.c_iflag &= NOTBITS(attr);
512  }
513 
514  // set up baudrate
515  if((ospeed = SERDEV_GET_BAUDRATE(nBaudRate)) == SERDEV_NO_ATTR)
516  {
517  LOGERROR("Invalid/unsupported baud rate: %u", nBaudRate);
518  errno = EINVAL;
519  return RC_ERROR;
520  }
521  ispeed = ospeed;
522  if( cfsetospeed(&tios, ospeed) == -1 ) // set output baudrate in structure
523  {
524  LOGSYSERROR("tcsetospeed(tios,%u)", ospeed);
525  return RC_ERROR;
526  }
527  if( cfsetispeed(&tios, ispeed) == -1 ) // set input baudrate in structure
528  {
529  LOGSYSERROR("tcsetispeed(tios,%u)", ispeed);
530  return RC_ERROR;
531  }
532 
533  // set up data character size (bits)
534  tios.c_cflag &= NOTBITS(CSIZE);
535  switch( nByteSize )
536  {
537  case 8:
538  tios.c_cflag |= CS8;
539  break;
540  case 7:
541  tios.c_cflag |= CS7;
542  break;
543  case 6:
544  tios.c_cflag |= CS6;
545  break;
546  case 5:
547  tios.c_cflag |= CS5;
548  break;
549  default:
550  LOGERROR("Invalid data byte size: %u", nByteSize);
551  errno = EINVAL;
552  return RC_ERROR;
553  }
554 
555  // set up stopbits
556  switch( nStopBits )
557  {
558  case 1:
559  tios.c_cflag &= NOTBITS(CSTOPB);
560  break;
561  case 2:
562  tios.c_cflag |= (CSTOPB);
563  break;
564  default:
565  LOGERROR("Invalid number of stop bits: %u", nStopBits);
566  errno = EINVAL;
567  return RC_ERROR;
568  }
569 
570  // set up parity
571  tios.c_iflag &= NOTBITS(INPCK|ISTRIP);
572  switch( cParity )
573  {
574  case 'N':
575  tios.c_cflag &= NOTBITS(PARENB|PARODD);
576  break;
577  case 'E':
578  tios.c_cflag &= NOTBITS(PARODD);
579  tios.c_cflag |= (PARENB);
580  break;
581  case 'O':
582  tios.c_cflag |= (PARENB|PARODD);
583  break;
584  default:
585  LOGERROR("Invalid parity: %c", cParity);
586  errno = EINVAL;
587  return RC_ERROR;
588  }
589 
590  // set up xon/xoff software flow control
591  if( (attr = SERDEV_GET_ATTR(IXANY)) != SERDEV_NO_ATTR )
592  {
593  if( bXonXoff )
594  {
595  tios.c_iflag |= (IXON|IXOFF); // |IXANY)
596  }
597  else
598  {
599  tios.c_iflag &= NOTBITS(IXON|IXOFF|IXANY);
600  }
601  }
602  else
603  {
604  if( bXonXoff )
605  {
606  tios.c_iflag |= (IXON|IXOFF);
607  }
608  else
609  {
610  tios.c_iflag &= NOTBITS(IXON|IXOFF);
611  }
612  }
613 
614  // set up rts/cts hardware flow control
615  if( (attr = SERDEV_GET_ATTR(CRTSCTS)) != SERDEV_NO_ATTR )
616  {
617  if( bRtsCts )
618  {
619  tios.c_cflag |= (CRTSCTS);
620  }
621  else
622  {
623  tios.c_cflag &= NOTBITS(CRTSCTS);
624  }
625  }
626  // try it with alternate constant name
627  else if( (attr = SERDEV_GET_ATTR(CNEW_RTSCTS)) != SERDEV_NO_ATTR )
628  {
629  if( bRtsCts )
630  {
631  tios.c_cflag |= (attr);
632  }
633  else
634  {
635  tios.c_cflag &= NOTBITS(attr);
636  }
637  }
638  else
639  {
640  LOGDIAG4("Do not know how to set/clear RTS/CTS hardware flow control.");
641  }
642 
643  // set up read buffering for non-blocking (vmin, vtime are byte values)
644  // select() will handle timeouts.
645  tios.c_cc[VMIN] = 0; // vmin is minimum number of characters to be read.
646  tios.c_cc[VTIME] = 0; // vtime is read timout in deciseconds
647 
648  // activate the serial device settings
649  if( tcsetattr(fd, TCSANOW, &tios) == -1 )
650  {
651  LOGSYSERROR("tcseattr(%d,TCSANOW,...)", fd);
652  return RC_ERROR;
653  }
654 
655  return OK;
656 }
657 
658 
659 // ---------------------------------------------------------------------------
660 // Public Interface
661 // ---------------------------------------------------------------------------
662 
663 int SerDevOpen(const char *sSerDevName,
664  int nBaudRate,
665  int nByteSize,
666  int cParity,
667  int nStopBits,
668  bool_t bRtsCts,
669  bool_t bXonXoff)
670 {
671  int fd;
672 
673  LOGDIAG4CALL( _TSTR(sSerDevName),
674  _TINT(nBaudRate),
675  _TINT(nByteSize),
676  _TCHAR(cParity),
677  _TINT(nStopBits),
678  _TBOOL(bRtsCts),
679  _TBOOL(bXonXoff) );
680 
681  fd = open(sSerDevName, O_RDWR|O_NONBLOCK|O_NOCTTY);
682 
683  if( fd == -1 )
684  {
685  LOGSYSERROR("open(%s,...)", sSerDevName);
686  return RC_ERROR;
687  }
688 
689  else if( SerDevConfigure(fd, nBaudRate, nByteSize, cParity,
690  nStopBits, bRtsCts, bXonXoff) != OK )
691  {
692  LOGERROR("SerDevConfigure(): failed");
693  close(fd);
694  return RC_ERROR;
695  }
696 
697  else
698  {
699  LOGDIAG4("Serial device %s opened", sSerDevName);
700  return fd;
701  }
702 }
703 
704 int SerDevClose(int fd)
705 {
706  LOGDIAG4CALL(_TINT(fd));
707 
708  if( fd < 0 )
709  {
710  LOGERROR("Invalid serial device file descriptor: %d", fd);
711  errno = EBADF;
712  return RC_ERROR;
713  }
714  else
715  {
716  return close(fd);
717  }
718 }
719 
720 ssize_t SerDevReadLine(int fd,
721  char buffer[],
722  size_t count,
723  char *eol,
724  uint_t usec)
725 {
726  struct timeval tstart; // start of read line
727  uint_t tdelta; // read delta time
728  int c; // received character
729  ssize_t len = 0; // length of line sans eol sequence
730  bool_t bInEol = false; // [not] in end-of-line state
731  char *sSave = eol; // save eol pointer
732 
733  buffer[0] = 0;
734 
735  // must have an end-of-line termination sequence
736  if( (eol == NULL) || (*eol == 0) )
737  {
738  LOGERROR("No end-of-line sequence specified.");
739  return RC_ERROR;
740  }
741 
742  // start
743  timer_mark(&tstart);
744 
745  //
746  // Read until the end of the end-of-line sequence or an error has occurred.
747  //
748  while( len < count-1 )
749  {
750  // read character
751  c = SerDevGetc(fd, usec);
752 
753  // read error occurred
754  if( c < 0 )
755  {
756  buffer[len] = 0;
757  return RC_ERROR;
758  }
759 
760  // end-of-line sequence
761  else if( c == *eol )
762  {
763  // start of eol
764  if( !bInEol )
765  {
766  buffer[len] = 0;
767  bInEol = true;
768  }
769 
770  ++eol;
771 
772  // got a full line
773  if( *eol == 0 )
774  {
775  return len;
776  }
777  }
778 
779  // unexpected character in end-of-line sequence
780  else if( bInEol )
781  {
782  LOGWARN("Unexpected character '%c' found in end-of-line sequence \"%s\".",
783  c, sSave);
784  return len;
785  }
786 
787  // normal character
788  else
789  {
790  buffer[len++] = (char)c;
791  }
792 
793  // delta time
794  tdelta = timer_elapsed(&tstart);
795 
796  // timed out
797  if( (usec > 0) && (tdelta >= usec) )
798  {
799  LOGDIAG4("%s() timed out", LOGFUNCNAME);
800  buffer[len] = 0;
801  return RC_ERROR;
802  }
803  }
804 
805  buffer[len] = 0;
806 
807  LOGERROR("Line > %zu characters long.", count);
808 
809  return RC_ERROR;
810 }
811 
812 ssize_t SerDevWriteLine(int fd,
813  char *buffer,
814  char *eol,
815  uint_t usec)
816 {
817  size_t lenBuf, lenEol;
818  ssize_t m, n;
819 
820  // must have an end-of-line termination sequence
821  if( (eol == NULL) || (*eol == 0) )
822  {
823  LOGERROR("No end-of-line sequence specified.");
824  return RC_ERROR;
825  }
826 
827  lenBuf = strlen(buffer);
828  lenEol = strlen(eol);
829 
830  m = SerDevWrite(fd, (byte_t *)buffer, lenBuf, usec);
831  n = SerDevWrite(fd, (byte_t *)eol, lenEol, usec);
832 
833  if( (m == lenBuf) && (n == lenEol) )
834  {
835  return m;
836  }
837  else
838  {
839  return RC_ERROR;
840  }
841 }
842 
843 int SerDevGetc(int fd, uint_t usec)
844 {
845  byte_t byte;
846  fd_set rset;
847  struct timeval timeout;
848  int nFd;
849  ssize_t n;
850 
851  LOGDIAG4CALL(_TINT(fd), _TUINT(usec));
852 
853  FD_ZERO(&rset);
854  fdset_nowarn(fd, &rset);
855 
856  // wait for character with timeout
857  if( usec > 0 )
858  {
859  // load timeout
860  timeout.tv_sec = (time_t)(usec / 1000000);
861  timeout.tv_usec = (time_t)(usec % 1000000);
862 
863  nFd = select(fd+1, &rset, NULL, NULL, &timeout);
864  }
865 
866  // block indefinitely for character
867  else
868  {
869  nFd = select(fd+1, &rset, NULL, NULL, NULL);
870  }
871 
872  // system error occurred
873  if( nFd < 0 )
874  {
875  LOGSYSERROR("select(%d,...)", fd);
876  return RC_ERROR;
877  }
878 
879  // select() timeout occurred
880  else if( nFd == 0 )
881  {
882  LOGDIAG4("select() on read timed out");
883  errno = ETIMEDOUT;
884  return RC_ERROR;
885  }
886 
887  // data available from serial device, but error on read
888  else if( (n = read(fd, &byte, (size_t)1)) < 0 )
889  {
890  LOGSYSERROR("read(%d,...)", fd);
891  return RC_ERROR;
892  }
893 
894  // nothing read
895  else if( n == 0 )
896  {
897  LOGERROR("0=read(%d,...)", fd);
898  errno = EIO;
899  return RC_ERROR;
900  }
901 
902  // read character
903  else
904  {
905  LOGDIAG4("%s() byte=0x%02x read", LOGFUNCNAME, byte);
906  return (int)(((uint_t)(byte)) & 0x00ff);
907  }
908 }
909 
910 int SerDevPutc(int fd, byte_t byte, uint_t usec)
911 {
912  fd_set wset;
913  struct timeval timeout;
914  int nFd;
915  ssize_t n;
916 
917  LOGDIAG4CALL(_TINT(fd), _THEX(byte), _TUINT(usec));
918 
919  FD_ZERO(&wset);
920  fdset_nowarn(fd, &wset);
921 
922  // wait for output with timeout
923  if( usec > 0 )
924  {
925  // load timeout (gets munged after each select())
926  timeout.tv_sec = (time_t)(usec / 1000000);
927  timeout.tv_usec = (time_t)(usec % 1000000);
928 
929  nFd = select(fd+1, NULL, &wset, NULL, &timeout);
930  }
931 
932  // block indefinitely for output
933  else
934  {
935  nFd = select(fd+1, NULL, &wset, NULL, NULL);
936  }
937 
938  // system error occurred
939  if( nFd < 0 )
940  {
941  LOGSYSERROR("select(%d,...)", fd);
942  return RC_ERROR;
943  }
944 
945  // select() timeout occurred
946  else if( nFd == 0 )
947  {
948  LOGDIAG4("select() on write timed out");
949  errno = ETIMEDOUT;
950  return RC_ERROR;
951  }
952 
953  // data available from serial device (but error on write)
954  else if( (n = write(fd, &byte, (size_t)1)) < 0 )
955  {
956  LOGSYSERROR("write(%d,...)", fd);
957  return RC_ERROR;
958  }
959 
960  // nothing written
961  else if( n == 0 )
962  {
963  LOGERROR("0=write(%d,...)", fd);
964  errno = EIO;
965  return RC_ERROR;
966  }
967 
968  // character written
969  else
970  {
971  LOGDIAG4("%s() byte=0x%02x written", LOGFUNCNAME, byte);
972  return (int)(((uint_t)(byte)) & 0x00ff);
973  }
974 }
975 
976 ssize_t SerDevRead(int fd, byte_t *buffer, size_t count, uint_t usec)
977 {
978  bool_t bNonBlocking;
979  ssize_t nBytes = 0;
980  struct timeval tstart;
981  uint_t tdelta;
982  fd_set rset;
983  struct timeval timeout;
984  int nFd;
985  ssize_t n;
986 
987  LOGDIAG4CALL(_TINT(fd), _TPTR(buffer), _TUINT(count), _TUINT(usec));
988 
989  bNonBlocking = usec > 0? true: false;
990 
991  while( nBytes < count )
992  {
993  FD_ZERO(&rset);
994  fdset_nowarn(fd, &rset);
995 
996  // wait for input with timeout
997  if( bNonBlocking )
998  {
999  timer_mark(&tstart);
1000 
1001  // (re)load timeout (gets munged after each select())
1002  timeout.tv_sec = (time_t)(usec / 1000000);
1003  timeout.tv_usec = (time_t)(usec % 1000000);
1004 
1005  nFd = select(fd+1, &rset, NULL, NULL, &timeout);
1006  }
1007  // block indefinitely for input
1008  else
1009  {
1010  nFd = select(fd+1, &rset, NULL, NULL, NULL);
1011  }
1012 
1013  // system error occurred
1014  if( nFd < 0 )
1015  {
1016  LOGSYSERROR("select(%d,...)", fd);
1017  return (ssize_t)(RC_ERROR);
1018  }
1019 
1020  // select() timeout occurred
1021  else if( nFd == 0 )
1022  {
1023  LOGDIAG4("select() on read timed out");
1024  }
1025 
1026  // data available from serial device (but error on read)
1027  else if( (n = read(fd, buffer+nBytes, count-(size_t)nBytes)) < 0 )
1028  {
1029  LOGSYSERROR("read(%d,...)", fd);
1030  return (ssize_t)(RC_ERROR);
1031  }
1032 
1033  // read some data
1034  else
1035  {
1036  nBytes += n;
1037  }
1038 
1039  // determine time left for non-blocking read timeout
1040  if( (nBytes < count) && bNonBlocking )
1041  {
1042  tdelta = timer_elapsed(&tstart);
1043  if( tdelta >= usec )
1044  {
1045  LOGDIAG4("%s() timed out", LOGFUNCNAME);
1046  break;
1047  }
1048  else
1049  {
1050  usec -= tdelta;
1051  }
1052  }
1053  }
1054 
1055  LOGDIAG4("%s() %lu bytes read", LOGFUNCNAME, nBytes);
1056  SERDEVLOG(buffer, (size_t)nBytes, true);
1057 
1058  return nBytes;
1059 }
1060 
1061 ssize_t SerDevWrite(int fd, byte_t *buffer, size_t count, uint_t usec)
1062 {
1063  bool_t bNonBlocking;
1064  ssize_t nBytes = 0;
1065  struct timeval tstart;
1066  uint_t tdelta;
1067  fd_set wset;
1068  struct timeval timeout;
1069  int nFd;
1070  ssize_t n;
1071 
1072  LOGDIAG4CALL(_TINT(fd), _TPTR(buffer), _TUINT(count), _TUINT(usec));
1073 
1074  bNonBlocking = usec > 0? true: false;
1075 
1076  while( nBytes < count )
1077  {
1078  FD_ZERO(&wset);
1079  fdset_nowarn(fd, &wset);
1080 
1081  // wait for output with timeout
1082  if( bNonBlocking )
1083  {
1084  timer_mark(&tstart);
1085 
1086  // (re)load timeout (gets munged after each select())
1087  timeout.tv_sec = (time_t)(usec / 1000000);
1088  timeout.tv_usec = (time_t)(usec % 1000000);
1089 
1090  nFd = select(fd+1, NULL, &wset, NULL, &timeout);
1091  }
1092  // block indefinitely for output
1093  else
1094  {
1095  nFd = select(fd+1, NULL, &wset, NULL, NULL);
1096  }
1097 
1098  // system error occurred
1099  if( nFd < 0 )
1100  {
1101  LOGSYSERROR("select(%d,...)", fd);
1102  return (ssize_t)(RC_ERROR);
1103  }
1104 
1105  // select() timeout occurred
1106  else if( nFd == 0 )
1107  {
1108  LOGDIAG4("select() on write timed out");
1109  }
1110 
1111  // data available from serial device (but error on read)
1112  else if( (n = write(fd, buffer+nBytes, count-(size_t)nBytes)) < 0 )
1113  {
1114  LOGSYSERROR("write(%d,...)", fd);
1115  return (ssize_t)(RC_ERROR);
1116  }
1117 
1118  // written some data
1119  else
1120  {
1121  nBytes += n;
1122  }
1123 
1124  // determine time left for non-blocking read timeout
1125  if( (nBytes < count) && bNonBlocking )
1126  {
1127  tdelta = timer_elapsed(&tstart);
1128  if( tdelta >= usec )
1129  {
1130  LOGDIAG4("%s() timed out", LOGFUNCNAME);
1131  break;
1132  }
1133  else
1134  {
1135  usec -= tdelta;
1136  }
1137  }
1138  }
1139 
1140  LOGDIAG4("%s() %lu bytes written", LOGFUNCNAME, nBytes);
1141  SERDEVLOG(buffer, (size_t)nBytes, true);
1142 
1143  return nBytes;
1144 }
1145 
1146 ssize_t SerDevFIFOInputCount(int fd)
1147 {
1148  unsigned int nBytes = 0;
1149  int rc;
1150 
1151  rc = ioctl(fd, (unsigned long)SERDEV_FIONREAD, &nBytes);
1152  if( rc == -1 )
1153  {
1154  // not a tty, something is hosed
1155  if( errno != ENOTTY )
1156  {
1157  LOGSYSERROR("ioctl(%d,0x%x,...)", fd, SERDEV_FIONREAD);
1158  return (ssize_t)(RC_ERROR);
1159  }
1160  else
1161  {
1162  return (ssize_t)0;
1163  }
1164  }
1165  else
1166  {
1167  return (ssize_t)nBytes;
1168  }
1169 }
1170 
1171 #ifdef SERDEV_DEBUG
1172 ssize_t SerDevFIFOInputFlush(int fd)
1173 {
1174  byte_t b[256];
1175  ssize_t n;
1176  ssize_t nBytes = 0;
1177 
1178  LOGDIAG4CALL(_TINT(fd));
1179 
1180  //
1181  // Flush existing input characters by reading and logging the data in the
1182  // FIFO.
1183  //
1184  while( (n = SerDevFIFOInputCount(fd)) > 0 )
1185  {
1186  n = n < arraysize(b)? n: arraysize(b);
1187  n = SerDevRead(fd, b, (size_t)n, 500000);
1188  if( n > 0 )
1189  {
1190  SERDEVLOG(b, (size_t)n, false);
1191  nBytes += n;
1192  }
1193  }
1194  if( nBytes > 0 )
1195  {
1196  SERDEVLOGNL();
1197  }
1198 
1199  return nBytes;
1200 }
1201 #else
1202 ssize_t SerDevFIFOInputFlush(int fd)
1203 {
1204  ssize_t n;
1205 
1206  LOGDIAG4CALL(_TINT(fd));
1207 
1208  n = SerDevFIFOInputCount(fd);
1209 
1210  tcflush(fd, TCIFLUSH);
1211 
1212  return n;
1213 }
1214 #endif // SERDEV_DEBUG
1215 
1217 {
1218  LOGDIAG4CALL(_TINT(fd));
1219 
1220  tcflush(fd, TCOFLUSH);
1221 }
1222 
1224 {
1225  LOGDIAG4CALL(_TINT(fd));
1226 
1227  tcdrain(fd);
1228 }
1229 
1230 int SerDevSetBaudRate(int fd, int nBaudRate)
1231 {
1232  struct termios tios;
1233  speed_t ospeed, ispeed;
1234 
1235  LOGDIAG4CALL(_TINT(fd), _TINT(nBaudRate));
1236 
1237  // get the current device attributes
1238  if( tcgetattr(fd, &tios) == -1 )
1239  {
1240  LOGSYSERROR("tcgetattr(%d,...) failed", fd);
1241  return RC_ERROR;
1242  }
1243 
1244  // set up baudrate
1245  if((ospeed = SERDEV_GET_BAUDRATE(nBaudRate)) == SERDEV_NO_ATTR)
1246  {
1247  LOGERROR("Invalid/unsupported baud rate: %u", nBaudRate);
1248  errno = EINVAL;
1249  return RC_ERROR;
1250  }
1251  ispeed = ospeed;
1252  if( cfsetospeed(&tios, ospeed) == -1 ) // set output baudrate in structure
1253  {
1254  LOGSYSERROR("tcsetospeed(tios,%u)", ospeed);
1255  return RC_ERROR;
1256  }
1257  if( cfsetispeed(&tios, ispeed) == -1 ) // set input baudrate in structure
1258  {
1259  LOGSYSERROR("tcsetispeed(tios,%u)", ispeed);
1260  return RC_ERROR;
1261  }
1262 
1263  return OK;
1264 }
1265 
1266 int SerDevSetByteSize(int fd, int nByteSize)
1267 {
1268  struct termios tios;
1269 
1270  LOGDIAG4CALL(_TINT(fd), _TINT(nByteSize));
1271 
1272  // set up data character size (bits)
1273  tios.c_cflag &= NOTBITS(CSIZE);
1274  switch( nByteSize )
1275  {
1276  case 8:
1277  tios.c_cflag |= CS8;
1278  break;
1279  case 7:
1280  tios.c_cflag |= CS7;
1281  break;
1282  case 6:
1283  tios.c_cflag |= CS6;
1284  break;
1285  case 5:
1286  tios.c_cflag |= CS5;
1287  break;
1288  default:
1289  LOGERROR("Invalid data byte size: %u", nByteSize);
1290  errno = EINVAL;
1291  return RC_ERROR;
1292  }
1293 
1294  return OK;
1295 }
1296 
1297 int SerDevSetParity(int fd, int cParity)
1298 {
1299  struct termios tios;
1300 
1301  LOGDIAG4CALL(_TINT(fd), _TCHAR(cParity));
1302 
1303  // set up parity
1304  tios.c_iflag &= NOTBITS(INPCK|ISTRIP);
1305  switch( cParity )
1306  {
1307  case 'N':
1308  tios.c_cflag &= NOTBITS(PARENB|PARODD);
1309  break;
1310  case 'E':
1311  tios.c_cflag &= NOTBITS(PARODD);
1312  tios.c_cflag |= (PARENB);
1313  break;
1314  case 'O':
1315  tios.c_cflag |= (PARENB|PARODD);
1316  break;
1317  default:
1318  LOGERROR("Invalid parity: %c", cParity);
1319  errno = EINVAL;
1320  return RC_ERROR;
1321  }
1322 
1323  return OK;
1324 }
1325 
1326 int SerDevSetStopBits(int fd, int nStopBits)
1327 {
1328  struct termios tios;
1329 
1330  LOGDIAG4CALL(_TINT(fd), _TINT(nStopBits));
1331 
1332  // set up stopbits
1333  switch( nStopBits )
1334  {
1335  case 1:
1336  tios.c_cflag &= NOTBITS(CSTOPB);
1337  break;
1338  case 2:
1339  tios.c_cflag |= (CSTOPB);
1340  break;
1341  default:
1342  LOGERROR("Invalid number of stop bits: %u", nStopBits);
1343  errno = EINVAL;
1344  return RC_ERROR;
1345  }
1346 
1347  return OK;
1348 }
1349 
1350 int SerDevSetHwFlowControl(int fd, bool_t bRtsCts)
1351 {
1352  struct termios tios;
1353  unsigned int attr;
1354 
1355  LOGDIAG4CALL(_TINT(fd), _TBOOL(bRtsCts));
1356 
1357  // get the current device attributes
1358  if( tcgetattr(fd, &tios) == -1 )
1359  {
1360  LOGSYSERROR("tcgetattr(%d,...) failed", fd);
1361  return RC_ERROR;
1362  }
1363 
1364  // set up rts/cts hardware flow control
1365  if( (attr = SERDEV_GET_ATTR(CRTSCTS)) != SERDEV_NO_ATTR )
1366  {
1367  if( bRtsCts )
1368  {
1369  tios.c_cflag |= (CRTSCTS);
1370  }
1371  else
1372  {
1373  tios.c_cflag &= NOTBITS(CRTSCTS);
1374  }
1375  }
1376  // try it with alternate constant name
1377  else if( (attr = SERDEV_GET_ATTR(CNEW_RTSCTS)) != SERDEV_NO_ATTR )
1378  {
1379  if( bRtsCts )
1380  {
1381  tios.c_cflag |= (attr);
1382  }
1383  else
1384  {
1385  tios.c_cflag &= NOTBITS(attr);
1386  }
1387  }
1388  else
1389  {
1390  LOGDIAG4("Do not know how to set/clear RTS/CTS hardware flow control.");
1391  return RC_ERROR;
1392  }
1393 
1394  // flush data
1395  if( tcflush(fd, TCIOFLUSH) == -1 )
1396  {
1397  LOGSYSERROR("tcflush(%d,TCIOFLUSH)", fd);
1398  }
1399 
1400  // set hw flow control
1401  if( tcsetattr(fd, TCSANOW, &tios) == -1 )
1402  {
1403  LOGSYSERROR("tcseattr(%d,TCSANOW,...)", fd);
1404  return RC_ERROR;
1405  }
1406 
1407  return OK;
1408 }
1409 
1410 int SerDevSetSwFlowControl(int fd, bool_t bXonXoff)
1411 {
1412  struct termios tios;
1413  unsigned int attr;
1414 
1415  LOGDIAG4CALL(_TINT(fd), _TBOOL(bXonXoff));
1416 
1417  // get the current device attributes
1418  if( tcgetattr(fd, &tios) == -1 )
1419  {
1420  LOGSYSERROR("tcgetattr(%d,...) failed", fd);
1421  return RC_ERROR;
1422  }
1423 
1424  // set up xon/xoff software flow control
1425  if( (attr = SERDEV_GET_ATTR(IXANY)) != SERDEV_NO_ATTR )
1426  {
1427  if( bXonXoff )
1428  {
1429  tios.c_iflag |= (IXON|IXOFF); // |IXANY)
1430  }
1431  else
1432  {
1433  tios.c_iflag &= NOTBITS(IXON|IXOFF|IXANY);
1434  }
1435  }
1436  else
1437  {
1438  if( bXonXoff )
1439  {
1440  tios.c_iflag |= (IXON|IXOFF);
1441  }
1442  else
1443  {
1444  tios.c_iflag &= NOTBITS(IXON|IXOFF);
1445  }
1446  }
1447 
1448  // set sw flow control
1449  if( tcsetattr(fd, TCSANOW, &tios) == -1 )
1450  {
1451  LOGSYSERROR("tcseattr(%d,TCSANOW,...)", fd);
1452  return RC_ERROR;
1453  }
1454 
1455  return OK;
1456 }
1457 
1458 int SerDevAssertRTS(int fd)
1459 {
1460  int status;
1461 
1462  if( ioctl(fd, TIOCMGET, &status) == -1 )
1463  {
1464  LOGSYSERROR("ioctl(%d,TIOCMGET,...)", fd);
1465  return RC_ERROR;
1466  }
1467 
1468  status |= TIOCM_RTS;
1469 
1470  if( ioctl(fd, TIOCMSET, &status) == -1 )
1471  {
1472  LOGSYSERROR("ioctl(%d,TIOCMSET,0x%x)", fd, status);
1473  return RC_ERROR;
1474  }
1475 
1476  return OK;
1477 }
1478 
1480 {
1481  int status;
1482 
1483  if( ioctl(fd, TIOCMGET, &status) == -1 )
1484  {
1485  LOGSYSERROR("ioctl(%d,TIOCMGET,...)", fd);
1486  return RC_ERROR;
1487  }
1488 
1489  status &= ~TIOCM_RTS;
1490 
1491  if( ioctl(fd, TIOCMSET, &status) == -1 )
1492  {
1493  LOGSYSERROR("ioctl(%d,TIOCMSET,0x%x)", fd, status);
1494  return RC_ERROR;
1495  }
1496 
1497  return OK;
1498 }
1499 
1500 int SerDevAssertCTS(int fd)
1501 {
1502  int status;
1503 
1504  if( ioctl(fd, TIOCMGET, &status) == -1 )
1505  {
1506  LOGSYSERROR("ioctl(%d,TIOCMGET,...)", fd);
1507  return RC_ERROR;
1508  }
1509 
1510  status |= TIOCM_CTS;
1511 
1512  if( ioctl(fd, TIOCMSET, &status) == -1 )
1513  {
1514  LOGSYSERROR("ioctl(%d,TIOCMSET,0x%x)", fd, status);
1515  return RC_ERROR;
1516  }
1517 
1518  return OK;
1519 }
1520 
1522 {
1523  int status;
1524 
1525  if( ioctl(fd, TIOCMGET, &status) == -1 )
1526  {
1527  LOGSYSERROR("ioctl(%d,TIOCMGET,...)", fd);
1528  return RC_ERROR;
1529  }
1530 
1531  status &= ~TIOCM_CTS;
1532 
1533  if( ioctl(fd, TIOCMSET, &status) == -1 )
1534  {
1535  LOGSYSERROR("ioctl(%d,TIOCMSET,0x%x)", fd, status);
1536  return RC_ERROR;
1537  }
1538 
1539  return OK;
1540 }
1541 
1542 
1543 #if 0
1544 int SerDevAssertRTS(int fd)
1545 {
1546  int modem = TIOCM_RTS; // modem bits to set
1547 
1548  // set the indicated modem bits
1549  if( ioctl(fd, TIOCMBIS, &modem) == -1 )
1550  {
1551  LOGSYSERROR("ioctl(%d,TIOCMBIS,0x%x)", modem);
1552  return RC_ERROR;
1553  }
1554 
1555  return OK;
1556 }
1557 
1558 int SerDevDeassertRTS(int fd)
1559 {
1560  int modem = TIOCM_RTS; // modem bits to clear
1561 
1562  // clear the indicated modem bits
1563  if( ioctl(fd, TIOCMBIC, &modem) == -1 )
1564  {
1565  LOGSYSERROR("ioctl(%d,TIOCMBIC,0x%x)", modem);
1566  return RC_ERROR;
1567  }
1568 
1569  return OK;
1570 }
1571 
1572 int SerDevAssertCTS(int fd)
1573 {
1574  int modem = TIOCM_CTS; // modem bits to set
1575 
1576  // set the indicated modem bits
1577  if( ioctl(fd, TIOCMBIS, &modem) == -1 )
1578  {
1579  LOGSYSERROR("ioctl(%d,TIOCMBIS,0x%x)", modem);
1580  return RC_ERROR;
1581  }
1582 
1583  return OK;
1584 }
1585 
1586 int SerDevDeassertCTS(int fd)
1587 {
1588  int modem = TIOCM_CTS; // modem bits to clear
1589 
1590  // clear the indicated modem bits
1591  if( ioctl(fd, TIOCMBIC, &modem) == -1 )
1592  {
1593  LOGSYSERROR("ioctl(%d,TIOCMBIC,0x%x)", modem);
1594  return RC_ERROR;
1595  }
1596 
1597  return OK;
1598 }
1599 #endif
int SerDevSetParity(int fd, int cParity)
Set the parity.
Definition: serdev.c:1297
#define SERDEV_BAUDRATE_ENTRY(baudrate)
Serial device supported baudrate macros.
Definition: serdev.c:298
#define SERDEV_GET_ATTR(attr)
Get I/O defined attribute value.
Definition: serdev.c:249
#define SERDEV_GET_BAUDRATE(baudrate)
Get baudrate defined value.
Definition: serdev.c:305
#define SERDEV_NO_ATTR
Special "No Attribute" value.
Definition: serdev.c:228
static SerDevAttrKvp_T SerDevOptAttrTbl[]
SerDevOptAttr table. Dynamic method to determine serial device optional defined attributes for each p...
Definition: serdev.c:268
ssize_t SerDevFIFOInputCount(int fd)
Determine the number of bytes in the input FIFO of the serial device.
Definition: serdev.c:1146
int SerDevSetByteSize(int fd, int nByteSize)
Set the byte size.
Definition: serdev.c:1266
ssize_t SerDevWrite(int fd, byte_t *buffer, size_t count, uint_t usec)
Write to serial device.
Definition: serdev.c:1061
ssize_t SerDevWriteLine(int fd, char *buffer, char *eol, uint_t usec)
Write null-terminated ASCII character line to serial device.
Definition: serdev.c:812
unsigned int m_uVal
attribute value
Definition: serdev.c:236
int SerDevSetStopBits(int fd, int nStopBits)
Set the number of stop bits.
Definition: serdev.c:1326
#define SERDEV_ATTR_ENTRY(attr)
Serial device attribute macros.
Definition: serdev.c:243
int SerDevSetSwFlowControl(int fd, bool_t bXonXoff)
Set software flow control state.
Definition: serdev.c:1410
int SerDevAssertRTS(int fd)
Assert RTS (request to send).
Definition: serdev.c:1458
int SerDevDeassertCTS(int fd)
De-assert RTS (clear to send).
Definition: serdev.c:1521
int SerDevOpen(const char *sSerDevName, int nBaudRate, int nByteSize, int cParity, int nStopBits, bool_t bRtsCts, bool_t bXonXoff)
Open and configure serial device for communication.
Definition: serdev.c:663
void SerDevFIFOOutputDrain(int fd)
Transmit (drain) all data written to the output FIFO buffer.
Definition: serdev.c:1223
RS-232 serial device communication declarations and defines.
ssize_t SerDevReadLine(int fd, char buffer[], size_t count, char *eol, uint_t usec)
Read a ASCII character line from the serial device.
Definition: serdev.c:720
static void SerDevLogBytes(byte_t buffer[], size_t size, bool_t bNewLine)
Log read/written bytes to log stream.
Definition: serdev.c:138
static void fdset_nowarn(int fd, fd_set *pset)
FD_SET() wrapper with no annoying warnings.
Definition: serdev.c:94
#define SERDEV_FIONREAD
number in input queue
Definition: serdev.c:225
static int SerDevOptAttrCmp(const void *pKey1, const void *pKey2)
Serial option attribute comparator.
Definition: serdev.c:258
ssize_t SerDevRead(int fd, byte_t *buffer, size_t count, uint_t usec)
Read from the serial device.
Definition: serdev.c:976
int SerDevSetBaudRate(int fd, int nBaudRate)
Set the baudrate.
Definition: serdev.c:1230
#define SERDEVLOG(buffer, size, bNewLine)
Log read/written bytes to log stream.
Definition: serdev.c:113
static unsigned int SerDevAttrLookup(SerDevAttrKvp_T tbl[], size_t nTblEntries, const void *pKey, int(*cmp)(const void *, const void *))
Lookup the attribute value associated with the key.
Definition: serdev.c:433
void SerDevFIFOOutputFlush(int fd)
Flush output FIFO buffer, discarding all data in buffer.
Definition: serdev.c:1216
static int SerDevBaudRateCmp(const void *pKey1, const void *pKey2)
BaudRate attribute comparator.
Definition: serdev.c:314
static int SerDevConfigure(int fd, int nBaudRate, int nByteSize, int cParity, int nStopBits, bool_t bRtsCts, bool_t bXonXoff)
(Re)configure a serial device attibutes.
Definition: serdev.c:463
Serial Device Attribute Key - Value Pair structure.
Definition: serdev.c:233
static SerDevAttrKvp_T SerDevBaudRateTbl[]
SerDevBaudRate table. Dynamic method to determine Serial device supported baud rates for each plaform...
Definition: serdev.c:324
int SerDevClose(int fd)
Close serial device port.
Definition: serdev.c:704
int SerDevDeassertRTS(int fd)
De-assert RTS (request to send).
Definition: serdev.c:1479
#define SERDEVLOGNL()
Write newline character to log stream.
Definition: serdev.c:119
#define NOTBITS(bits)
Bitwise complement.
Definition: serdev.c:86
ssize_t SerDevFIFOInputFlush(int fd)
Flush the input FIFO buffer, discarding all data in buffer.
Definition: serdev.c:1202
int SerDevSetHwFlowControl(int fd, bool_t bRtsCts)
Set hardware flow control state.
Definition: serdev.c:1350
int SerDevPutc(int fd, byte_t byte, uint_t usec)
Put one character to serial device.
Definition: serdev.c:910
int SerDevAssertCTS(int fd)
Assert RTS (clear to send).
Definition: serdev.c:1500
static void timer_mark(struct timeval *pTvMark)
Mark the current time. Resolution is microseconds.
Definition: serdev.c:174
static uint_t timer_elapsed(struct timeval *pTvMark)
Calculate the elapsed time between the given time mark and this call.
Definition: serdev.c:192
int SerDevGetc(int fd, uint_t usec)
Get 1 character from the serial device.
Definition: serdev.c:843
void * m_pKey
attribute key
Definition: serdev.c:235