]> Git Repo - serial.git/blame - src/impl/unix.cc
Fixed some memory problems on destruction. Serial listener maybe working, serial...
[serial.git] / src / impl / unix.cc
CommitLineData
0a6aabe7
JH
1#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <fcntl.h>
5#include <sys/ioctl.h>
6#include <errno.h>
7#include <paths.h>
8#include <sysexits.h>
9#include <termios.h>
10#include <sys/param.h>
11#include <sys/select.h>
12#include <sys/time.h>
13#include <time.h>
14
18284ae7
WW
15#include "serial/impl/unix.h"
16
0a6aabe7
JH
17#ifndef TIOCINQ
18#ifdef FIONREAD
19#define TIOCINQ FIONREAD
20#else
21#define TIOCINQ 0x541B
22#endif
23#endif
24
48a30ec4
WW
25class UnhandledException : public std::exception {
26 const char * e_what;
27public:
28 UnhandledException(const char * e_what) {this->e_what = e_what;}
29
30 virtual const char* what() const throw() {
31 std::stringstream ss;
32 ss << "Unhandled Exception: " << this->e_what;
33 return ss.str().c_str();
34 }
35};
36
37typedef UnhandledException e;
38
0a6aabe7
JH
39using ::serial::Serial;
40using std::string;
18284ae7 41
0a6aabe7 42Serial::SerialImpl::SerialImpl (const string &port, int baudrate,
65fc8fb2
WW
43 long timeout, bytesize_t bytesize,
44 parity_t parity, stopbits_t stopbits,
45 flowcontrol_t flowcontrol)
46: fd_(-1), isOpen_(false), interCharTimeout_(-1), port_(port),
47 baudrate_(baudrate), timeout_(timeout), bytesize_(bytesize),
48 parity_(parity), stopbits_(stopbits), flowcontrol_(flowcontrol)
18284ae7 49{
65fc8fb2 50 if (port_.empty() == false) this->open();
18284ae7
WW
51}
52
0a6aabe7
JH
53Serial::SerialImpl::~SerialImpl () {
54 this->close();
18284ae7
WW
55}
56
57void
0a6aabe7 58Serial::SerialImpl::open () {
48a30ec4
WW
59 if (port_.empty() == true) throw e("error");
60 if (isOpen_ == true) throw e("error");
61
65fc8fb2 62 fd_ = ::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
48a30ec4 63
65fc8fb2 64 if (fd_ == -1) throw "Error";
48a30ec4 65
65fc8fb2
WW
66 reconfigurePort();
67 isOpen_ = true;
18284ae7
WW
68}
69
70void
0a6aabe7 71Serial::SerialImpl::reconfigurePort () {
48a30ec4 72 if (fd_ == -1) throw e("Error"); // Can only operate on a valid file descriptor
65fc8fb2
WW
73
74 struct termios options; // The current options for the file descriptor
75 struct termios originalTTYAttrs; // The orignal file descriptor options
76
0a6aabe7
JH
77 uint8_t vmin = 0, vtime = 0; // timeout is done via select
78 if (interCharTimeout_ == -1) {
65fc8fb2
WW
79 vmin = 1;
80 vtime = int(interCharTimeout_ * 10);
81 }
82
48a30ec4 83 if (tcgetattr(fd_, &originalTTYAttrs) == -1) throw e("Error");
65fc8fb2
WW
84
85 options = originalTTYAttrs;
86
0a6aabe7
JH
87 // set up raw mode / no echo / binary
88 options.c_cflag |= (CLOCAL|CREAD);
89 options.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|
90 ISIG|IEXTEN); //|ECHOPRT
91
92 options.c_oflag &= ~(OPOST);
93 options.c_iflag &= ~(INLCR|IGNCR|ICRNL|IGNBRK);
94#ifdef IUCLC
95 options.c_iflag &= ~IUCLC;
96#endif
97#ifdef PARMRK
65fc8fb2 98 options.c_iflag &= ~PARMRK;
0a6aabe7
JH
99#endif
100
101 // setup baud rate
65fc8fb2
WW
102 // TODO(ash_git): validate baud rate
103 cfsetspeed(&options, baudrate_);
0a6aabe7
JH
104
105 // setup char len
106 options.c_cflag &= ~CSIZE;
107 if (bytesize_ == EIGHTBITS)
108 options.c_cflag |= CS8;
109 else if (bytesize_ == SEVENBITS)
110 options.c_cflag |= CS7;
111 else if (bytesize_ == SIXBITS)
112 options.c_cflag |= CS6;
113 else if (bytesize_ == FIVEBITS)
114 options.c_cflag |= CS5;
115 else
48a30ec4 116 throw e("ValueError(Invalid char len: %%r)");
0a6aabe7
JH
117 // setup stopbits
118 if (stopbits_ == STOPBITS_ONE)
119 options.c_cflag &= ~(CSTOPB);
120 else if (stopbits_ == STOPBITS_ONE_POINT_FIVE)
121 options.c_cflag |= (CSTOPB); // XXX same as TWO.. there is no POSIX support for 1.5
122 else if (stopbits_ == STOPBITS_TWO)
123 options.c_cflag |= (CSTOPB);
65fc8fb2 124 else
48a30ec4 125 throw e("ValueError(Invalid stop bit specification:)");
0a6aabe7
JH
126 // setup parity
127 options.c_iflag &= ~(INPCK|ISTRIP);
128 if (parity_ == PARITY_NONE) {
129 options.c_cflag &= ~(PARENB|PARODD);
130 }
65fc8fb2 131 else if (parity_ == PARITY_EVEN) {
0a6aabe7
JH
132 options.c_cflag &= ~(PARODD);
133 options.c_cflag |= (PARENB);
134 }
65fc8fb2 135 else if (parity_ == PARITY_ODD) {
0a6aabe7
JH
136 options.c_cflag |= (PARENB|PARODD);
137 }
65fc8fb2 138 else {
48a30ec4 139 throw e("ValueError(Invalid parity:");
65fc8fb2 140 }
0a6aabe7
JH
141 // setup flow control
142 // xonxoff
143#ifdef IXANY
144 if (xonxoff_)
145 options.c_iflag |= (IXON|IXOFF); //|IXANY)
146 else
147 options.c_iflag &= ~(IXON|IXOFF|IXANY);
148#else
149 if (xonxoff_)
150 options.c_iflag |= (IXON|IXOFF);
151 else
152 options.c_iflag &= ~(IXON|IXOFF);
153#endif
154 // rtscts
155#ifdef CRTSCTS
156 if (rtscts_)
157 options.c_cflag |= (CRTSCTS);
158 else
159 options.c_cflag &= ~(CRTSCTS);
160#elif defined CNEW_RTSCTS
161 if (rtscts_)
65fc8fb2 162 options.c_cflag |= (CNEW_RTSCTS);
0a6aabe7
JH
163 else
164 options.c_cflag &= ~(CNEW_RTSCTS);
165#else
166#error "OS Support seems wrong."
167#endif
168
169 // buffer
170 // vmin "minimal number of characters to be read. = for non blocking"
171 options.c_cc[VMIN] = vmin;
172 // vtime
173 options.c_cc[VTIME] = vtime;
174
175 // activate settings
65fc8fb2 176 ::tcsetattr(fd_, TCSANOW, &options);
18284ae7
WW
177}
178
0a6aabe7
JH
179void
180Serial::SerialImpl::close () {
65fc8fb2
WW
181 if (isOpen_ == true) {
182 if (fd_ != -1) {
183 ::close(fd_);
184 fd_ = -1;
185 }
186 isOpen_ = false;
187 }
18284ae7
WW
188}
189
0a6aabe7
JH
190bool
191Serial::SerialImpl::isOpen () {
192 return isOpen_;
18284ae7
WW
193}
194
195size_t
0a6aabe7 196Serial::SerialImpl::available () {
65fc8fb2
WW
197 if (!isOpen_) {
198 return 0;
199 }
200 int count = 0;
201 int result = ioctl(fd_, TIOCINQ, &count);
202 if (result == 0) {
203 return count;
204 } else {
48a30ec4 205 throw e("Error");
65fc8fb2 206 }
18284ae7
WW
207}
208
0a6aabe7
JH
209string
210Serial::SerialImpl::read (size_t size) {
48a30ec4 211 if (!isOpen_) throw e("PortNotOpenError()");
65fc8fb2
WW
212 string message = "";
213 char buf[1024];
214 fd_set readfds;
0a6aabe7 215 while (message.length() < size) {
65fc8fb2
WW
216 FD_ZERO(&readfds);
217 FD_SET(fd_, &readfds);
218 struct timeval timeout;
219 timeout.tv_sec = timeout_ / 1000;
220 timeout.tv_usec = timeout_ % 1000;
221 int r = select(1, &readfds, NULL, NULL, &timeout);
222
223 if (r == -1 && errno == EINTR)
224 continue;
225
226 if (r == -1) {
0a6aabe7
JH
227 perror("select()");
228 exit(EXIT_FAILURE);
229 }
230
231 if (FD_ISSET(fd_, &readfds)) {
65fc8fb2
WW
232 memset(buf, 0, 1024);
233 size_t bytes_read = ::read(fd_, buf, 1024);
234 // read should always return some data as select reported it was
235 // ready to read when we get to this point.
236 if (bytes_read < 1) {
237 // Disconnected devices, at least on Linux, show the
238 // behavior that they are always ready to read immediately
239 // but reading returns nothing.
48a30ec4 240 throw e("SerialException('device reports readiness to read but returned no data (device disconnected?)')");
65fc8fb2
WW
241 }
242 message.append(buf, bytes_read);
243 }
244 else {
245 break; // Timeout
246 }
247 }
0a6aabe7 248 return message;
18284ae7
WW
249}
250
251size_t
0a6aabe7 252Serial::SerialImpl::write (const string &data) {
48a30ec4 253 if (isOpen_ == false) throw e("portNotOpenError");
65fc8fb2 254
f14ac390 255 size_t t = data.length();
65fc8fb2
WW
256 size_t n = ::write(fd_, data.c_str(), data.length());
257 if (n == -1) {
48a30ec4 258 throw e("Write error");
65fc8fb2 259 }
f14ac390 260 return n;
18284ae7
WW
261}
262
263void
0a6aabe7
JH
264Serial::SerialImpl::setPort (const string &port) {
265 port_ = port;
18284ae7
WW
266}
267
0a6aabe7
JH
268string
269Serial::SerialImpl::getPort () const {
270 return port_;
18284ae7
WW
271}
272
273void
0a6aabe7 274Serial::SerialImpl::setTimeout (long timeout) {
f14ac390 275 timeout_ = timeout;
18284ae7
WW
276}
277
278long
0a6aabe7 279Serial::SerialImpl::getTimeout () const {
f14ac390 280 return timeout_;
18284ae7
WW
281}
282
283void
0a6aabe7 284Serial::SerialImpl::setBaudrate (int baudrate) {
65fc8fb2
WW
285 baudrate_ = baudrate;
286 reconfigurePort();
18284ae7
WW
287}
288
289int
0a6aabe7
JH
290Serial::SerialImpl::getBaudrate () const {
291 return baudrate_;
18284ae7
WW
292}
293
294void
0a6aabe7 295Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize) {
65fc8fb2 296 bytesize_ = bytesize;
18284ae7
WW
297}
298
0a6aabe7
JH
299serial::bytesize_t
300Serial::SerialImpl::getBytesize () const {
f14ac390 301 return bytesize_;
18284ae7
WW
302}
303
304void
0a6aabe7 305Serial::SerialImpl::setParity (serial::parity_t parity) {
f14ac390 306 parity_ = parity;
18284ae7
WW
307}
308
0a6aabe7
JH
309serial::parity_t
310Serial::SerialImpl::getParity () const {
f14ac390 311 return parity_;
18284ae7
WW
312}
313
314void
0a6aabe7 315Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits) {
f14ac390 316 stopbits_ = stopbits;
18284ae7
WW
317}
318
0a6aabe7
JH
319serial::stopbits_t
320Serial::SerialImpl::getStopbits () const {
f14ac390 321 return stopbits_;
18284ae7
WW
322}
323
324void
0a6aabe7 325Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol) {
f14ac390 326 flowcontrol_ = flowcontrol;
18284ae7
WW
327}
328
0a6aabe7
JH
329serial::flowcontrol_t
330Serial::SerialImpl::getFlowcontrol () const {
f14ac390 331 return flowcontrol_;
18284ae7
WW
332}
333
334
335
336
337
338
This page took 0.063544 seconds and 4 git commands to generate.