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 |
|
|
} ; |