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

Annotation of /smsdaemon/serialport/SerialPort.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 91 - (hide annotations) (download)
Mon Jun 16 10:56:02 2008 UTC (15 years, 11 months ago) by torben
File size: 41533 byte(s)
Move serialport to its own directory

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

  ViewVC Help
Powered by ViewVC 1.1.20