cec: bumped interface version to 4 stay in sync with the lib version. added changelog...
[deb_libcec.git] / src / lib / libPlatform / linux / serialport.cpp
1 /*
2 * boblight
3 * Copyright (C) Bob 2009
4 *
5 * boblight is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * boblight is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <iostream>//debug
20
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24
25 #include "../serialport.h"
26 #include "../baudrate.h"
27 #include "../../util/misc.h"
28 #include "../../util/timeutils.h"
29
30 using namespace std;
31
32 CSerialPort::CSerialPort()
33 {
34 m_fd = -1;
35 }
36
37 CSerialPort::~CSerialPort()
38 {
39 Close();
40 }
41
42 int CSerialPort::Write(uint8_t* data, int len)
43 {
44 fd_set port;
45
46 if (m_fd == -1)
47 {
48 m_error = "port closed";
49 return -1;
50 }
51
52 int byteswritten = 0;
53
54 while (byteswritten < len)
55 {
56 FD_ZERO(&port);
57 FD_SET(m_fd, &port);
58 int returnv = select(m_fd + 1, NULL, &port, NULL, NULL);
59 if (returnv == -1)
60 {
61 m_error = GetErrno();
62 return -1;
63 }
64
65 returnv = write(m_fd, data + byteswritten, len - byteswritten);
66 if (returnv == -1)
67 {
68 m_error = GetErrno();
69 return -1;
70 }
71 byteswritten += returnv;
72 }
73
74 //print what's written to stdout for debugging
75 // if (m_tostdout)
76 // {
77 // printf("%s write:", m_name.c_str());
78 // for (int i = 0; i < byteswritten; i++)
79 // printf(" %02x", (unsigned int)data[i]);
80
81 // printf("\n");
82 // }
83
84 return byteswritten;
85 }
86
87 int CSerialPort::Read(uint8_t* data, int len, int iTimeoutMs /*= -1*/)
88 {
89 fd_set port;
90 struct timeval timeout, *tv;
91 int64_t now, target;
92 int bytesread = 0;
93
94 if (m_fd == -1)
95 {
96 m_error = "port closed";
97 return -1;
98 }
99
100 if (iTimeoutMs >= 0)
101 {
102 now = GetTimeMs();
103 target = now + (int64_t) iTimeoutMs;
104 }
105
106 while (bytesread < len && (iTimeoutMs < 0 || target > now))
107 {
108 if (iTimeoutMs < 0)
109 {
110 tv = NULL;
111 }
112 else
113 {
114 timeout.tv_sec = ((long int)target - (long int)now) / (long int)1000.;
115 timeout.tv_usec = ((long int)target - (long int)now) % (long int)1000.;
116 tv = &timeout;
117 }
118
119 FD_ZERO(&port);
120 FD_SET(m_fd, &port);
121 int returnv = select(m_fd + 1, &port, NULL, NULL, tv);
122
123 if (returnv == -1)
124 {
125 m_error = GetErrno();
126 return -1;
127 }
128 else if (returnv == 0)
129 {
130 break; //nothing to read
131 }
132
133 returnv = read(m_fd, data + bytesread, len - bytesread);
134 if (returnv == -1)
135 {
136 m_error = GetErrno();
137 return -1;
138 }
139
140 bytesread += returnv;
141
142 if (iTimeoutMs > 0)
143 now = GetTimeMs();
144 }
145
146 //print what's read to stdout for debugging
147 // if (m_tostdout && bytesread > 0)
148 // {
149 // printf("%s read:", m_name.c_str());
150 // for (int i = 0; i < bytesread; i++)
151 // printf(" %02x", (unsigned int)data[i]);
152 //
153 // printf("\n");
154 // }
155
156 return bytesread;
157 }
158
159 //setting all this stuff up is a pain in the ass
160 bool CSerialPort::Open(string name, int baudrate, int databits/* = 8*/, int stopbits/* = 1*/, int parity/* = PAR_NONE*/)
161 {
162 m_name = name;
163 m_error = GetErrno();
164
165 if (databits < 5 || databits > 8)
166 {
167 m_error = "Databits has to be between 5 and 8";
168 return false;
169 }
170
171 if (stopbits != 1 && stopbits != 2)
172 {
173 m_error = "Stopbits has to be 1 or 2";
174 return false;
175 }
176
177 if (parity != PAR_NONE && parity != PAR_EVEN && parity != PAR_ODD)
178 {
179 m_error = "Parity has to be none, even or odd";
180 return false;
181 }
182
183 m_fd = open(name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
184
185 if (m_fd == -1)
186 {
187 m_error = GetErrno();
188 return false;
189 }
190
191 fcntl(m_fd, F_SETFL, 0);
192
193 if (!SetBaudRate(baudrate))
194 {
195 return false;
196 }
197
198 m_options.c_cflag |= (CLOCAL | CREAD);
199 m_options.c_cflag &= ~HUPCL;
200
201 m_options.c_cflag &= ~CSIZE;
202 if (databits == 5) m_options.c_cflag |= CS5;
203 if (databits == 6) m_options.c_cflag |= CS6;
204 if (databits == 7) m_options.c_cflag |= CS7;
205 if (databits == 8) m_options.c_cflag |= CS8;
206
207 m_options.c_cflag &= ~PARENB;
208 if (parity == PAR_EVEN || parity == PAR_ODD)
209 m_options.c_cflag |= PARENB;
210 if (parity == PAR_ODD)
211 m_options.c_cflag |= PARODD;
212
213 #ifdef CRTSCTS
214 m_options.c_cflag &= ~CRTSCTS;
215 #elif defined(CNEW_RTSCTS)
216 m_options.c_cflag &= ~CNEW_RTSCTS;
217 #endif
218
219 if (stopbits == 1) m_options.c_cflag &= ~CSTOPB;
220 else m_options.c_cflag |= CSTOPB;
221
222 //I guessed a little here
223 m_options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | XCASE | ECHOK | ECHONL | ECHOCTL | ECHOPRT | ECHOKE | TOSTOP);
224
225 if (parity == PAR_NONE)
226 {
227 m_options.c_iflag &= ~INPCK;
228 }
229 else
230 {
231 m_options.c_iflag |= INPCK | ISTRIP;
232 }
233
234 m_options.c_iflag &= ~(IXON | IXOFF | IXANY | BRKINT | INLCR | IGNCR | ICRNL | IUCLC | IMAXBEL);
235 m_options.c_oflag &= ~(OPOST | ONLCR | OCRNL);
236
237 if (tcsetattr(m_fd, TCSANOW, &m_options) != 0)
238 {
239 m_error = GetErrno();
240 return false;
241 }
242
243 //non-blocking port
244 fcntl(m_fd, F_SETFL, FNDELAY);
245
246 return true;
247 }
248
249 void CSerialPort::Close()
250 {
251 if (m_fd != -1)
252 {
253 close(m_fd);
254 m_fd = -1;
255 m_name = "";
256 m_error = "";
257 }
258 }
259
260 bool CSerialPort::SetBaudRate(int baudrate)
261 {
262 int rate = IntToRate(baudrate);
263 if (rate == -1)
264 {
265 char buff[255];
266 sprintf(buff, "%i is not a valid baudrate", baudrate);
267 m_error = buff;
268 return false;
269 }
270
271 //get the current port attributes
272 if (tcgetattr(m_fd, &m_options) != 0)
273 {
274 m_error = GetErrno();
275 return false;
276 }
277
278 if (cfsetispeed(&m_options, rate) != 0)
279 {
280 m_error = GetErrno();
281 return false;
282 }
283
284 if (cfsetospeed(&m_options, rate) != 0)
285 {
286 m_error = GetErrno();
287 return false;
288 }
289
290 return true;
291 }