]>
Commit | Line | Data |
---|---|---|
8f4b34cc | 1 | /* Copyright 2012 William Woodall and John Harrison */ |
6138acee | 2 | #include <alloca.h> |
8f4b34cc | 3 | |
c8e78412 WW |
4 | #include "serial/serial.h" |
5 | ||
6 | #ifdef _WIN32 | |
7 | #include "serial/impl/win.h" | |
8 | #else | |
9 | #include "serial/impl/unix.h" | |
10 | #endif | |
11 | ||
8f4b34cc | 12 | using std::invalid_argument; |
8f4b34cc | 13 | using std::min; |
c2ad2721 | 14 | using std::numeric_limits; |
8f4b34cc | 15 | using std::vector; |
c2ad2721 | 16 | using std::size_t; |
8f4b34cc JH |
17 | using std::string; |
18 | ||
0a6aabe7 | 19 | using serial::Serial; |
c2ad2721 JH |
20 | using serial::SerialExecption; |
21 | using serial::IOException; | |
0a6aabe7 JH |
22 | using serial::bytesize_t; |
23 | using serial::parity_t; | |
24 | using serial::stopbits_t; | |
25 | using serial::flowcontrol_t; | |
0a6aabe7 | 26 | |
c429b0ee WW |
27 | class Serial::ScopedReadLock { |
28 | public: | |
29 | ScopedReadLock(SerialImpl *pimpl) : pimpl_(pimpl) { | |
30 | this->pimpl_->readLock(); | |
31 | } | |
32 | ~ScopedReadLock() { | |
33 | this->pimpl_->readUnlock(); | |
34 | } | |
35 | private: | |
7714615a WW |
36 | // Disable copy constructors |
37 | ScopedReadLock(const ScopedReadLock&); | |
38 | void operator=(const ScopedReadLock&); | |
39 | const ScopedReadLock& operator=(ScopedReadLock); | |
40 | ||
c429b0ee WW |
41 | SerialImpl *pimpl_; |
42 | }; | |
43 | ||
44 | class Serial::ScopedWriteLock { | |
45 | public: | |
46 | ScopedWriteLock(SerialImpl *pimpl) : pimpl_(pimpl) { | |
47 | this->pimpl_->writeLock(); | |
48 | } | |
49 | ~ScopedWriteLock() { | |
50 | this->pimpl_->writeUnlock(); | |
51 | } | |
52 | private: | |
7714615a WW |
53 | // Disable copy constructors |
54 | ScopedWriteLock(const ScopedWriteLock&); | |
55 | void operator=(const ScopedWriteLock&); | |
56 | const ScopedWriteLock& operator=(ScopedWriteLock); | |
c429b0ee WW |
57 | SerialImpl *pimpl_; |
58 | }; | |
97630762 | 59 | |
6fac95d6 | 60 | Serial::Serial (const string &port, uint32_t baudrate, Timeout timeout, |
65fc8fb2 | 61 | bytesize_t bytesize, parity_t parity, stopbits_t stopbits, |
d8874120 JH |
62 | flowcontrol_t flowcontrol) |
63 | : read_cache_("") | |
c8e78412 | 64 | { |
8022c1b1 | 65 | pimpl_ = new SerialImpl (port, baudrate, bytesize, parity, |
65fc8fb2 | 66 | stopbits, flowcontrol); |
194169e5 | 67 | pimpl_->setTimeout(timeout); |
c8e78412 WW |
68 | } |
69 | ||
8f4b34cc JH |
70 | Serial::~Serial () |
71 | { | |
d8874120 | 72 | delete pimpl_; |
c8e78412 WW |
73 | } |
74 | ||
75 | void | |
8f4b34cc JH |
76 | Serial::open () |
77 | { | |
78 | pimpl_->open (); | |
c8e78412 WW |
79 | } |
80 | ||
81 | void | |
8f4b34cc JH |
82 | Serial::close () |
83 | { | |
84 | pimpl_->close (); | |
c8e78412 | 85 | } |
0046f3f6 | 86 | |
c8e78412 | 87 | bool |
8f4b34cc JH |
88 | Serial::isOpen () const |
89 | { | |
90 | return pimpl_->isOpen (); | |
c8e78412 WW |
91 | } |
92 | ||
93 | size_t | |
8f4b34cc JH |
94 | Serial::available () |
95 | { | |
96 | return pimpl_->available (); | |
c8e78412 WW |
97 | } |
98 | ||
29783866 | 99 | size_t |
6fac95d6 | 100 | Serial::read_ (uint8_t *buffer, size_t size) |
29783866 WW |
101 | { |
102 | return this->pimpl_->read (buffer, size); | |
103 | } | |
104 | ||
105 | size_t | |
6fac95d6 | 106 | Serial::read (uint8_t *buffer, size_t size) |
29783866 WW |
107 | { |
108 | ScopedReadLock (this->pimpl_); | |
109 | return this->pimpl_->read (buffer, size); | |
110 | } | |
111 | ||
112 | size_t | |
6fac95d6 | 113 | Serial::read (std::vector<uint8_t> &buffer, size_t size) |
29783866 WW |
114 | { |
115 | ScopedReadLock (this->pimpl_); | |
6fac95d6 | 116 | uint8_t *buffer_ = new uint8_t[size]; |
29783866 WW |
117 | size_t bytes_read = this->pimpl_->read (buffer_, size); |
118 | buffer.insert (buffer.end (), buffer_, buffer_+bytes_read); | |
119 | delete[] buffer_; | |
120 | return bytes_read; | |
121 | } | |
122 | ||
123 | size_t | |
124 | Serial::read (std::string &buffer, size_t size) | |
125 | { | |
126 | ScopedReadLock (this->pimpl_); | |
6fac95d6 | 127 | uint8_t *buffer_ = new uint8_t[size]; |
29783866 WW |
128 | size_t bytes_read = this->pimpl_->read (buffer_, size); |
129 | buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read); | |
130 | delete[] buffer_; | |
131 | return bytes_read; | |
132 | } | |
133 | ||
0a6aabe7 | 134 | string |
8f4b34cc JH |
135 | Serial::read (size_t size) |
136 | { | |
29783866 WW |
137 | std::string buffer; |
138 | this->read (buffer, size); | |
139 | return buffer; | |
140 | } | |
141 | ||
142 | size_t | |
143 | Serial::readline (string &buffer, size_t size, string eol) | |
144 | { | |
145 | ScopedReadLock (this->pimpl_); | |
9734f943 | 146 | size_t eol_len = eol.length (); |
6fac95d6 WW |
147 | uint8_t *buffer_ = static_cast<uint8_t*> |
148 | (alloca (size * sizeof (uint8_t))); | |
29783866 WW |
149 | size_t read_so_far = 0; |
150 | while (true) | |
8f4b34cc | 151 | { |
9734f943 | 152 | size_t bytes_read = this->read_ (buffer_ + read_so_far, 1); |
29783866 WW |
153 | read_so_far += bytes_read; |
154 | if (bytes_read == 0) { | |
155 | break; // Timeout occured on reading 1 byte | |
156 | } | |
9734f943 JH |
157 | if (string (reinterpret_cast<const char*> |
158 | (buffer_ + read_so_far - eol_len), eol_len) == eol) { | |
29783866 WW |
159 | break; // EOL found |
160 | } | |
161 | if (read_so_far == size) { | |
162 | break; // Reached the maximum read length | |
8f4b34cc | 163 | } |
8f4b34cc | 164 | } |
81fc77dd | 165 | buffer.append(reinterpret_cast<const char*> (buffer_), read_so_far); |
29783866 | 166 | return read_so_far; |
c8e78412 WW |
167 | } |
168 | ||
f14ac390 | 169 | string |
8f4b34cc JH |
170 | Serial::readline (size_t size, string eol) |
171 | { | |
29783866 WW |
172 | std::string buffer; |
173 | this->readline (buffer, size, eol); | |
174 | return buffer; | |
f14ac390 JH |
175 | } |
176 | ||
177 | vector<string> | |
29783866 | 178 | Serial::readlines (size_t size, string eol) |
8f4b34cc | 179 | { |
29783866 WW |
180 | ScopedReadLock (this->pimpl_); |
181 | std::vector<std::string> lines; | |
9734f943 | 182 | size_t eol_len = eol.length (); |
6fac95d6 WW |
183 | uint8_t *buffer_ = static_cast<uint8_t*> |
184 | (alloca (size * sizeof (uint8_t))); | |
29783866 WW |
185 | size_t read_so_far = 0; |
186 | size_t start_of_line = 0; | |
187 | while (read_so_far < size) { | |
188 | size_t bytes_read = this->read_ (buffer_+read_so_far, 1); | |
189 | read_so_far += bytes_read; | |
190 | if (bytes_read == 0) { | |
191 | if (start_of_line != read_so_far) { | |
9734f943 JH |
192 | lines.push_back ( |
193 | string (reinterpret_cast<const char*> (buffer_ + start_of_line), | |
194 | read_so_far - start_of_line)); | |
29783866 WW |
195 | } |
196 | break; // Timeout occured on reading 1 byte | |
197 | } | |
9734f943 JH |
198 | if (string (reinterpret_cast<const char*> |
199 | (buffer_ + read_so_far - eol_len), eol_len) == eol) { | |
29783866 WW |
200 | // EOL found |
201 | lines.push_back( | |
9734f943 JH |
202 | string(reinterpret_cast<const char*> (buffer_ + start_of_line), |
203 | read_so_far - start_of_line)); | |
29783866 WW |
204 | start_of_line = read_so_far; |
205 | } | |
206 | if (read_so_far == size) { | |
207 | if (start_of_line != read_so_far) { | |
208 | lines.push_back( | |
9734f943 JH |
209 | string(reinterpret_cast<const char*> (buffer_ + start_of_line), |
210 | read_so_far - start_of_line)); | |
29783866 WW |
211 | } |
212 | break; // Reached the maximum read length | |
f14ac390 | 213 | } |
f14ac390 | 214 | } |
f14ac390 | 215 | return lines; |
c8e78412 WW |
216 | } |
217 | ||
c8e78412 | 218 | size_t |
8f4b34cc JH |
219 | Serial::write (const string &data) |
220 | { | |
c429b0ee | 221 | ScopedWriteLock(this->pimpl_); |
6fac95d6 WW |
222 | return this->write_ (reinterpret_cast<const uint8_t*>(data.c_str()), |
223 | data.length()); | |
224 | } | |
225 | ||
226 | size_t | |
227 | Serial::write (const std::vector<uint8_t> &data) | |
228 | { | |
229 | ScopedWriteLock(this->pimpl_); | |
230 | return this->write_ (&data[0], data.size()); | |
231 | } | |
232 | ||
233 | size_t | |
234 | Serial::write (const uint8_t *data, size_t size) | |
235 | { | |
236 | ScopedWriteLock(this->pimpl_); | |
237 | return this->write_(data, size); | |
238 | } | |
239 | ||
240 | size_t | |
241 | Serial::write_ (const uint8_t *data, size_t length) | |
242 | { | |
243 | return pimpl_->write (data, length); | |
c8e78412 WW |
244 | } |
245 | ||
246 | void | |
8f4b34cc JH |
247 | Serial::setPort (const string &port) |
248 | { | |
c429b0ee WW |
249 | ScopedReadLock(this->pimpl_); |
250 | ScopedWriteLock(this->pimpl_); | |
9734f943 | 251 | bool was_open = pimpl_->isOpen (); |
8f4b34cc JH |
252 | if (was_open) close(); |
253 | pimpl_->setPort (port); | |
9734f943 | 254 | if (was_open) open (); |
c8e78412 WW |
255 | } |
256 | ||
0a6aabe7 | 257 | string |
8f4b34cc JH |
258 | Serial::getPort () const |
259 | { | |
260 | return pimpl_->getPort (); | |
c8e78412 WW |
261 | } |
262 | ||
263 | void | |
194169e5 | 264 | Serial::setTimeout (serial::Timeout &timeout) |
8f4b34cc JH |
265 | { |
266 | pimpl_->setTimeout (timeout); | |
c8e78412 WW |
267 | } |
268 | ||
194169e5 | 269 | serial::Timeout |
c8e78412 | 270 | Serial::getTimeout () const { |
8f4b34cc | 271 | return pimpl_->getTimeout (); |
c8e78412 WW |
272 | } |
273 | ||
274 | void | |
6fac95d6 | 275 | Serial::setBaudrate (uint32_t baudrate) |
8f4b34cc JH |
276 | { |
277 | pimpl_->setBaudrate (baudrate); | |
c8e78412 WW |
278 | } |
279 | ||
6fac95d6 | 280 | uint32_t |
8f4b34cc JH |
281 | Serial::getBaudrate () const |
282 | { | |
6fac95d6 | 283 | return uint32_t(pimpl_->getBaudrate ()); |
c8e78412 WW |
284 | } |
285 | ||
286 | void | |
8f4b34cc JH |
287 | Serial::setBytesize (bytesize_t bytesize) |
288 | { | |
289 | pimpl_->setBytesize (bytesize); | |
c8e78412 WW |
290 | } |
291 | ||
292 | bytesize_t | |
8f4b34cc JH |
293 | Serial::getBytesize () const |
294 | { | |
295 | return pimpl_->getBytesize (); | |
c8e78412 WW |
296 | } |
297 | ||
298 | void | |
8f4b34cc JH |
299 | Serial::setParity (parity_t parity) |
300 | { | |
301 | pimpl_->setParity (parity); | |
c8e78412 WW |
302 | } |
303 | ||
304 | parity_t | |
8f4b34cc JH |
305 | Serial::getParity () const |
306 | { | |
307 | return pimpl_->getParity (); | |
c8e78412 WW |
308 | } |
309 | ||
310 | void | |
8f4b34cc JH |
311 | Serial::setStopbits (stopbits_t stopbits) |
312 | { | |
313 | pimpl_->setStopbits (stopbits); | |
c8e78412 WW |
314 | } |
315 | ||
316 | stopbits_t | |
8f4b34cc JH |
317 | Serial::getStopbits () const |
318 | { | |
319 | return pimpl_->getStopbits (); | |
c8e78412 WW |
320 | } |
321 | ||
322 | void | |
8f4b34cc JH |
323 | Serial::setFlowcontrol (flowcontrol_t flowcontrol) |
324 | { | |
325 | pimpl_->setFlowcontrol (flowcontrol); | |
c8e78412 WW |
326 | } |
327 | ||
328 | flowcontrol_t | |
8f4b34cc JH |
329 | Serial::getFlowcontrol () const |
330 | { | |
331 | return pimpl_->getFlowcontrol (); | |
c8e78412 WW |
332 | } |
333 | ||
8f4b34cc JH |
334 | void Serial::flush () |
335 | { | |
c429b0ee WW |
336 | ScopedReadLock(this->pimpl_); |
337 | ScopedWriteLock(this->pimpl_); | |
8f4b34cc | 338 | pimpl_->flush (); |
d8874120 | 339 | read_cache_.clear (); |
11807e40 | 340 | } |
0046f3f6 | 341 | |
8f4b34cc JH |
342 | void Serial::flushInput () |
343 | { | |
c429b0ee | 344 | ScopedReadLock(this->pimpl_); |
8f4b34cc | 345 | pimpl_->flushInput (); |
11807e40 | 346 | } |
0046f3f6 | 347 | |
8f4b34cc JH |
348 | void Serial::flushOutput () |
349 | { | |
c429b0ee | 350 | ScopedWriteLock(this->pimpl_); |
8f4b34cc | 351 | pimpl_->flushOutput (); |
d8874120 | 352 | read_cache_.clear (); |
11807e40 | 353 | } |
0046f3f6 | 354 | |
8f4b34cc JH |
355 | void Serial::sendBreak (int duration) |
356 | { | |
357 | pimpl_->sendBreak (duration); | |
11807e40 | 358 | } |
0046f3f6 | 359 | |
8f4b34cc JH |
360 | void Serial::setBreak (bool level) |
361 | { | |
362 | pimpl_->setBreak (level); | |
11807e40 | 363 | } |
0046f3f6 | 364 | |
8f4b34cc JH |
365 | void Serial::setRTS (bool level) |
366 | { | |
367 | pimpl_->setRTS (level); | |
11807e40 | 368 | } |
0046f3f6 | 369 | |
8f4b34cc JH |
370 | void Serial::setDTR (bool level) |
371 | { | |
372 | pimpl_->setDTR (level); | |
11807e40 | 373 | } |
0046f3f6 | 374 | |
8022c1b1 WW |
375 | bool Serial::waitForChange() |
376 | { | |
377 | return pimpl_->waitForChange(); | |
378 | } | |
379 | ||
8f4b34cc JH |
380 | bool Serial::getCTS () |
381 | { | |
382 | return pimpl_->getCTS (); | |
11807e40 | 383 | } |
0046f3f6 | 384 | |
8f4b34cc JH |
385 | bool Serial::getDSR () |
386 | { | |
387 | return pimpl_->getDSR (); | |
11807e40 | 388 | } |
0046f3f6 | 389 | |
8f4b34cc JH |
390 | bool Serial::getRI () |
391 | { | |
392 | return pimpl_->getRI (); | |
11807e40 | 393 | } |
0046f3f6 | 394 | |
8f4b34cc JH |
395 | bool Serial::getCD () |
396 | { | |
397 | return pimpl_->getCD (); | |
11807e40 | 398 | } |