forked from drewnoakes/joystick
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathserialstream.h
199 lines (172 loc) · 5.9 KB
/
serialstream.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
* Author: Terraneo Federico
* Distributed under the Boost Software License, Version 1.0.
*/
#include <string>
#include <memory>
#include <stdexcept>
#include <boost/system/error_code.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/categories.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#ifndef SERIALSTREAM_H
#define SERIALSTREAM_H
/**
* Thrown if timeout occurs
*/
class TimeoutException: public std::ios_base::failure
{
public:
TimeoutException(const std::string& arg): failure(arg) {}
};
/**
* This class contains all the options for a serial port.
*/
class SerialOptions
{
typedef boost::posix_time::time_duration time_duration;
typedef boost::posix_time::seconds seconds;
public:
///Possible flow controls.
enum FlowControl { noflow, software, hardware };
///Possible parities.
enum Parity { noparity, odd, even };
///Possible stop bits.
enum StopBits { one, onepointfive, two };
/**
* Default constructor.
*/
SerialOptions() : device(), baudrate(9600), timeout(seconds(0)),
parity(noparity), csize(8), flow(noflow), stop(one) {}
/**
* Constructor.
* \param device device name (/dev/ttyS0, /dev/ttyUSB0, COM1, ...)
* \param baudrate baudrate, like 9600, 115200 ...
* \param timeout timeout when reading, use zero to disable
* \param parity parity
* \param csize character size (5,6,7 or 8)
* \param flow flow control
* \param stop stop bits
*
*/
SerialOptions(const std::string& device, unsigned int baudrate,
time_duration timeout=seconds(0), Parity parity=noparity,
unsigned char csize=8, FlowControl flow=noflow, StopBits stop=one) :
device(device), baudrate(baudrate), timeout(timeout),
parity(parity), csize(csize), flow(flow), stop(stop) {}
/**
* Setter and getter for device name
*/
void setDevice(const std::string& device) { this->device=device; }
std::string getDevice() const { return this->device; }
/**
* Setter and getter for baudrate
*/
void setBaudrate(unsigned int baudrate) { this->baudrate=baudrate; }
unsigned int getBaudrate() const { return this->baudrate; }
/**
* Setter and getter for timeout
*/
void setTimeout(time_duration timeout) { this->timeout=timeout; }
time_duration getTimeout() const { return this->timeout; }
/**
* Setter and getter for parity
*/
void setParity(Parity parity) { this->parity=parity; }
Parity getParity() const { return this->parity; }
/**
* Setter and getter character size
*/
void setCsize(unsigned char csize) { this->csize=csize; }
unsigned char getCsize() const { return this->csize; }
/**
* Setter and getter flow control
*/
void setFlowControl(FlowControl flow) { this->flow=flow; }
FlowControl getFlowControl() const { return this->flow; }
/**
* Setter and getter for stop bits
*/
void setStopBits(StopBits stop) { this->stop=stop; }
StopBits getStopBits() const { return this->stop; }
private:
std::string device;
unsigned int baudrate;
time_duration timeout;
Parity parity;
unsigned char csize;
FlowControl flow;
StopBits stop;
};
//Forward declaration
class SerialDeviceImpl;
/**
* \internal
* Implementation detail of a serial device.
* User code should use SerialStream
*/
class SerialDevice
{
public:
typedef char char_type;
typedef boost::iostreams::bidirectional_device_tag category;
/**
* \internal
* Constructor.
* \throws ios_base::failure if there are errors with the serial port.
* \param options serial port options
*/
explicit SerialDevice(const SerialOptions& options);
/**
* \internal
* Read from serial port.
* \throws TimeoutException on timeout, or ios_base::failure if there are
* errors with the serial port.
* Note: TimeoutException derives from ios_base::failure so catching that
* allows to catch any exception.
* Use the clear() member function to go on reading after an exception was
* thrown.
* \param s where to store read characters
* \param n max number of characters to read
* \return number of character read
*/
std::streamsize read(char *s, std::streamsize n);
/**
* \internal
* Write to serial port.
* \throws ios_base::failure if there are errors with the serial port.
* Use the clear() member function to go on reading after an exception was
* thrown.
* \param s
* \param n
* \return
*/
std::streamsize write(const char *s, std::streamsize n);
private:
/**
* Callack called either when the read timeout is expired or canceled.
* If called because timeout expired, sets result to resultTimeoutExpired
*/
void timeoutExpired(const boost::system::error_code& error);
/**
* Callback called either if a read complete or read error occurs
* If called because of read complete, sets result to resultSuccess
* If called because read error, sets result to resultError
*/
void readCompleted(const boost::system::error_code& error,
const size_t bytesTransferred);
std::shared_ptr<SerialDeviceImpl> pImpl; //Implementation
};
/**
* SerialStream, an iostream-compatible serial port class.
* Note: due to a limitation about error reporting with boost::iostreams,
* this class *always* throws exceptions on error (timeout, failure, etc..)
* so after creating an instance of this class you should alway enable
* exceptions with the exceptions() member function:
* \code SerialStream serial; serial.exceptions(ios::failbit | ios::badbit);
* \endcode
* If you don't, functions like getline() will swallow the exceptions, while
* operator >> will throw, leading to unconsistent behaviour.
*/
typedef boost::iostreams::stream<SerialDevice> SerialStream;
#endif //SERIALSTREAM_H