]> git.zerfleddert.de Git - proxmark3-svn/blob - uart/uart_posix.c
e3113e86165276de6ce9aa408bc87573b0bf8d4f
[proxmark3-svn] / uart / uart_posix.c
1 /*
2 * Generic uart / rs232/ serial port library
3 *
4 * Copyright (c) 2013, Roel Verdult
5 * Copyright (c) 2018 Google
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the copyright holders nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * @file uart_posix.c
31 *
32 * This version of the library has functionality removed which was not used by
33 * proxmark3 project.
34 */
35
36 // Test if we are dealing with posix operating systems
37 #ifndef _WIN32
38 #define _DEFAULT_SOURCE
39
40 #include "uart.h"
41
42 #include <termios.h>
43 #include <sys/ioctl.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <limits.h>
49 #include <sys/time.h>
50 #include <errno.h>
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <netinet/tcp.h>
55 #include <arpa/inet.h>
56 #include <netdb.h>
57
58 typedef struct termios term_info;
59 typedef struct {
60 int fd; // Serial port file descriptor
61 term_info tiOld; // Terminal info before using the port
62 term_info tiNew; // Terminal info during the transaction
63 } serial_port_unix;
64
65 // Set time-out on 30 miliseconds
66 const struct timeval timeout = {
67 .tv_sec = 0, // 0 second
68 .tv_usec = 300000 // 300000 micro seconds
69 };
70
71 serial_port uart_open(const char* pcPortName)
72 {
73 serial_port_unix* sp = malloc(sizeof(serial_port_unix));
74 if (sp == 0) return INVALID_SERIAL_PORT;
75
76 if (memcmp(pcPortName, "tcp:", 4) == 0) {
77 struct addrinfo *addr, *rp;
78 char *addrstr = strdup(pcPortName + 4);
79 if (addrstr == NULL) {
80 printf("Error: strdup\n");
81 return INVALID_SERIAL_PORT;
82 }
83 char *colon = strrchr(addrstr, ':');
84 char *portstr;
85 if (colon) {
86 portstr = colon + 1;
87 *colon = '\0';
88 } else
89 portstr = "7901";
90
91 int s = getaddrinfo(addrstr, portstr, NULL, &addr);
92 if (s != 0) {
93 printf("Error: getaddrinfo: %s\n", gai_strerror(s));
94 return INVALID_SERIAL_PORT;
95 }
96
97 int sfd;
98 for (rp = addr; rp != NULL; rp = rp->ai_next) {
99 sfd = socket(rp->ai_family, rp->ai_socktype,
100 rp->ai_protocol);
101 if (sfd == -1)
102 continue;
103
104 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
105 break;
106
107 close(sfd);
108 }
109
110 if (rp == NULL) { /* No address succeeded */
111 printf("Error: Could not connect\n");
112 return INVALID_SERIAL_PORT;
113 }
114
115 freeaddrinfo(addr);
116 free(addrstr);
117
118 sp->fd = sfd;
119
120 int one = 1;
121 setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
122 return sp;
123 }
124
125 sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
126 if(sp->fd == -1) {
127 uart_close(sp);
128 return INVALID_SERIAL_PORT;
129 }
130
131 // Finally figured out a way to claim a serial port interface under unix
132 // We just try to set a (advisory) lock on the file descriptor
133 struct flock fl;
134 fl.l_type = F_WRLCK;
135 fl.l_whence = SEEK_SET;
136 fl.l_start = 0;
137 fl.l_len = 0;
138 fl.l_pid = getpid();
139
140 // Does the system allows us to place a lock on this file descriptor
141 if (fcntl(sp->fd, F_SETLK, &fl) == -1) {
142 // A conflicting lock is held by another process
143 free(sp);
144 return CLAIMED_SERIAL_PORT;
145 }
146
147 // Try to retrieve the old (current) terminal info struct
148 if(tcgetattr(sp->fd,&sp->tiOld) == -1) {
149 uart_close(sp);
150 return INVALID_SERIAL_PORT;
151 }
152
153 // Duplicate the (old) terminal info struct
154 sp->tiNew = sp->tiOld;
155
156 // Configure the serial port
157 sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
158 sp->tiNew.c_iflag = IGNPAR;
159 sp->tiNew.c_oflag = 0;
160 sp->tiNew.c_lflag = 0;
161
162 // Block until n bytes are received
163 sp->tiNew.c_cc[VMIN] = 0;
164 // Block until a timer expires (n * 100 mSec.)
165 sp->tiNew.c_cc[VTIME] = 0;
166
167 // Try to set the new terminal info struct
168 if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) {
169 uart_close(sp);
170 return INVALID_SERIAL_PORT;
171 }
172
173 // Flush all lingering data that may exist
174 tcflush(sp->fd, TCIOFLUSH);
175
176 return sp;
177 }
178
179 void uart_close(const serial_port sp) {
180 serial_port_unix* spu = (serial_port_unix*)sp;
181 tcflush(spu->fd,TCIOFLUSH);
182 tcsetattr(spu->fd,TCSANOW,&(spu->tiOld));
183 struct flock fl;
184 fl.l_type = F_UNLCK;
185 fl.l_whence = SEEK_SET;
186 fl.l_start = 0;
187 fl.l_len = 0;
188 fl.l_pid = getpid();
189 fcntl(spu->fd, F_SETLK, &fl);
190 close(spu->fd);
191 free(sp);
192 }
193
194 bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) {
195 int res;
196 int byteCount;
197 fd_set rfds;
198 struct timeval tv;
199
200 // Reset the output count
201 *pszRxLen = 0;
202
203 do {
204 // Reset file descriptor
205 FD_ZERO(&rfds);
206 FD_SET(((serial_port_unix*)sp)->fd,&rfds);
207 tv = timeout;
208 res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv);
209
210 // Read error
211 if (res < 0) {
212 return false;
213 }
214
215 // Read time-out
216 if (res == 0) {
217 if (*pszRxLen == 0) {
218 // Error, we received no data
219 return false;
220 } else {
221 // We received some data, but nothing more is available
222 return true;
223 }
224 }
225
226 // Retrieve the count of the incoming bytes
227 res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
228 if (res < 0) return false;
229
230 // Cap the number of bytes, so we don't overrun the buffer
231 if (pszMaxRxLen - (*pszRxLen) < byteCount) {
232 byteCount = pszMaxRxLen - (*pszRxLen);
233 }
234
235 // There is something available, read the data
236 res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount);
237
238 // Stop if the OS has some troubles reading the data
239 if (res <= 0) return false;
240
241 *pszRxLen += res;
242
243 if (*pszRxLen == pszMaxRxLen) {
244 // We have all the data we wanted.
245 return true;
246 }
247
248 } while (byteCount);
249
250 return true;
251 }
252
253 bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) {
254 int32_t res;
255 size_t szPos = 0;
256 fd_set rfds;
257 struct timeval tv;
258
259 while (szPos < szTxLen) {
260 // Reset file descriptor
261 FD_ZERO(&rfds);
262 FD_SET(((serial_port_unix*)sp)->fd,&rfds);
263 tv = timeout;
264 res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv);
265
266 // Write error
267 if (res < 0) {
268 return false;
269 }
270
271 // Write time-out
272 if (res == 0) {
273 return false;
274 }
275
276 // Send away the bytes
277 res = write(((serial_port_unix*)sp)->fd,pbtTx+szPos,szTxLen-szPos);
278
279 // Stop if the OS has some troubles sending the data
280 if (res <= 0) return false;
281
282 szPos += res;
283 }
284 return true;
285 }
286
287 bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
288 const serial_port_unix* spu = (serial_port_unix*)sp;
289 speed_t stPortSpeed;
290 switch (uiPortSpeed) {
291 case 0: stPortSpeed = B0; break;
292 case 50: stPortSpeed = B50; break;
293 case 75: stPortSpeed = B75; break;
294 case 110: stPortSpeed = B110; break;
295 case 134: stPortSpeed = B134; break;
296 case 150: stPortSpeed = B150; break;
297 case 300: stPortSpeed = B300; break;
298 case 600: stPortSpeed = B600; break;
299 case 1200: stPortSpeed = B1200; break;
300 case 1800: stPortSpeed = B1800; break;
301 case 2400: stPortSpeed = B2400; break;
302 case 4800: stPortSpeed = B4800; break;
303 case 9600: stPortSpeed = B9600; break;
304 case 19200: stPortSpeed = B19200; break;
305 case 38400: stPortSpeed = B38400; break;
306 # ifdef B57600
307 case 57600: stPortSpeed = B57600; break;
308 # endif
309 # ifdef B115200
310 case 115200: stPortSpeed = B115200; break;
311 # endif
312 # ifdef B230400
313 case 230400: stPortSpeed = B230400; break;
314 # endif
315 # ifdef B460800
316 case 460800: stPortSpeed = B460800; break;
317 # endif
318 # ifdef B921600
319 case 921600: stPortSpeed = B921600; break;
320 # endif
321 default: return false;
322 };
323 struct termios ti;
324 if (tcgetattr(spu->fd,&ti) == -1) return false;
325 // Set port speed (Input and Output)
326 cfsetispeed(&ti,stPortSpeed);
327 cfsetospeed(&ti,stPortSpeed);
328 return (tcsetattr(spu->fd,TCSANOW,&ti) != -1);
329 }
330
331 uint32_t uart_get_speed(const serial_port sp) {
332 struct termios ti;
333 uint32_t uiPortSpeed;
334 const serial_port_unix* spu = (serial_port_unix*)sp;
335 if (tcgetattr(spu->fd,&ti) == -1) return 0;
336 // Set port speed (Input)
337 speed_t stPortSpeed = cfgetispeed(&ti);
338 switch (stPortSpeed) {
339 case B0: uiPortSpeed = 0; break;
340 case B50: uiPortSpeed = 50; break;
341 case B75: uiPortSpeed = 75; break;
342 case B110: uiPortSpeed = 110; break;
343 case B134: uiPortSpeed = 134; break;
344 case B150: uiPortSpeed = 150; break;
345 case B300: uiPortSpeed = 300; break;
346 case B600: uiPortSpeed = 600; break;
347 case B1200: uiPortSpeed = 1200; break;
348 case B1800: uiPortSpeed = 1800; break;
349 case B2400: uiPortSpeed = 2400; break;
350 case B4800: uiPortSpeed = 4800; break;
351 case B9600: uiPortSpeed = 9600; break;
352 case B19200: uiPortSpeed = 19200; break;
353 case B38400: uiPortSpeed = 38400; break;
354 # ifdef B57600
355 case B57600: uiPortSpeed = 57600; break;
356 # endif
357 # ifdef B115200
358 case B115200: uiPortSpeed = 115200; break;
359 # endif
360 # ifdef B230400
361 case B230400: uiPortSpeed = 230400; break;
362 # endif
363 # ifdef B460800
364 case B460800: uiPortSpeed = 460800; break;
365 # endif
366 # ifdef B921600
367 case B921600: uiPortSpeed = 921600; break;
368 # endif
369 default: return 0;
370 };
371 return uiPortSpeed;
372 }
373
374 #endif
375
Impressum, Datenschutz