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

Annotation of /smsdaemon/serialport/SerialPort.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

astyle -t -b -N

1 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 torben 196 //
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 torben 26
51 torben 196 /*
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 torben 26 } ;
62    
63     class SerialPort::SerialPortImpl : public PosixSignalHandler
64     {
65     public:
66 torben 196 /**
67     * Constructor.
68     */
69     SerialPortImpl( const std::string& serialPortName ) ;
70 torben 26
71 torben 196 /**
72     * Destructor.
73     */
74     ~SerialPortImpl() ;
75 torben 26
76 torben 196 /**
77     * Open the serial port.
78     */
79     void Open()
80     throw( SerialPort::OpenFailed,
81     SerialPort::AlreadyOpen ) ;
82 torben 26
83 torben 196 /**
84     * Check if the serial port is currently open.
85     */
86     bool
87     IsOpen() const ;
88 torben 26
89 torben 196 /**
90     * Close the serial port.
91     */
92     void
93     Close()
94     throw(SerialPort::NotOpen) ;
95 torben 26
96 torben 196 /**
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 torben 26
106 torben 196 /**
107     * Get the current baud rate.
108     */
109     SerialPort::BaudRate
110     GetBaudRate() const
111     throw( SerialPort::NotOpen,
112     std::runtime_error ) ;
113 torben 26
114 torben 196 /**
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 torben 26
123 torben 196 /**
124     * Get the current character size.
125     */
126     SerialPort::CharacterSize
127     GetCharSize() const
128     throw( SerialPort::NotOpen,
129     std::runtime_error ) ;
130 torben 26
131 torben 196 void
132     SetParity( const SerialPort::Parity parityType )
133     throw( SerialPort::NotOpen,
134     std::invalid_argument,
135     std::runtime_error ) ;
136 torben 26
137 torben 196 SerialPort::Parity
138     GetParity() const
139     throw(SerialPort::NotOpen) ;
140 torben 26
141 torben 196 void
142     SetNumOfStopBits( const SerialPort::StopBits numOfStopBits )
143     throw( SerialPort::NotOpen,
144     std::invalid_argument ) ;
145 torben 26
146 torben 196 SerialPort::StopBits
147     GetNumOfStopBits() const
148     throw(SerialPort::NotOpen) ;
149 torben 26
150 torben 196 void
151     SetFlowControl( const SerialPort::FlowControl flowControl )
152     throw( SerialPort::NotOpen,
153     std::invalid_argument ) ;
154 torben 26
155 torben 196 SerialPort::FlowControl
156     GetFlowControl() const
157     throw( SerialPort::NotOpen ) ;
158 torben 26
159 torben 196 bool
160     IsDataAvailable() const
161     throw( SerialPort::NotOpen,
162     std::runtime_error ) ;
163 torben 26
164 torben 196 unsigned char
165     ReadByte(const unsigned int msTimeout = 0 )
166     throw( SerialPort::NotOpen,
167     SerialPort::ReadTimeout,
168     std::runtime_error ) ;
169 torben 26
170 torben 196 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 torben 26
178 torben 196 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 torben 26
185 torben 196 void
186     WriteByte( const unsigned char dataByte )
187     throw( SerialPort::NotOpen,
188     std::runtime_error ) ;
189 torben 26
190 torben 196 void
191     Write(const SerialPort::DataBuffer& dataBuffer)
192     throw( SerialPort::NotOpen,
193     std::runtime_error ) ;
194 torben 26
195 torben 196 void
196     Write( const unsigned char* dataBuffer,
197     const unsigned int bufferSize )
198     throw( SerialPort::NotOpen,
199     std::runtime_error ) ;
200 torben 26
201 torben 196 void
202     SetDtr( const bool dtrState )
203     throw( SerialPort::NotOpen,
204     std::runtime_error ) ;
205 torben 26
206 torben 196 bool
207     GetDtr() const
208     throw( SerialPort::NotOpen,
209     std::runtime_error ) ;
210 torben 26
211 torben 196 void
212     SetRts( const bool rtsState )
213     throw( SerialPort::NotOpen,
214     std::runtime_error ) ;
215 torben 26
216 torben 196 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 torben 26 private:
238 torben 196 /**
239     * Name of the serial port. On POSIX systems this is the name of
240     * the device file.
241     */
242     std::string mSerialPortName ;
243 torben 26
244 torben 196 /**
245     * Flag that indicates whether the serial port is currently open.
246     */
247     bool mIsOpen ;
248 torben 26
249 torben 196 /**
250     * The file descriptor corresponding to the serial port.
251     */
252     int mFileDescriptor ;
253 torben 26
254 torben 196 /**
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 torben 26
261 torben 196 /**
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 torben 26
274 torben 196 /**
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 torben 26
289 torben 196 /**
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 torben 26 } ;
303    
304     SerialPort::SerialPort( const std::string& serialPortName ) :
305 torben 196 mSerialPortImpl(new SerialPortImpl(serialPortName) )
306 torben 26 {
307 torben 196 /* empty */
308 torben 26 }
309    
310     SerialPort::~SerialPort()
311 torben 196 throw()
312 torben 26 {
313 torben 196 /*
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 torben 26 }
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 torben 196 throw( OpenFailed,
337     AlreadyOpen,
338     UnsupportedBaudRate,
339     std::invalid_argument )
340 torben 26 {
341 torben 196 //
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 torben 26 }
357    
358     bool
359     SerialPort::IsOpen() const
360     {
361 torben 196 return mSerialPortImpl->IsOpen() ;
362 torben 26 }
363    
364     void
365     SerialPort::Close()
366 torben 196 throw(NotOpen)
367 torben 26 {
368 torben 196 mSerialPortImpl->Close() ;
369     return ;
370 torben 26 }
371    
372     void
373     SerialPort::SetBaudRate( const BaudRate baudRate )
374 torben 196 throw( UnsupportedBaudRate,
375     NotOpen,
376     std::invalid_argument )
377 torben 26 {
378 torben 196 mSerialPortImpl->SetBaudRate( baudRate ) ;
379     return ;
380 torben 26 }
381    
382     SerialPort::BaudRate
383     SerialPort::GetBaudRate() const
384 torben 196 throw( NotOpen,
385     std::runtime_error )
386 torben 26 {
387 torben 196 return mSerialPortImpl->GetBaudRate() ;
388 torben 26 }
389    
390    
391     void
392     SerialPort::SetCharSize( const CharacterSize charSize )
393 torben 196 throw( NotOpen,
394     std::invalid_argument )
395 torben 26 {
396 torben 196 mSerialPortImpl->SetCharSize(charSize) ;
397 torben 26 }
398    
399     SerialPort::CharacterSize
400     SerialPort::GetCharSize() const
401 torben 196 throw(NotOpen)
402 torben 26 {
403 torben 196 return mSerialPortImpl->GetCharSize() ;
404 torben 26 }
405    
406     void
407     SerialPort::SetParity( const Parity parityType )
408 torben 196 throw( NotOpen,
409     std::invalid_argument )
410 torben 26 {
411 torben 196 mSerialPortImpl->SetParity( parityType ) ;
412     return ;
413 torben 26 }
414    
415     SerialPort::Parity
416     SerialPort::GetParity() const
417 torben 196 throw(NotOpen)
418 torben 26 {
419 torben 196 return mSerialPortImpl->GetParity() ;
420 torben 26 }
421    
422     void
423     SerialPort::SetNumOfStopBits( const StopBits numOfStopBits )
424 torben 196 throw( NotOpen,
425     std::invalid_argument )
426 torben 26 {
427 torben 196 mSerialPortImpl->SetNumOfStopBits(numOfStopBits) ;
428     return ;
429 torben 26 }
430    
431     SerialPort::StopBits
432     SerialPort::GetNumOfStopBits() const
433 torben 196 throw(NotOpen)
434 torben 26 {
435 torben 196 return mSerialPortImpl->GetNumOfStopBits() ;
436 torben 26 }
437    
438    
439     void
440     SerialPort::SetFlowControl( const FlowControl flowControl )
441 torben 196 throw( NotOpen,
442     std::invalid_argument )
443 torben 26 {
444 torben 196 mSerialPortImpl->SetFlowControl( flowControl ) ;
445     return ;
446 torben 26 }
447    
448     SerialPort::FlowControl
449     SerialPort::GetFlowControl() const
450 torben 196 throw( NotOpen )
451 torben 26 {
452 torben 196 return mSerialPortImpl->GetFlowControl() ;
453 torben 26 }
454    
455     bool
456     SerialPort::IsDataAvailable() const
457 torben 196 throw(NotOpen)
458 torben 26 {
459 torben 196 return mSerialPortImpl->IsDataAvailable() ;
460 torben 26 }
461    
462     unsigned char
463     SerialPort::ReadByte( const unsigned int msTimeout )
464 torben 196 throw( NotOpen,
465     ReadTimeout,
466     std::runtime_error )
467 torben 26 {
468 torben 196 return mSerialPortImpl->ReadByte(msTimeout) ;
469 torben 26 }
470    
471     void
472     SerialPort::Read( SerialPort::DataBuffer& dataBuffer,
473     const unsigned int numOfBytes,
474     const unsigned int msTimeout )
475 torben 196 throw( NotOpen,
476     ReadTimeout,
477     std::runtime_error )
478 torben 26 {
479 torben 196 return mSerialPortImpl->Read( dataBuffer,
480     numOfBytes,
481     msTimeout ) ;
482 torben 26 }
483    
484    
485     const std::string
486     SerialPort::ReadLine( const unsigned int msTimeout,
487     const char lineTerminator )
488 torben 196 throw( NotOpen,
489     ReadTimeout,
490     std::runtime_error )
491 torben 26 {
492 torben 196 return mSerialPortImpl->ReadLine( msTimeout,
493     lineTerminator ) ;
494 torben 26 }
495    
496    
497     void
498     SerialPort::WriteByte( const unsigned char dataByte )
499 torben 196 throw( SerialPort::NotOpen,
500     std::runtime_error )
501 torben 26 {
502 torben 196 mSerialPortImpl->WriteByte( dataByte ) ;
503     return ;
504 torben 26 }
505    
506    
507     void
508     SerialPort::Write(const DataBuffer& dataBuffer)
509 torben 196 throw( NotOpen,
510     std::runtime_error )
511 torben 26 {
512 torben 196 mSerialPortImpl->Write( dataBuffer ) ;
513     return ;
514 torben 26 }
515    
516     void
517     SerialPort::Write(const std::string& dataString)
518 torben 196 throw( NotOpen,
519     std::runtime_error )
520 torben 26 {
521 torben 196 mSerialPortImpl->Write( reinterpret_cast<const unsigned char*>(dataString.c_str()),
522     dataString.length() ) ;
523     return ;
524 torben 26 }
525    
526     void
527     SerialPort::SetDtr( const bool dtrState )
528 torben 196 throw( SerialPort::NotOpen,
529     std::runtime_error )
530 torben 26 {
531 torben 196 mSerialPortImpl->SetDtr( dtrState ) ;
532     return ;
533 torben 26 }
534    
535     bool
536 torben 196 SerialPort::GetDtr() const
537     throw( SerialPort::NotOpen,
538     std::runtime_error )
539 torben 26 {
540 torben 196 return mSerialPortImpl->GetDtr() ;
541 torben 26 }
542    
543     void
544     SerialPort::SetRts( const bool rtsState )
545 torben 196 throw( SerialPort::NotOpen,
546     std::runtime_error )
547 torben 26 {
548 torben 196 mSerialPortImpl->SetRts( rtsState ) ;
549     return ;
550 torben 26 }
551    
552     bool
553 torben 196 SerialPort::GetRts() const
554     throw( SerialPort::NotOpen,
555     std::runtime_error )
556 torben 26 {
557 torben 196 return mSerialPortImpl->GetRts() ;
558 torben 26 }
559    
560    
561     bool
562 torben 196 SerialPort::GetCts() const
563     throw( SerialPort::NotOpen,
564     std::runtime_error )
565 torben 26 {
566 torben 196 return mSerialPortImpl->GetCts() ;
567 torben 26 }
568    
569     bool
570 torben 196 SerialPort::GetDsr() const
571     throw( SerialPort::NotOpen,
572     std::runtime_error )
573 torben 26 {
574 torben 196 return mSerialPortImpl->GetDsr() ;
575 torben 26 }
576    
577     /* ------------------------------------------------------------ */
578     inline
579     SerialPort::SerialPortImpl::SerialPortImpl( const std::string& serialPortName ) :
580 torben 196 mSerialPortName(serialPortName),
581     mIsOpen(false),
582     mFileDescriptor(-1),
583     mOldPortSettings(),
584     mInputBuffer()
585 torben 26 {
586 torben 196 /* empty */
587 torben 26 }
588    
589     inline
590     SerialPort::SerialPortImpl::~SerialPortImpl()
591     {
592 torben 196 //
593     // Close the serial port if it is open.
594     //
595     if ( this->IsOpen() )
596     {
597     this->Close() ;
598     }
599     return ;
600 torben 26 }
601    
602     inline
603     void
604     SerialPort::SerialPortImpl::Open()
605 torben 196 throw( SerialPort::OpenFailed,
606     SerialPort::AlreadyOpen )
607 torben 26 {
608 torben 196 /*
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 torben 26
632    
633 torben 196 PosixSignalDispatcher& signal_dispatcher = PosixSignalDispatcher::Instance() ;
634     signal_dispatcher.AttachHandler( SIGIO,
635     *this ) ;
636 torben 26
637 torben 196 /*
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 torben 26
648 torben 196 /*
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 torben 26
658 torben 196 /*
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 torben 26
668 torben 196 //
669     // Start assembling the new port settings.
670     //
671     termios port_settings ;
672     bzero( &port_settings,
673     sizeof( port_settings ) ) ;
674 torben 26
675 torben 196 //
676     // Enable the receiver (CREAD) and ignore modem control lines
677     // (CLOCAL).
678     //
679     port_settings.c_cflag |= CREAD | CLOCAL ;
680 torben 26
681 torben 196 //
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 torben 26
709 torben 196 /*
710     * The serial port is open at this point.
711     */
712     mIsOpen = true ;
713     return ;
714 torben 26 }
715    
716     inline
717     bool
718     SerialPort::SerialPortImpl::IsOpen() const
719     {
720 torben 196 return mIsOpen ;
721 torben 26 }
722    
723     inline
724     void
725     SerialPort::SerialPortImpl::Close()
726 torben 196 throw( SerialPort::NotOpen )
727 torben 26 {
728 torben 196 //
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 torben 26 }
756    
757     inline
758     void
759     SerialPort::SerialPortImpl::SetBaudRate( const SerialPort::BaudRate baudRate )
760 torben 196 throw( SerialPort::NotOpen,
761     SerialPort::UnsupportedBaudRate,
762     std::invalid_argument,
763     std::runtime_error )
764 torben 26 {
765 torben 196 //
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 torben 26 }
805    
806     inline
807     SerialPort::BaudRate
808     SerialPort::SerialPortImpl::GetBaudRate() const
809 torben 196 throw( SerialPort::NotOpen,
810     std::runtime_error )
811 torben 26 {
812 torben 196 //
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 torben 26 }
833    
834     inline
835     void
836     SerialPort::SerialPortImpl::SetCharSize( const SerialPort::CharacterSize charSize )
837 torben 196 throw( SerialPort::NotOpen,
838     std::invalid_argument,
839     std::runtime_error )
840 torben 26 {
841 torben 196 //
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 torben 26 }
873    
874     inline
875     SerialPort::CharacterSize
876     SerialPort::SerialPortImpl::GetCharSize() const
877 torben 196 throw( SerialPort::NotOpen,
878     std::runtime_error )
879 torben 26 {
880 torben 196 //
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 torben 26 }
901    
902     inline
903     void
904     SerialPort::SerialPortImpl::SetParity( const SerialPort::Parity parityType )
905 torben 196 throw( SerialPort::NotOpen,
906     std::invalid_argument,
907     std::runtime_error )
908 torben 26 {
909 torben 196 //
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 torben 26 }
958    
959     inline
960     SerialPort::Parity
961     SerialPort::SerialPortImpl::GetParity() const
962 torben 196 throw(SerialPort::NotOpen)
963 torben 26 {
964 torben 196 //
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 torben 26 }
1002    
1003     inline
1004     void
1005     SerialPort::SerialPortImpl::SetNumOfStopBits( const SerialPort::StopBits numOfStopBits )
1006 torben 196 throw( SerialPort::NotOpen,
1007     std::invalid_argument )
1008 torben 26 {
1009 torben 196 //
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 torben 26 }
1051    
1052     inline
1053     SerialPort::StopBits
1054     SerialPort::SerialPortImpl::GetNumOfStopBits() const
1055 torben 196 throw(SerialPort::NotOpen)
1056 torben 26 {
1057 torben 196 //
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 torben 26 }
1083    
1084     inline
1085     void
1086     SerialPort::SerialPortImpl::SetFlowControl( const SerialPort::FlowControl flowControl )
1087 torben 196 throw( SerialPort::NotOpen,
1088     std::invalid_argument )
1089 torben 26 {
1090 torben 196 //
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 torben 26 }
1132    
1133     inline
1134     SerialPort::FlowControl
1135     SerialPort::SerialPortImpl::GetFlowControl() const
1136 torben 196 throw( SerialPort::NotOpen )
1137 torben 26 {
1138 torben 196 //
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 torben 26 }
1164    
1165     inline
1166     bool
1167     SerialPort::SerialPortImpl::IsDataAvailable() const
1168 torben 196 throw( SerialPort::NotOpen,
1169     std::runtime_error )
1170 torben 26 {
1171 torben 196 //
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 torben 26 }
1183    
1184     inline
1185     unsigned char
1186     SerialPort::SerialPortImpl::ReadByte(const unsigned int msTimeout)
1187 torben 196 throw( SerialPort::NotOpen,
1188     SerialPort::ReadTimeout,
1189     std::runtime_error )
1190 torben 26 {
1191 torben 196 //
1192     // Make sure that the serial port is open.
1193     //
1194     if ( ! this->IsOpen() )
1195     {
1196     throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1197     }
1198     //
1199     // Get the current time. Throw an exception if we are unable
1200     // to read the current time.
1201     //
1202     struct timeval entry_time ;
1203     if ( gettimeofday( &entry_time,
1204     NULL ) < 0 )
1205     {
1206     throw std::runtime_error( strerror(errno) ) ;
1207     }
1208     //
1209     // Wait for data to be available.
1210     //
1211     const int MICROSECONDS_PER_MS = 1000 ;
1212     const int MILLISECONDS_PER_SEC = 1000 ;
1213     //
1214     while ( 0 == mInputBuffer.size() )
1215     {
1216     //
1217     // Read the current time.
1218     //
1219     struct timeval curr_time ;
1220     if ( gettimeofday( &curr_time,
1221     NULL ) < 0 )
1222     {
1223     throw std::runtime_error( strerror(errno) ) ;
1224     }
1225     //
1226     // Obtain the elapsed time.
1227     //
1228     struct timeval elapsed_time = curr_time - entry_time ;
1229     //
1230     // Increase the elapsed number of milliseconds.
1231     //
1232     unsigned int elapsed_ms = ( elapsed_time.tv_sec * MILLISECONDS_PER_SEC +
1233     elapsed_time.tv_usec / MICROSECONDS_PER_MS ) ;
1234     //
1235     // If more than msTimeout milliseconds have elapsed while
1236     // waiting for data, then we throw a ReadTimeout exception.
1237     //
1238     if ( ( msTimeout > 0 ) &&
1239     ( elapsed_ms > msTimeout ) )
1240     {
1241     throw SerialPort::ReadTimeout() ;
1242     }
1243     //
1244     // Wait for 1ms (1000us) for data to arrive.
1245     //
1246     usleep( MICROSECONDS_PER_MS ) ;
1247     }
1248     //
1249     // Return the first byte and remove it from the queue.
1250     //
1251     unsigned char next_char = mInputBuffer.front() ;
1252     mInputBuffer.pop() ;
1253     return next_char ;
1254 torben 26 }
1255    
1256     inline
1257     void
1258     SerialPort::SerialPortImpl::Read( SerialPort::DataBuffer& dataBuffer,
1259     const unsigned int numOfBytes,
1260     const unsigned int msTimeout )
1261 torben 196 throw( SerialPort::NotOpen,
1262     SerialPort::ReadTimeout,
1263     std::runtime_error )
1264 torben 26 {
1265 torben 196 //
1266     // Make sure that the serial port is open.
1267     //
1268     if ( ! this->IsOpen() )
1269     {
1270     throw SerialPort::NotOpen( ERR_MSG_PORT_NOT_OPEN ) ;
1271     }
1272     //
1273     // Empty the data buffer.
1274     //
1275     dataBuffer.resize(0) ;
1276     //
1277     if ( 0 == numOfBytes )
1278     {
1279     //
1280     // Read all available data if numOfBytes is zero.
1281     //
1282     while ( this->IsDataAvailable() )
1283     {
1284     dataBuffer.push_back( ReadByte(msTimeout) ) ;
1285     }
1286     }
1287     else
1288     {
1289     //
1290     // Reserve enough space in the buffer to store the incoming
1291     // data.
1292     //
1293     dataBuffer.reserve( numOfBytes ) ;
1294     //
1295     for (unsigned int i=0; i<numOfBytes; ++i)
1296     {
1297     dataBuffer.push_back( ReadByte(msTimeout) ) ;
1298     }
1299     }
1300     return ;
1301 torben 26 }
1302    
1303     inline
1304     const std::string
1305     SerialPort::SerialPortImpl::ReadLine( const unsigned int msTimeout,
1306     const char lineTerminator )
1307 torben 196 throw( SerialPort::NotOpen,
1308     SerialPort::ReadTimeout,
1309     std::runtime_error )
1310 torben 26 {
1311 torben 196 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 torben 26 }
1321    
1322     inline
1323     void
1324     SerialPort::SerialPortImpl::WriteByte( const unsigned char dataByte )
1325 torben 196 throw( SerialPort::NotOpen,
1326     std::runtime_error )
1327 torben 26 {
1328 torben 196 //
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 torben 26 }
1342    
1343     inline
1344     void
1345     SerialPort::SerialPortImpl::Write(const SerialPort::DataBuffer& dataBuffer)
1346 torben 196 throw( SerialPort::NotOpen,
1347     std::runtime_error )
1348 torben 26 {
1349 torben 196 //
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 torben 26 }
1403    
1404     inline
1405     void
1406     SerialPort::SerialPortImpl::Write( const unsigned char* dataBuffer,
1407     const unsigned int bufferSize )
1408 torben 196 throw( SerialPort::NotOpen,
1409     std::runtime_error )
1410 torben 26 {
1411 torben 196 //
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 torben 26 }
1441    
1442     inline
1443     void
1444     SerialPort::SerialPortImpl::SetDtr( const bool dtrState )
1445 torben 196 throw( SerialPort::NotOpen,
1446     std::runtime_error )
1447 torben 26 {
1448 torben 196 this->SetModemControlLine( TIOCM_DTR,
1449     dtrState ) ;
1450     return ;
1451 torben 26 }
1452    
1453     inline
1454     bool
1455     SerialPort::SerialPortImpl::GetDtr() const
1456 torben 196 throw( SerialPort::NotOpen,
1457     std::runtime_error )
1458 torben 26 {
1459 torben 196 return this->GetModemControlLine( TIOCM_DTR ) ;
1460     }
1461 torben 26
1462     inline
1463     void
1464     SerialPort::SerialPortImpl::SetRts( const bool rtsState )
1465 torben 196 throw( SerialPort::NotOpen,
1466     std::runtime_error )
1467 torben 26 {
1468 torben 196 this->SetModemControlLine( TIOCM_RTS,
1469     rtsState ) ;
1470     return ;
1471 torben 26 }
1472    
1473     inline
1474     bool
1475     SerialPort::SerialPortImpl::GetRts() const
1476 torben 196 throw( SerialPort::NotOpen,
1477     std::runtime_error )
1478 torben 26 {
1479 torben 196 return this->GetModemControlLine( TIOCM_RTS ) ;
1480     }
1481 torben 26
1482    
1483     inline
1484     bool
1485     SerialPort::SerialPortImpl::GetCts() const
1486 torben 196 throw( SerialPort::NotOpen,
1487     std::runtime_error )
1488 torben 26 {
1489 torben 196 return this->GetModemControlLine( TIOCM_CTS ) ;
1490     }
1491 torben 26
1492    
1493     inline
1494     bool
1495     SerialPort::SerialPortImpl::GetDsr() const
1496 torben 196 throw( SerialPort::NotOpen,
1497     std::runtime_error )
1498 torben 26 {
1499 torben 196 return this->GetModemControlLine( TIOCM_DSR ) ;
1500     }
1501 torben 26
1502     inline
1503     void
1504     SerialPort::SerialPortImpl::HandlePosixSignal( int signalNumber )
1505     {
1506 torben 196 //
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 torben 26 }
1547    
1548     inline
1549     void
1550     SerialPort::SerialPortImpl::SetModemControlLine( const int modemLine,
1551 torben 196 const bool lineState )
1552     throw( SerialPort::NotOpen,
1553     std::runtime_error )
1554 torben 26 {
1555 torben 196 //
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 torben 26 }
1592    
1593     inline
1594     bool
1595     SerialPort::SerialPortImpl::GetModemControlLine( const int modemLine ) const
1596 torben 196 throw( SerialPort::NotOpen,
1597     std::runtime_error )
1598 torben 26 {
1599 torben 196 //
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 torben 26 }
1621    
1622     namespace
1623     {
1624 torben 196 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 torben 26 } ;

  ViewVC Help
Powered by ViewVC 1.1.20