]>
git.zerfleddert.de Git - proxmark3-svn/blob - uart/uart_posix.c
f6e6519de885472ff5f138a0cca29ab59d86bd47
2 * Generic uart / rs232/ serial port library
4 * Copyright (c) 2013, Roel Verdult
5 * Copyright (c) 2018 Google
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.
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.
32 * This version of the library has functionality removed which was not used by
36 // Test if we are dealing with posix operating systems
38 #define _DEFAULT_SOURCE
47 #include <sys/ioctl.h>
50 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <netinet/tcp.h>
58 // Fix missing definition on OS X.
59 // Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7
61 #define SOL_TCP IPPROTO_TCP
64 typedef struct termios term_info
;
66 int fd
; // Serial port file descriptor
67 term_info tiOld
; // Terminal info before using the port
68 term_info tiNew
; // Terminal info during the transaction
71 // Set time-out on 30 miliseconds
72 static struct timeval timeout
= {
73 .tv_sec
= 0, // 0 second
74 .tv_usec
= 30000 // 30000 micro seconds
78 void uart_close(const serial_port sp
) {
79 serial_port_unix
* spu
= (serial_port_unix
*)sp
;
80 tcflush(spu
->fd
, TCIOFLUSH
);
81 tcsetattr(spu
->fd
, TCSANOW
, &(spu
->tiOld
));
84 fl
.l_whence
= SEEK_SET
;
88 fcntl(spu
->fd
, F_SETLK
, &fl
);
94 serial_port
uart_open(const char* pcPortName
) {
96 serial_port_unix
* sp
= malloc(sizeof(serial_port_unix
));
97 if (sp
== 0) return INVALID_SERIAL_PORT
;
99 if (memcmp(pcPortName
, "tcp:", 4) == 0) {
100 struct addrinfo
*addr
= NULL
, *rp
;
101 char *addrstr
= strdup(pcPortName
+ 4);
102 if (addrstr
== NULL
) {
103 printf("Error: strdup\n");
104 return INVALID_SERIAL_PORT
;
106 char *colon
= strrchr(addrstr
, ':');
109 // Set time-out to 300 milliseconds only for TCP port
110 timeout
.tv_usec
= 300000;
119 struct addrinfo info
;
121 memset(&info
, 0, sizeof(info
));
123 info
.ai_socktype
= SOCK_STREAM
;
125 int s
= getaddrinfo(addrstr
, portstr
, &info
, &addr
);
127 printf("Error: getaddrinfo: %s\n", gai_strerror(s
));
128 return INVALID_SERIAL_PORT
;
132 for (rp
= addr
; rp
!= NULL
; rp
= rp
->ai_next
) {
133 sfd
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
);
136 if (connect(sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
141 if (rp
== NULL
) { /* No address succeeded */
142 printf("Error: Could not connect\n");
143 return INVALID_SERIAL_PORT
;
152 setsockopt(sp
->fd
, SOL_TCP
, TCP_NODELAY
, &one
, sizeof(one
));
156 sp
->fd
= open(pcPortName
, O_RDWR
| O_NOCTTY
| O_NDELAY
| O_NONBLOCK
);
159 return INVALID_SERIAL_PORT
;
162 // Finally figured out a way to claim a serial port interface under unix
163 // We just try to set a (advisory) lock on the file descriptor
166 fl
.l_whence
= SEEK_SET
;
171 // Does the system allows us to place a lock on this file descriptor
172 if (fcntl(sp
->fd
, F_SETLK
, &fl
) == -1) {
173 // A conflicting lock is held by another process
175 return CLAIMED_SERIAL_PORT
;
178 // Try to retrieve the old (current) terminal info struct
179 if (tcgetattr(sp
->fd
,&sp
->tiOld
) == -1) {
181 return INVALID_SERIAL_PORT
;
184 // Duplicate the (old) terminal info struct
185 sp
->tiNew
= sp
->tiOld
;
187 // Configure the serial port
188 sp
->tiNew
.c_cflag
&= ~(CSIZE
| PARENB
);
189 sp
->tiNew
.c_cflag
|= (CS8
| CLOCAL
| CREAD
);
190 sp
->tiNew
.c_iflag
&= ~(IGNBRK
| BRKINT
| PARMRK
| ISTRIP
| INLCR
| IGNCR
| ICRNL
| IXON
);
191 sp
->tiNew
.c_iflag
|= IGNPAR
;
192 sp
->tiNew
.c_oflag
&= ~OPOST
;
193 sp
->tiNew
.c_lflag
&= ~(ECHO
| ECHONL
| ICANON
| ISIG
| IEXTEN
);
196 // Try to set the new terminal info struct
197 if (tcsetattr(sp
->fd
, TCSANOW
, &sp
->tiNew
) == -1) {
199 return INVALID_SERIAL_PORT
;
202 // Flush all lingering data that may exist
203 tcflush(sp
->fd
, TCIOFLUSH
);
209 bool uart_receive(const serial_port sp
, uint8_t* pbtRx
, size_t szMaxRxLen
, size_t* pszRxLen
) {
213 if (szMaxRxLen
== 0) return true;
215 struct timeval t_current
;
216 gettimeofday(&t_current
, NULL
);
217 struct timeval t_end
;
218 timeradd(&t_current
, &timeout
, &t_end
);
221 int res
= read(((serial_port_unix
*)sp
)->fd
, pbtRx
, szMaxRxLen
- *pszRxLen
);
222 if (res
< 0 && errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) return false;
227 if (*pszRxLen
== szMaxRxLen
) return true; // we could read all requested bytes in time
228 gettimeofday(&t_current
, NULL
);
229 if (timercmp(&t_current
, &t_end
, >)) return true; // timeout
230 // set next select timeout
231 struct timeval t_remains
;
232 timersub(&t_end
, &t_current
, &t_remains
);
233 // Set the file descriptor set
236 FD_SET(((serial_port_unix
*)sp
)->fd
, &rfds
);
237 // wait for more bytes available
238 res
= select(((serial_port_unix
*)sp
)->fd
+1, &rfds
, NULL
, NULL
, &t_remains
);
239 if (res
< 0) return false;
240 if (res
== 0) return true; // timeout
242 return true; // should never come here
246 bool uart_send(const serial_port sp
, const uint8_t* pbtTx
, const size_t szTxLen
) {
248 if (szTxLen
== 0) return true;
250 size_t bytes_written
= 0;
252 struct timeval t_current
;
253 gettimeofday(&t_current
, NULL
);
254 struct timeval t_end
;
255 timeradd(&t_current
, &timeout
, &t_end
);
258 int res
= write(((serial_port_unix
*)sp
)->fd
, pbtTx
, szTxLen
- bytes_written
);
259 if (res
< 0 && res
!= EAGAIN
&& res
!= EWOULDBLOCK
) return false;
262 bytes_written
+= res
;
264 if (bytes_written
== szTxLen
) return true; // we could write all bytes
265 gettimeofday(&t_current
, NULL
);
266 if (timercmp(&t_current
, &t_end
, >)) return false; // timeout
267 // set next select timeout
268 struct timeval t_remains
;
269 timersub(&t_end
, &t_current
, &t_remains
);
270 // Set the file descriptor set
273 FD_SET(((serial_port_unix
*)sp
)->fd
, &wfds
);
274 // wait until more bytes can be written
275 res
= select(((serial_port_unix
*)sp
)->fd
+1, NULL
, &wfds
, NULL
, &t_remains
);
276 if (res
< 0) return false; // error
277 if (res
== 0) return false; // timeout
283 bool uart_set_speed(serial_port sp
, const uint32_t uiPortSpeed
) {
284 const serial_port_unix
* spu
= (serial_port_unix
*)sp
;
286 switch (uiPortSpeed
) {
287 case 0: stPortSpeed
= B0
; break;
288 case 50: stPortSpeed
= B50
; break;
289 case 75: stPortSpeed
= B75
; break;
290 case 110: stPortSpeed
= B110
; break;
291 case 134: stPortSpeed
= B134
; break;
292 case 150: stPortSpeed
= B150
; break;
293 case 300: stPortSpeed
= B300
; break;
294 case 600: stPortSpeed
= B600
; break;
295 case 1200: stPortSpeed
= B1200
; break;
296 case 1800: stPortSpeed
= B1800
; break;
297 case 2400: stPortSpeed
= B2400
; break;
298 case 4800: stPortSpeed
= B4800
; break;
299 case 9600: stPortSpeed
= B9600
; break;
300 case 19200: stPortSpeed
= B19200
; break;
301 case 38400: stPortSpeed
= B38400
; break;
303 case 57600: stPortSpeed
= B57600
; break;
306 case 115200: stPortSpeed
= B115200
; break;
309 case 230400: stPortSpeed
= B230400
; break;
312 case 460800: stPortSpeed
= B460800
; break;
315 case 921600: stPortSpeed
= B921600
; break;
317 default: return false;
320 if (tcgetattr(spu
->fd
, &ti
) == -1) return false;
321 // Set port speed (Input and Output)
322 cfsetispeed(&ti
,stPortSpeed
);
323 cfsetospeed(&ti
,stPortSpeed
);
324 return (tcsetattr(spu
->fd
, TCSANOW
, &ti
) != -1);
327 uint32_t uart_get_speed(const serial_port sp
) {
329 uint32_t uiPortSpeed
;
330 const serial_port_unix
* spu
= (serial_port_unix
*)sp
;
331 if (tcgetattr(spu
->fd
, &ti
) == -1) return 0;
332 // Set port speed (Input)
333 speed_t stPortSpeed
= cfgetispeed(&ti
);
334 switch (stPortSpeed
) {
335 case B0
: uiPortSpeed
= 0; break;
336 case B50
: uiPortSpeed
= 50; break;
337 case B75
: uiPortSpeed
= 75; break;
338 case B110
: uiPortSpeed
= 110; break;
339 case B134
: uiPortSpeed
= 134; break;
340 case B150
: uiPortSpeed
= 150; break;
341 case B300
: uiPortSpeed
= 300; break;
342 case B600
: uiPortSpeed
= 600; break;
343 case B1200
: uiPortSpeed
= 1200; break;
344 case B1800
: uiPortSpeed
= 1800; break;
345 case B2400
: uiPortSpeed
= 2400; break;
346 case B4800
: uiPortSpeed
= 4800; break;
347 case B9600
: uiPortSpeed
= 9600; break;
348 case B19200
: uiPortSpeed
= 19200; break;
349 case B38400
: uiPortSpeed
= 38400; break;
351 case B57600
: uiPortSpeed
= 57600; break;
354 case B115200
: uiPortSpeed
= 115200; break;
357 case B230400
: uiPortSpeed
= 230400; break;
360 case B460800
: uiPortSpeed
= 460800; break;
363 case B921600
: uiPortSpeed
= 921600; break;