/[projects]/smsdaemon/serialport/SerialPort.cpp
ViewVC logotype

Contents of /smsdaemon/serialport/SerialPort.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 196 - (show annotations) (download)
Thu Dec 18 06:53:29 2008 UTC (15 years, 5 months ago) by torben
File size: 36876 byte(s)
Make pretty

astyle -t -b -N

1 /***************************************************************************
2 * Copyright (C) 2004 by Manish Pagey *
3 * crayzeewulf@users.sourceforge.net
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "SerialPort.h"
22 #include "PosixSignalDispatcher.h"
23 #include "PosixSignalHandler.h"
24 #include <queue>
25 #include <map>
26 #include <cerrno>
27 #include <cassert>
28 #include <termios.h>
29 #include <fcntl.h>
30 #include <sys/ioctl.h>
31 #include <sys/time.h>
32 #include <signal.h>
33 #include <strings.h>
34 #include <string.h>
35 #include <stdlib.h>
36
37 namespace
38 {
39 //
40 // Various error messages used in this file while throwing
41 // exceptions.
42 //
43 const std::string ERR_MSG_PORT_NOT_OPEN = "Serial port not open." ;
44 const std::string ERR_MSG_PORT_ALREADY_OPEN = "Serial port already open." ;
45 const std::string ERR_MSG_UNSUPPORTED_BAUD = "Unsupported baud rate." ;
46 const std::string ERR_MSG_UNKNOWN_BAUD = "Unknown baud rate." ;
47 const std::string ERR_MSG_INVALID_PARITY = "Invalid parity setting." ;
48 const std::string ERR_MSG_INVALID_STOP_BITS = "Invalid number of stop bits." ;
49 const std::string ERR_MSG_INVALID_FLOW_CONTROL = "Invalid flow control." ;
50
51 /*
52 * Return the difference between the two specified timeval values.
53 * This method subtracts secondOperand from firstOperand and returns
54 * the result as a timeval. The time represented by firstOperand must
55 * be later than the time represented by secondOperand. Otherwise,
56 * the result of this operator may be undefined.
57 */
58 const struct timeval
59 operator-( const struct timeval& firstOperand,
60 const struct timeval& secondOperand ) ;
61 } ;
62
63 class SerialPort::SerialPortImpl : public PosixSignalHandler
64 {
65 public:
66 /**
67 * Constructor.
68 */
69 SerialPortImpl( const std::string& serialPortName ) ;
70
71 /**
72 * Destructor.
73 */
74 ~SerialPortImpl() ;
75
76 /**
77 * Open the serial port.
78 */
79 void Open()
80 throw( SerialPort::OpenFailed,
81 SerialPort::AlreadyOpen ) ;
82
83 /**
84 * Check if the serial port is currently open.
85 */
86 bool
87 IsOpen() const ;
88
89 /**
90 * Close the serial port.
91 */
92 void
93 Close()
94 throw(SerialPort::NotOpen) ;
95
96 /**
97 * Set the baud rate of the serial port.
98 */
99 void
100 SetBaudRate( const SerialPort::BaudRate baudRate )
101 throw( SerialPort::NotOpen,
102 SerialPort::UnsupportedBaudRate,
103 std::invalid_argument,
104 std::runtime_error ) ;
105
106 /**
107 * Get the current baud rate.
108 */
109 SerialPort::BaudRate
110 GetBaudRate() const
111 throw( SerialPort::NotOpen,
112 std::runtime_error ) ;
113
114 /**
115 * Set the character size.
116 */
117 void
118 SetCharSize( const SerialPort::CharacterSize charSize )
119 throw( SerialPort::NotOpen,
120 std::invalid_argument,
121 std::runtime_error ) ;
122
123 /**
124 * Get the current character size.
125 */
126 SerialPort::CharacterSize
127 GetCharSize() const
128 throw( SerialPort::NotOpen,
129 std::runtime_error ) ;
130
131 void
132 SetParity( const SerialPort::Parity parityType )
133 throw( SerialPort::NotOpen,
134 std::invalid_argument,
135 std::runtime_error ) ;
136
137 SerialPort::Parity
138 GetParity() const
139 throw(SerialPort::NotOpen) ;
140
141 void
142 SetNumOfStopBits( const SerialPort::StopBits numOfStopBits )
143 throw( SerialPort::NotOpen,
144 std::invalid_argument ) ;
145
146 SerialPort::StopBits
147 GetNumOfStopBits() const
148 throw(SerialPort::NotOpen) ;
149
150 void
151 SetFlowControl( const SerialPort::FlowControl flowControl )
152 throw( SerialPort::NotOpen,
153 std::invalid_argument ) ;
154
155 SerialPort::FlowControl
156 GetFlowControl() const
157 throw( SerialPort::NotOpen ) ;
158
159 bool
160 IsDataAvailable() const
161 throw( SerialPort::NotOpen,
162 std::runtime_error ) ;
163
164 unsigned char
165 ReadByte(const unsigned int msTimeout = 0 )
166 throw( SerialPort::NotOpen,
167 SerialPort::ReadTimeout,
168 std::runtime_error ) ;
169
170 void
171 Read( SerialPort::DataBuffer& dataBuffer,
172 const unsigned int numOfBytes,
173 const unsigned int msTimeout )
174 throw( SerialPort::NotOpen,
175 SerialPort::ReadTimeout,
176 std::runtime_error ) ;
177
178 const std::string
179 ReadLine( const unsigned int msTimeout = 0,
180 const char lineTerminator = '\n' )
181 throw( SerialPort::NotOpen,
182 SerialPort::ReadTimeout,
183 std::runtime_error ) ;
184
185 void
186 WriteByte( const unsigned char dataByte )
187 throw( SerialPort::NotOpen,
188 std::runtime_error ) ;
189
190 void
191 Write(const SerialPort::DataBuffer& dataBuffer)
192 throw( SerialPort::NotOpen,
193 std::runtime_error ) ;
194
195 void
196 Write( const unsigned char* dataBuffer,
197 const unsigned int bufferSize )
198 throw( SerialPort::NotOpen,
199 std::runtime_error ) ;
200
201 void
202 SetDtr( const bool dtrState )
203 throw( SerialPort::NotOpen,
204 std::runtime_error ) ;
205
206 bool
207 GetDtr() const
208 throw( SerialPort::NotOpen,
209 std::runtime_error ) ;
210
211 void
212 SetRts( const bool rtsState )
213 throw( SerialPort::NotOpen,
214 std::runtime_error ) ;
215
216 bool
217 GetRts() const
218 throw( SerialPort::NotOpen,
219 std::runtime_error ) ;
220
221 bool
222 GetCts() const
223 throw( SerialPort::NotOpen,
224 std::runtime_error ) ;
225
226
227 bool
228 GetDsr() const
229 throw( SerialPort::NotOpen,
230 std::runtime_error ) ;
231 /*
232 * This method must be defined by all subclasses of
233 * PosixSignalHandler.
234 */
235 void
236 HandlePosixSignal(int signalNumber) ;
237 private:
238 /**
239 * Name of the serial port. On POSIX systems this is the name of
240 * the device file.
241 */
242 std::string mSerialPortName ;
243
244 /**
245 * Flag that indicates whether the serial port is currently open.
246 */
247 bool mIsOpen ;
248
249 /**
250 * The file descriptor corresponding to the serial port.
251 */
252 int mFileDescriptor ;
253
254 /**
255 * Serial port settings are saved into this variable immediately
256 * after the port is opened. These settings are restored when the
257 * serial port is closed.
258 */
259 termios mOldPortSettings ;
260
261 /**
262 * Circular buffer used to store the received data. This is done
263 * asynchronously and helps prevent overflow of the corresponding
264 * tty's input buffer.
265 *
266 * :TODO: The size of this buffer is allowed to increase indefinitely. If
267 * data keeps arriving at the serial port and is never read then this
268 * buffer will continue occupying more and more memory. We need to put a
269 * cap on the size of this buffer. It might even be worth providing a
270 * method to set the size of this buffer.
271 */
272 std::queue<unsigned char> mInputBuffer ;
273
274 /**
275 * Set the specified modem control line to the specified value.
276 *
277 * @param modemLine One of the following four values: TIOCM_DTR,
278 * TIOCM_RTS, TIOCM_CTS, or TIOCM_DSR.
279 *
280 * @param lineState State of the modem line after successful
281 * call to this method.
282 */
283 void
284 SetModemControlLine( const int modemLine,
285 const bool lineState )
286 throw( SerialPort::NotOpen,
287 std::runtime_error ) ;
288
289 /**
290 * Get the current state of the specified modem control line.
291 *
292 * @param modemLine One of the following four values: TIOCM_DTR,
293 * TIOCM_RTS, TIOCM_CTS, or TIOCM_DSR.
294 *
295 * @return True if the specified line is currently set and false
296 * otherwise.
297 */
298 bool
299 GetModemControlLine( const int modemLine ) const
300 throw( SerialPort::NotOpen,
301 std::runtime_error ) ;
302 } ;
303
304 SerialPort::SerialPort( const std::string& serialPortName ) :
305 mSerialPortImpl(new SerialPortImpl(serialPortName) )
306 {
307 /* empty */
308 }
309
310 SerialPort::~SerialPort()
311 throw()
312 {
313 /*
314 * Close the serial port if it is open.
315 */
316 if ( this->IsOpen() )
317 {
318 this->Close() ;
319 }
320 /*
321 * Free the memory allocated to the implementation instance.
322 */
323 if ( mSerialPortImpl )
324 {
325 delete mSerialPortImpl ;
326 }
327 return ;
328 }
329
330 void
331 SerialPort::Open( const BaudRate baudRate,
332 const CharacterSize charSize,
333 const Parity parityType,
334 const StopBits stopBits,
335 const FlowControl flowControl )
336 throw( OpenFailed,
337 AlreadyOpen,
338 UnsupportedBaudRate,
339 std::invalid_argument )
340 {
341 //
342 // Open the serial port.
343 mSerialPortImpl->Open() ;
344 //
345 // Set the various parameters of the serial port if it is open.
346 //
347 this->SetBaudRate(baudRate) ;
348 this->SetCharSize(charSize) ;
349 this->SetParity(parityType) ;
350 this->SetNumOfStopBits(stopBits) ;
351 this->SetFlowControl(flowControl) ;
352 //
353 // All done.
354 //
355 return ;
356 }
357
358 bool
359 SerialPort::IsOpen() const
360 {
361 return mSerialPortImpl->IsOpen() ;
362 }
363
364 void
365 SerialPort::Close()
366 throw(NotOpen)
367 {
368 mSerialPortImpl->Close() ;
369 return ;
370 }
371
372 void
373 SerialPort::SetBaudRate( const BaudRate baudRate )
374 throw( UnsupportedBaudRate,
375 NotOpen,
376 std::invalid_argument )
377 {
378 mSerialPortImpl->SetBaudRate( baudRate ) ;
379 return ;
380 }
381
382 SerialPort::BaudRate
383 SerialPort::GetBaudRate() const
384 throw( NotOpen,
385 std::runtime_error )
386 {
387 return mSerialPortImpl->GetBaudRate() ;
388 }
389
390
391 void
392 SerialPort::SetCharSize( const CharacterSize charSize )
393 throw( NotOpen,
394 std::invalid_argument )
395 {
396 mSerialPortImpl->SetCharSize(charSize) ;
397 }
398
399 SerialPort::CharacterSize
400 SerialPort::GetCharSize() const
401 throw(NotOpen)
402 {
403 return mSerialPortImpl->GetCharSize() ;
404 }
405
406 void
407 SerialPort::SetParity( const Parity parityType )
408 throw( NotOpen,
409 std::invalid_argument )
410 {
411 mSerialPortImpl->SetParity( parityType ) ;
412 return ;
413 }
414
415 SerialPort::Parity
416 SerialPort::GetParity() const
417 throw(NotOpen)
418 {
419 return mSerialPortImpl->GetParity() ;
420 }
421
422 void
423 SerialPort::SetNumOfStopBits( const StopBits numOfStopBits )
424 throw( NotOpen,
425 std::invalid_argument )
426 {
427 mSerialPortImpl->SetNumOfStopBits(numOfStopBits) ;
428 return ;
429 }
430
431 SerialPort::StopBits
432 SerialPort::GetNumOfStopBits() const
433 throw(NotOpen)
434 {
435 return mSerialPortImpl->GetNumOfStopBits() ;
436 }
437
438
439 void
440 SerialPort::SetFlowControl( const FlowControl flowControl )
441 throw( NotOpen,
442 std::invalid_argument )
443 {
444 mSerialPortImpl->SetFlowControl( flowControl ) ;
445 return ;
446 }
447
448 SerialPort::FlowControl
449 SerialPort::GetFlowControl() const
450 throw( NotOpen )
451 {
452 return mSerialPortImpl->GetFlowControl() ;
453 }
454
455 bool
456 SerialPort::IsDataAvailable() const
457 throw(NotOpen)
458 {
459 return mSerialPortImpl->IsDataAvailable() ;
460 }
461
462 unsigned char
463 SerialPort::ReadByte( const unsigned int msTimeout )
464 throw( NotOpen,
465 ReadTimeout,
466 std::runtime_error )
467 {
468 return mSerialPortImpl->ReadByte(msTimeout) ;
469 }
470
471 void
472 SerialPort::Read( SerialPort::DataBuffer& dataBuffer,
473 const unsigned int numOfBytes,
474 const unsigned int msTimeout )
475 throw( NotOpen,
476 ReadTimeout,
477 std::runtime_error )
478 {
479 return mSerialPortImpl->Read( dataBuffer,
480 numOfBytes,
481 msTimeout ) ;
482 }
483
484
485 const std::string
486 SerialPort::ReadLine( const unsigned int msTimeout,
487 const char lineTerminator )
488 throw( NotOpen,
489 ReadTimeout,
490 std::runtime_error )
491 {
492 return mSerialPortImpl->ReadLine( msTimeout,
493 lineTerminator ) ;
494 }
495
496
497 void
498 SerialPort::WriteByte( const unsigned char dataByte )
499 throw( SerialPort::NotOpen,
500 std::runtime_error )
501 {
502 mSerialPortImpl->WriteByte( dataByte ) ;
503 return ;
504 }
505
506
507 void
508 SerialPort::Write(const DataBuffer& dataBuffer)
509 throw( NotOpen,
510 std::runtime_error )
511 {
512 mSerialPortImpl->Write( dataBuffer ) ;
513 return ;
514 }
515
516 void
517 SerialPort::Write(const std::string& dataString)
518 throw( NotOpen,
519 std::runtime_error )
520 {
521 mSerialPortImpl->Write( reinterpret_cast<const unsigned char*>(dataString.c_str()),
522 dataString.length() ) ;
523 return ;
524 }
525
526 void
527 SerialPort::SetDtr( const bool dtrState )
528 throw( SerialPort::NotOpen,
529 std::runtime_error )
530 {
531 mSerialPortImpl->SetDtr( dtrState ) ;
532 return ;
533 }
534
535 bool
536 SerialPort::GetDtr() const
537 throw( SerialPort::NotOpen,
538 std::runtime_error )
539 {
540 return mSerialPortImpl->GetDtr() ;
541 }
542
543 void
544 SerialPort::SetRts( const bool rtsState )
545 throw( SerialPort::NotOpen,
546 std::runtime_error )
547 {
548 mSerialPortImpl->SetRts( rtsState ) ;
549 return ;
550 }
551
552 bool
553 SerialPort::GetRts() const
554 throw( SerialPort::NotOpen,
555 std::runtime_error )
556 {
557 return mSerialPortImpl->GetRts() ;
558 }
559
560
561 bool
562 SerialPort::GetCts() const
563 throw( SerialPort::NotOpen,
564 std::runtime_error )
565 {
566 return mSerialPortImpl->GetCts() ;
567 }
568
569 bool
570 SerialPort::GetDsr() const
571 throw( SerialPort::NotOpen,
572 std::runtime_error )
573 {
574 return mSerialPortImpl->GetDsr() ;
575 }
576
577 /* ------------------------------------------------------------ */
578 inline
579 SerialPort::SerialPortImpl::SerialPortImpl( const std::string& serialPortName ) :
580 mSerialPortName(serialPortName),
581 mIsOpen(false),
582 mFileDescriptor(-1),
583 mOldPortSettings(),
584 mInputBuffer()
585 {
586 /* empty */
587 }
588
589 inline
590 SerialPort::SerialPortImpl::~SerialPortImpl()
591 {
592 //
593 // Close the serial port if it is open.
594 //
595 if ( this->IsOpen() )
596 {
597 this->Close() ;
598 }
599 return ;
600 }
601
602 inline
603 void
604 SerialPort::SerialPortImpl::Open()
605 throw( SerialPort::OpenFailed,
606 SerialPort::AlreadyOpen )
607 {
608 /*
609 * Throw an exception if the port is already open.
610 */
611 if ( this->IsOpen() )
612 {
613 throw SerialPort::AlreadyOpen( ERR_MSG_PORT_ALREADY_OPEN ) ;
614 }
615 /*
616 * Try to open the serial port and throw an exception if we are
617 * not able to open it.
618 *
619 * :FIXME: Exception thrown by this method after opening the
620 * serial port might leave the port open even though mIsOpen
621 * is false. We need to close the port before throwing an
622 * exception or close it next time this method is called before
623 * calling open() again.
624 */
625 mFileDescriptor = open( mSerialPortName.c_str(),
626 O_RDWR | O_NOCTTY | O_NONBLOCK ) ;
627 if ( mFileDescriptor < 0 )
628 {
629 throw SerialPort::OpenFailed( strerror(errno) ) ;
630 }
631
632
633 PosixSignalDispatcher& signal_dispatcher = PosixSignalDispatcher::Instance() ;
634 signal_dispatcher.AttachHandler( SIGIO,
635 *this ) ;
636
637 /*
638 * Direct all SIGIO and SIGURG signals for the port to the current
639 * process.
640 */
641 if ( fcntl( mFileDescriptor,
642 F_SETOWN,
643 getpid() ) < 0 )
644 {
645 throw SerialPort::OpenFailed( strerror(errno) ) ;
646 }
647
648 /*
649 * Enable asynchronous I/O with the serial port.
650 */
651 if ( fcntl( mFileDescriptor,
652 F_SETFL,
653 FASYNC ) < 0 )
654 {
655 throw SerialPort::OpenFailed( strerror(errno) ) ;
656 }
657
658 /*
659 * Save the current settings of the serial port so they can be
660 * restored when the serial port is closed.
661 */
662 if ( tcgetattr( mFileDescriptor,
663 &mOldPortSettings ) < 0 )
664 {
665 throw SerialPort::OpenFailed( strerror(errno) ) ;
666 }
667
668 //
669 // Start assembling the new port settings.
670 //
671 termios port_settings ;
672 bzero( &port_settings,
673 sizeof( port_settings ) ) ;
674
675 //
676 // Enable the receiver (CREAD) and ignore modem control lines
677 // (CLOCAL).
678 //
679 port_settings.c_cflag |= CREAD | CLOCAL ;
680
681 //
682 // Set the VMIN and VTIME parameters to zero by default. VMIN is
683 // the minimum number of characters for non-canonical read and
684 // VTIME is the timeout in deciseconds for non-canonical
685 // read. Setting both of these parameters to zero implies that a
686 // read will return immediately only giving the currently
687 // available characters.
688 //
689 port_settings.c_cc[ VMIN ] = 0 ;
690 port_settings.c_cc[ VTIME ] = 0 ;
691 /*
692 * Flush the input buffer associated with the port.
693 */
694 if ( tcflush( mFileDescriptor,
695 TCIFLUSH ) < 0 )
696 {
697 throw SerialPort::OpenFailed( strerror(errno) ) ;
698 }
699 /*
700 * Write the new settings to the port.
701 */
702 if ( tcsetattr( mFileDescriptor,
703 TCSANOW,
704 &port_settings ) < 0 )
705 {
706 throw SerialPort::OpenFailed( strerror(errno) ) ;
707 }
708
709 /*
710 * The serial port is open at this point.
711 */
712 mIsOpen = true ;
713 return ;
714 }
715
716 inline
717 bool
718 SerialPort::SerialPortImpl::IsOpen() const
719 {
720 return mIsOpen ;
721 }
722
723 inline
724 void
725 SerialPort::SerialPortImpl::Close()
726 throw( SerialPort::NotOpen )
727 {
728 //
729 // Throw an exception if the serial port is not open.
730 //
731 if ( ! this->IsOpen() )
732 {
733 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
734 }
735 //
736 PosixSignalDispatcher& signal_dispatcher = PosixSignalDispatcher::Instance() ;
737 signal_dispatcher.DetachHandler( SIGIO,
738 *this ) ;
739 //
740 // Restore the old settings of the port.
741 //
742 tcsetattr( mFileDescriptor,
743 TCSANOW,
744 &mOldPortSettings ) ;
745 //
746 // Close the serial port file descriptor.
747 //
748 close(mFileDescriptor) ;
749 //
750 // The port is not open anymore.
751 //
752 mIsOpen = false ;
753 //
754 return ;
755 }
756
757 inline
758 void
759 SerialPort::SerialPortImpl::SetBaudRate( const SerialPort::BaudRate baudRate )
760 throw( SerialPort::NotOpen,
761 SerialPort::UnsupportedBaudRate,
762 std::invalid_argument,
763 std::runtime_error )
764 {
765 //
766 // Throw an exception if the serial port is not open.
767 //
768 if ( ! this->IsOpen() )
769 {
770 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
771 }
772 //
773 // Get the current settings of the serial port.
774 //
775 termios port_settings ;
776 if ( tcgetattr( mFileDescriptor,
777 &port_settings ) < 0 )
778 {
779 throw std::runtime_error( strerror(errno) ) ;
780 }
781 //
782 // Set the baud rate for both input and output.
783 //
784 if ( ( cfsetispeed( &port_settings,
785 baudRate ) < 0 ) ||
786 ( cfsetospeed( &port_settings,
787 baudRate ) < 0 ) )
788 {
789 //
790 // If any of the settings fail, we abandon this method.
791 //
792 throw SerialPort::UnsupportedBaudRate( ERR_MSG_UNSUPPORTED_BAUD ) ;
793 }
794 //
795 // Set the new attributes of the serial port.
796 //
797 if ( tcsetattr( mFileDescriptor,
798 TCSANOW,
799 &port_settings ) < 0 )
800 {
801 throw SerialPort::UnsupportedBaudRate( strerror(errno) ) ;
802 }
803 return ;
804 }
805
806 inline
807 SerialPort::BaudRate
808 SerialPort::SerialPortImpl::GetBaudRate() const
809 throw( SerialPort::NotOpen,
810 std::runtime_error )
811 {
812 //
813 // Make sure that the serial port is open.
814 //
815 if ( ! this->IsOpen() )
816 {
817 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
818 }
819 //
820 // Read the current serial port settings.
821 //
822 termios port_settings ;
823 if ( tcgetattr( mFileDescriptor,
824 &port_settings ) < 0 )
825 {
826 throw std::runtime_error( strerror(errno) ) ;
827 }
828 //
829 // Obtain the input baud rate from the current settings.
830 //
831 return SerialPort::BaudRate(cfgetispeed( &port_settings )) ;
832 }
833
834 inline
835 void
836 SerialPort::SerialPortImpl::SetCharSize( const SerialPort::CharacterSize charSize )
837 throw( SerialPort::NotOpen,
838 std::invalid_argument,
839 std::runtime_error )
840 {
841 //
842 // Make sure that the serial port is open.
843 //
844 if ( ! this->IsOpen() )
845 {
846 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
847 }
848 //
849 // Get the current settings of the serial port.
850 //
851 termios port_settings ;
852 if ( tcgetattr( mFileDescriptor,
853 &port_settings ) < 0 )
854 {
855 throw std::runtime_error( strerror(errno) ) ;
856 }
857 //
858 // Set the character size.
859 //
860 port_settings.c_cflag &= ~CSIZE ;
861 port_settings.c_cflag |= charSize ;
862 //
863 // Apply the modified settings.
864 //
865 if ( tcsetattr( mFileDescriptor,
866 TCSANOW,
867 &port_settings ) < 0 )
868 {
869 throw std::invalid_argument( strerror(errno) ) ;
870 }
871 return ;
872 }
873
874 inline
875 SerialPort::CharacterSize
876 SerialPort::SerialPortImpl::GetCharSize() const
877 throw( SerialPort::NotOpen,
878 std::runtime_error )
879 {
880 //
881 // Make sure that the serial port is open.
882 //
883 if ( ! this->IsOpen() )
884 {
885 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
886 }
887 //
888 // Get the current port settings.
889 //
890 termios port_settings ;
891 if ( tcgetattr( mFileDescriptor,
892 &port_settings ) < 0 )
893 {
894 throw std::runtime_error( strerror(errno) ) ;
895 }
896 //
897 // Read the character size from the setttings.
898 //
899 return SerialPort::CharacterSize( port_settings.c_cflag & CSIZE ) ;
900 }
901
902 inline
903 void
904 SerialPort::SerialPortImpl::SetParity( const SerialPort::Parity parityType )
905 throw( SerialPort::NotOpen,
906 std::invalid_argument,
907 std::runtime_error )
908 {
909 //
910 // Make sure that the serial port is open.
911 //
912 if ( ! this->IsOpen() )
913 {
914 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
915 }
916 //
917 // Get the current port settings.
918 //
919 termios port_settings ;
920 if ( tcgetattr( mFileDescriptor,
921 &port_settings ) < 0 )
922 {
923 throw std::runtime_error( strerror(errno) ) ;
924 }
925 //
926 // Set the parity type depending on the specified parameter.
927 //
928 switch ( parityType )
929 {
930 case SerialPort::PARITY_EVEN:
931 port_settings.c_cflag |= PARENB ;
932 port_settings.c_cflag &= ~PARODD ;
933 port_settings.c_iflag |= INPCK ;
934 break ;
935 case SerialPort::PARITY_ODD:
936 port_settings.c_cflag |= ( PARENB | PARODD ) ;
937 port_settings.c_iflag |= INPCK ;
938 break ;
939 case SerialPort::PARITY_NONE:
940 port_settings.c_cflag &= ~(PARENB) ;
941 port_settings.c_iflag |= IGNPAR ;
942 break ;
943 default:
944 throw std::invalid_argument( ERR_MSG_INVALID_PARITY ) ;
945 break ;
946 }
947 //
948 // Apply the modified port settings.
949 //
950 if ( tcsetattr( mFileDescriptor,
951 TCSANOW,
952 &port_settings ) < 0 )
953 {
954 throw std::invalid_argument( strerror(errno) ) ;
955 }
956 return ;
957 }
958
959 inline
960 SerialPort::Parity
961 SerialPort::SerialPortImpl::GetParity() const
962 throw(SerialPort::NotOpen)
963 {
964 //
965 // Make sure that the serial port is open.
966 //
967 if ( ! this->IsOpen() )
968 {
969 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
970 }
971 //
972 // Get the current port settings.
973 //
974 termios port_settings ;
975 if ( tcgetattr( mFileDescriptor,
976 &port_settings ) < 0 )
977 {
978 throw std::runtime_error( strerror(errno) ) ;
979 }
980 //
981 // Get the parity type from the current settings.
982 //
983 if ( port_settings.c_cflag & PARENB )
984 {
985 //
986 // Parity is enabled. Lets check if it is odd or even.
987 //
988 if ( port_settings.c_cflag & PARODD )
989 {
990 return SerialPort::PARITY_ODD ;
991 }
992 else
993 {
994 return SerialPort::PARITY_EVEN ;
995 }
996 }
997 //
998 // Parity is disabled.
999 //
1000 return SerialPort::PARITY_NONE ;
1001 }
1002
1003 inline
1004 void
1005 SerialPort::SerialPortImpl::SetNumOfStopBits( const SerialPort::StopBits numOfStopBits )
1006 throw( SerialPort::NotOpen,
1007 std::invalid_argument )
1008 {
1009 //
1010 // Make sure that the serial port is open.
1011 //
1012 if ( ! this->IsOpen() )
1013 {
1014 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1015 }
1016 //
1017 // Get the current port settings.
1018 //
1019 termios port_settings ;
1020 if ( tcgetattr( mFileDescriptor,
1021 &port_settings ) < 0 )
1022 {
1023 throw std::runtime_error( strerror(errno) ) ;
1024 }
1025 //
1026 // Set the number of stop bits.
1027 //
1028 switch ( numOfStopBits )
1029 {
1030 case SerialPort::STOP_BITS_1:
1031 port_settings.c_cflag &= ~(CSTOPB) ;
1032 break ;
1033 case SerialPort::STOP_BITS_2:
1034 port_settings.c_cflag |= CSTOPB ;
1035 break ;
1036 default:
1037 throw std::invalid_argument( ERR_MSG_INVALID_STOP_BITS ) ;
1038 break ;
1039 }
1040 //
1041 // Apply the modified settings.
1042 //
1043 if ( tcsetattr( mFileDescriptor,
1044 TCSANOW,
1045 &port_settings ) < 0 )
1046 {
1047 throw std::invalid_argument( strerror(errno) ) ;
1048 }
1049 return ;
1050 }
1051
1052 inline
1053 SerialPort::StopBits
1054 SerialPort::SerialPortImpl::GetNumOfStopBits() const
1055 throw(SerialPort::NotOpen)
1056 {
1057 //
1058 // Make sure that the serial port is open.
1059 //
1060 if ( ! this->IsOpen() )
1061 {
1062 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1063 }
1064 //
1065 // Get the current port settings.
1066 //
1067 termios port_settings ;
1068 if ( tcgetattr( mFileDescriptor,
1069 &port_settings ) < 0 )
1070 {
1071 throw std::runtime_error( strerror(errno) ) ;
1072 }
1073 //
1074 // If CSTOPB is set then we are using two stop bits, otherwise we
1075 // are using 1 stop bit.
1076 //
1077 if ( port_settings.c_cflag & CSTOPB )
1078 {
1079 return SerialPort::STOP_BITS_2 ;
1080 }
1081 return SerialPort::STOP_BITS_1 ;
1082 }
1083
1084 inline
1085 void
1086 SerialPort::SerialPortImpl::SetFlowControl( const SerialPort::FlowControl flowControl )
1087 throw( SerialPort::NotOpen,
1088 std::invalid_argument )
1089 {
1090 //
1091 // Make sure that the serial port is open.
1092 //
1093 if ( ! this->IsOpen() )
1094 {
1095 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1096 }
1097 //
1098 // Get the current port settings.
1099 //
1100 termios port_settings ;
1101 if ( tcgetattr( mFileDescriptor,
1102 &port_settings ) < 0 )
1103 {
1104 throw std::runtime_error( strerror(errno) ) ;
1105 }
1106 //
1107 // Set the flow control.
1108 //
1109 switch ( flowControl )
1110 {
1111 case SerialPort::FLOW_CONTROL_HARD:
1112 port_settings.c_cflag |= CRTSCTS ;
1113 break ;
1114 case SerialPort::FLOW_CONTROL_NONE:
1115 port_settings.c_cflag &= ~(CRTSCTS) ;
1116 break ;
1117 default:
1118 throw std::invalid_argument( ERR_MSG_INVALID_FLOW_CONTROL ) ;
1119 break ;
1120 }
1121 //
1122 // Apply the modified settings.
1123 //
1124 if ( tcsetattr( mFileDescriptor,
1125 TCSANOW,
1126 &port_settings ) < 0 )
1127 {
1128 throw std::invalid_argument( strerror(errno) ) ;
1129 }
1130 return ;
1131 }
1132
1133 inline
1134 SerialPort::FlowControl
1135 SerialPort::SerialPortImpl::GetFlowControl() const
1136 throw( SerialPort::NotOpen )
1137 {
1138 //
1139 // Make sure that the serial port is open.
1140 //
1141 if ( ! this->IsOpen() )
1142 {
1143 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1144 }
1145 //
1146 // Get the current port settings.
1147 //
1148 termios port_settings ;
1149 if ( tcgetattr( mFileDescriptor,
1150 &port_settings ) < 0 )
1151 {
1152 throw std::runtime_error( strerror(errno) ) ;
1153 }
1154 //
1155 // If CRTSCTS is set then we are using hardware flow
1156 // control. Otherwise, we are not using any flow control.
1157 //
1158 if ( port_settings.c_cflag & CRTSCTS )
1159 {
1160 return SerialPort::FLOW_CONTROL_HARD ;
1161 }
1162 return SerialPort::FLOW_CONTROL_NONE ;
1163 }
1164
1165 inline
1166 bool
1167 SerialPort::SerialPortImpl::IsDataAvailable() const
1168 throw( SerialPort::NotOpen,
1169 std::runtime_error )
1170 {
1171 //
1172 // Make sure that the serial port is open.
1173 //
1174 if ( ! this->IsOpen() )
1175 {
1176 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1177 }
1178 //
1179 // Check if any data is available in the input buffer.
1180 //
1181 return ( mInputBuffer.size() > 0 ? true : false ) ;
1182 }
1183
1184 inline
1185 unsigned char
1186 SerialPort::SerialPortImpl::ReadByte(const unsigned int msTimeout)
1187 throw( SerialPort::NotOpen,
1188 SerialPort::ReadTimeout,
1189 std::runtime_error )
1190 {
1191 //
1192 // Make sure that the serial port is open.
1193 //
1194 if ( ! this->IsOpen() )
1195 {
1196 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1197 }
1198 //
1199 // Get the current time. Throw an exception if we are unable
1200 // to read the current time.
1201 //
1202 struct timeval entry_time ;
1203 if ( gettimeofday( &entry_time,
1204 NULL ) < 0 )
1205 {
1206 throw std::runtime_error( strerror(errno) ) ;
1207 }
1208 //
1209 // Wait for data to be available.
1210 //
1211 const int MICROSECONDS_PER_MS = 1000 ;
1212 const int MILLISECONDS_PER_SEC = 1000 ;
1213 //
1214 while ( 0 == mInputBuffer.size() )
1215 {
1216 //
1217 // Read the current time.
1218 //
1219 struct timeval curr_time ;
1220 if ( gettimeofday( &curr_time,
1221 NULL ) < 0 )
1222 {
1223 throw std::runtime_error( strerror(errno) ) ;
1224 }
1225 //
1226 // Obtain the elapsed time.
1227 //
1228 struct timeval elapsed_time = curr_time - entry_time ;
1229 //
1230 // Increase the elapsed number of milliseconds.
1231 //
1232 unsigned int elapsed_ms = ( elapsed_time.tv_sec * MILLISECONDS_PER_SEC +
1233 elapsed_time.tv_usec / MICROSECONDS_PER_MS ) ;
1234 //
1235 // If more than msTimeout milliseconds have elapsed while
1236 // waiting for data, then we throw a ReadTimeout exception.
1237 //
1238 if ( ( msTimeout > 0 ) &&
1239 ( elapsed_ms > msTimeout ) )
1240 {
1241 throw SerialPort::ReadTimeout() ;
1242 }
1243 //
1244 // Wait for 1ms (1000us) for data to arrive.
1245 //
1246 usleep( MICROSECONDS_PER_MS ) ;
1247 }
1248 //
1249 // Return the first byte and remove it from the queue.
1250 //
1251 unsigned char next_char = mInputBuffer.front() ;
1252 mInputBuffer.pop() ;
1253 return next_char ;
1254 }
1255
1256 inline
1257 void
1258 SerialPort::SerialPortImpl::Read( SerialPort::DataBuffer& dataBuffer,
1259 const unsigned int numOfBytes,
1260 const unsigned int msTimeout )
1261 throw( SerialPort::NotOpen,
1262 SerialPort::ReadTimeout,
1263 std::runtime_error )
1264 {
1265 //
1266 // Make sure that the serial port is open.
1267 //
1268 if ( ! this->IsOpen() )
1269 {
1270 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1271 }
1272 //
1273 // Empty the data buffer.
1274 //
1275 dataBuffer.resize(0) ;
1276 //
1277 if ( 0 == numOfBytes )
1278 {
1279 //
1280 // Read all available data if numOfBytes is zero.
1281 //
1282 while ( this->IsDataAvailable() )
1283 {
1284 dataBuffer.push_back( ReadByte(msTimeout) ) ;
1285 }
1286 }
1287 else
1288 {
1289 //
1290 // Reserve enough space in the buffer to store the incoming
1291 // data.
1292 //
1293 dataBuffer.reserve( numOfBytes ) ;
1294 //
1295 for (unsigned int i=0; i<numOfBytes; ++i)
1296 {
1297 dataBuffer.push_back( ReadByte(msTimeout) ) ;
1298 }
1299 }
1300 return ;
1301 }
1302
1303 inline
1304 const std::string
1305 SerialPort::SerialPortImpl::ReadLine( const unsigned int msTimeout,
1306 const char lineTerminator )
1307 throw( SerialPort::NotOpen,
1308 SerialPort::ReadTimeout,
1309 std::runtime_error )
1310 {
1311 std::string result ;
1312 char next_char = 0 ;
1313 do
1314 {
1315 next_char = this->ReadByte( msTimeout ) ;
1316 result += next_char ;
1317 }
1318 while ( next_char != lineTerminator ) ;
1319 return result ;
1320 }
1321
1322 inline
1323 void
1324 SerialPort::SerialPortImpl::WriteByte( const unsigned char dataByte )
1325 throw( SerialPort::NotOpen,
1326 std::runtime_error )
1327 {
1328 //
1329 // Make sure that the serial port is open.
1330 //
1331 if ( ! this->IsOpen() )
1332 {
1333 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1334 }
1335 //
1336 // Write the byte to the serial port.
1337 //
1338 this->Write( &dataByte,
1339 1 ) ;
1340 return ;
1341 }
1342
1343 inline
1344 void
1345 SerialPort::SerialPortImpl::Write(const SerialPort::DataBuffer& dataBuffer)
1346 throw( SerialPort::NotOpen,
1347 std::runtime_error )
1348 {
1349 //
1350 // Make sure that the serial port is open.
1351 //
1352 if ( ! this->IsOpen() )
1353 {
1354 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1355 }
1356 //
1357 // Nothing needs to be done if there is no data in the buffer.
1358 //
1359 if ( 0 == dataBuffer.size() )
1360 {
1361 return ;
1362 }
1363 //
1364 // Allocate memory for storing the contents of the
1365 // dataBuffer. This allows us to write all the data using a single
1366 // call to write() instead of writing one byte at a time.
1367 //
1368 unsigned char* local_buffer = new unsigned char[dataBuffer.size()] ;
1369 if ( 0 == local_buffer )
1370 {
1371 throw std::runtime_error( std::string(__FUNCTION__) +
1372 ": Cannot allocate memory while writing"
1373 "data to the serial port." ) ;
1374 }
1375 //
1376 // Copy the data into local_buffer.
1377 //
1378 std::copy( dataBuffer.begin(),
1379 dataBuffer.end(),
1380 local_buffer ) ;
1381 //
1382 // Write data to the serial port.
1383 //
1384 try
1385 {
1386 this->Write( local_buffer,
1387 dataBuffer.size() ) ;
1388 }
1389 catch ( ... )
1390 {
1391 //
1392 // Free the allocated memory.
1393 //
1394 delete [] local_buffer ;
1395 throw ;
1396 }
1397 //
1398 // Free the allocated memory.
1399 //
1400 delete [] local_buffer ;
1401 return ;
1402 }
1403
1404 inline
1405 void
1406 SerialPort::SerialPortImpl::Write( const unsigned char* dataBuffer,
1407 const unsigned int bufferSize )
1408 throw( SerialPort::NotOpen,
1409 std::runtime_error )
1410 {
1411 //
1412 // Make sure that the serial port is open.
1413 //
1414 if ( ! this->IsOpen() )
1415 {
1416 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1417 }
1418 //
1419 // Write the data to the serial port. Keep retrying if EAGAIN
1420 // error is received.
1421 //
1422 int num_of_bytes_written = -1 ;
1423 do
1424 {
1425 num_of_bytes_written = write( mFileDescriptor,
1426 dataBuffer,
1427 bufferSize ) ;
1428 }
1429 while ( ( num_of_bytes_written < 0 ) &&
1430 ( EAGAIN == errno ) ) ;
1431 //
1432 if ( num_of_bytes_written < 0 )
1433 {
1434 throw std::runtime_error( strerror(errno) ) ;
1435 }
1436 //
1437 // :FIXME: What happens if num_of_bytes_written < bufferSize ?
1438 //
1439 return ;
1440 }
1441
1442 inline
1443 void
1444 SerialPort::SerialPortImpl::SetDtr( const bool dtrState )
1445 throw( SerialPort::NotOpen,
1446 std::runtime_error )
1447 {
1448 this->SetModemControlLine( TIOCM_DTR,
1449 dtrState ) ;
1450 return ;
1451 }
1452
1453 inline
1454 bool
1455 SerialPort::SerialPortImpl::GetDtr() const
1456 throw( SerialPort::NotOpen,
1457 std::runtime_error )
1458 {
1459 return this->GetModemControlLine( TIOCM_DTR ) ;
1460 }
1461
1462 inline
1463 void
1464 SerialPort::SerialPortImpl::SetRts( const bool rtsState )
1465 throw( SerialPort::NotOpen,
1466 std::runtime_error )
1467 {
1468 this->SetModemControlLine( TIOCM_RTS,
1469 rtsState ) ;
1470 return ;
1471 }
1472
1473 inline
1474 bool
1475 SerialPort::SerialPortImpl::GetRts() const
1476 throw( SerialPort::NotOpen,
1477 std::runtime_error )
1478 {
1479 return this->GetModemControlLine( TIOCM_RTS ) ;
1480 }
1481
1482
1483 inline
1484 bool
1485 SerialPort::SerialPortImpl::GetCts() const
1486 throw( SerialPort::NotOpen,
1487 std::runtime_error )
1488 {
1489 return this->GetModemControlLine( TIOCM_CTS ) ;
1490 }
1491
1492
1493 inline
1494 bool
1495 SerialPort::SerialPortImpl::GetDsr() const
1496 throw( SerialPort::NotOpen,
1497 std::runtime_error )
1498 {
1499 return this->GetModemControlLine( TIOCM_DSR ) ;
1500 }
1501
1502 inline
1503 void
1504 SerialPort::SerialPortImpl::HandlePosixSignal( int signalNumber )
1505 {
1506 //
1507 // We only want to deal with SIGIO signals here.
1508 //
1509 if ( SIGIO != signalNumber )
1510 {
1511 return ;
1512 }
1513 //
1514 // Check if any data is available at the specified file
1515 // descriptor.
1516 //
1517 int num_of_bytes_available = 0 ;
1518 if ( ioctl( mFileDescriptor,
1519 FIONREAD,
1520 &num_of_bytes_available ) < 0 )
1521 {
1522 /*
1523 * Ignore any errors and return immediately.
1524 */
1525 return ;
1526 }
1527 //
1528 // If data is available, read all available data and shove
1529 // it into the corresponding input buffer.
1530 //
1531 for (int i=0; i<num_of_bytes_available; ++i)
1532 {
1533 unsigned char next_byte ;
1534 if ( read( mFileDescriptor,
1535 &next_byte,
1536 1 ) > 0 )
1537 {
1538 mInputBuffer.push( next_byte ) ;
1539 }
1540 else
1541 {
1542 break ;
1543 }
1544 }
1545 return ;
1546 }
1547
1548 inline
1549 void
1550 SerialPort::SerialPortImpl::SetModemControlLine( const int modemLine,
1551 const bool lineState )
1552 throw( SerialPort::NotOpen,
1553 std::runtime_error )
1554 {
1555 //
1556 // Make sure that the serial port is open.
1557 //
1558 if ( ! this->IsOpen() )
1559 {
1560 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1561 }
1562 //
1563 // :TODO: Check to make sure that modemLine is a valid value.
1564 //
1565 // Set or unset the specified bit according to the value of
1566 // lineState.
1567 //
1568 int ioctl_result = -1 ;
1569 if ( true == lineState )
1570 {
1571 int set_line_mask = modemLine ;
1572 ioctl_result = ioctl( mFileDescriptor,
1573 TIOCMBIS,
1574 &set_line_mask ) ;
1575 }
1576 else
1577 {
1578 int reset_line_mask = modemLine ;
1579 ioctl_result = ioctl( mFileDescriptor,
1580 TIOCMBIC,
1581 &reset_line_mask ) ;
1582 }
1583 //
1584 // Check for errors.
1585 //
1586 if ( -1 == ioctl_result )
1587 {
1588 throw std::runtime_error( strerror(errno) ) ;
1589 }
1590 return ;
1591 }
1592
1593 inline
1594 bool
1595 SerialPort::SerialPortImpl::GetModemControlLine( const int modemLine ) const
1596 throw( SerialPort::NotOpen,
1597 std::runtime_error )
1598 {
1599 //
1600 // Make sure that the serial port is open.
1601 //
1602 if ( ! this->IsOpen() )
1603 {
1604 throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1605 }
1606 //
1607 // Use an ioctl() call to get the state of the line.
1608 //
1609 int serial_port_state = 0 ;
1610 if ( -1 == ioctl( mFileDescriptor,
1611 TIOCMGET,
1612 &serial_port_state ) )
1613 {
1614 throw std::runtime_error( strerror(errno) ) ;
1615 }
1616 //
1617 // :TODO: Verify that modemLine is a valid value.
1618 //
1619 return ( serial_port_state & modemLine ) ;
1620 }
1621
1622 namespace
1623 {
1624 const struct timeval
1625 operator-( const struct timeval& firstOperand,
1626 const struct timeval& secondOperand )
1627 {
1628 /*
1629 * This implementation may result in undefined behavior if the
1630 * platform uses unsigned values for storing tv_sec and tv_usec
1631 * members of struct timeval.
1632 */
1633 //
1634 // Number of microseconds in a second.
1635 //
1636 const int MICROSECONDS_PER_SECOND = 1000000 ;
1637 struct timeval result ;
1638 //
1639 // Take the difference of individual members of the two operands.
1640 //
1641 result.tv_sec = firstOperand.tv_sec - secondOperand.tv_sec ;
1642 result.tv_usec = firstOperand.tv_usec - secondOperand.tv_usec ;
1643 //
1644 // If abs(result.tv_usec) is larger than MICROSECONDS_PER_SECOND,
1645 // then increment/decrement result.tv_sec accordingly.
1646 //
1647 if ( abs( result.tv_usec ) > MICROSECONDS_PER_SECOND )
1648 {
1649 int num_of_seconds = (result.tv_usec / MICROSECONDS_PER_SECOND ) ;
1650 result.tv_sec += num_of_seconds ;
1651 result.tv_usec -= ( MICROSECONDS_PER_SECOND * num_of_seconds ) ;
1652 }
1653 return result ;
1654 }
1655 } ;

  ViewVC Help
Powered by ViewVC 1.1.20