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

Annotation of /smsdaemon/serialport/SerialPort.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 114 - (hide annotations) (download)
Sun Nov 2 20:14:20 2008 UTC (15 years, 7 months ago) by torben
File size: 41573 byte(s)
Enable compilation 4.3

1 torben 26 /***************************************************************************
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 torben 114 #include <string.h>
35     #include <stdlib.h>
36 torben 26
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 torben 36 unsigned int elapsed_ms = ( elapsed_time.tv_sec * MILLISECONDS_PER_SEC +
1233 torben 26 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 torben 36 for(unsigned int i=0; i<numOfBytes; ++i)
1296 torben 26 {
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