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
46 #include <sys/ioctl.h>
49 #include <netinet/tcp.h>
51 #include <sys/socket.h>
55 #include <bluetooth/bluetooth.h>
56 #include <bluetooth/rfcomm.h>
62 // Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7
64 # define SOL_TCP IPPROTO_TCP
67 typedef struct termios term_info
;
69 int fd
; // Serial port file descriptor
70 term_info tiOld
; // Terminal info before using the port
71 term_info tiNew
; // Terminal info during the transaction
75 struct timeval timeout
= {
76 .tv_sec
= 0, // 0 second
77 .tv_usec
= UART_FPC_CLIENT_RX_TIMEOUT_MS
* 1000
80 static uint32_t newtimeout_value
= 0;
81 static bool newtimeout_pending
= false;
83 int uart_reconfigure_timeouts(uint32_t value
) {
84 newtimeout_value
= value
;
85 newtimeout_pending
= true;
89 serial_port
uart_open(const char *pcPortName
, uint32_t speed
) {
90 serial_port_unix
*sp
= calloc(sizeof(serial_port_unix
), sizeof(uint8_t));
93 PrintAndLogEx(ERR
, "UART failed to allocate memory");
94 return INVALID_SERIAL_PORT
;
98 timeout
.tv_usec
= UART_FPC_CLIENT_RX_TIMEOUT_MS
* 1000;
100 char *prefix
= strdup(pcPortName
);
101 if (prefix
== NULL
) {
102 PrintAndLogEx(ERR
, "error: malloc");
104 return INVALID_SERIAL_PORT
;
108 if (memcmp(prefix
, "tcp:", 4) == 0) {
111 if (strlen(pcPortName
) <= 4) {
113 return INVALID_SERIAL_PORT
;
116 struct addrinfo
*addr
= NULL
, *rp
;
118 char *addrstr
= strdup(pcPortName
+ 4);
119 if (addrstr
== NULL
) {
120 PrintAndLogEx(ERR
, "error: malloc");
122 return INVALID_SERIAL_PORT
;
125 timeout
.tv_usec
= UART_TCP_CLIENT_RX_TIMEOUT_MS
* 1000;
127 char *colon
= strrchr(addrstr
, ':');
136 struct addrinfo info
;
138 memset(&info
, 0, sizeof(info
));
140 info
.ai_socktype
= SOCK_STREAM
;
142 int s
= getaddrinfo(addrstr
, portstr
, &info
, &addr
);
144 PrintAndLogEx(ERR
, "error: getaddrinfo: %s", gai_strerror(s
));
148 return INVALID_SERIAL_PORT
;
152 for (rp
= addr
; rp
!= NULL
; rp
= rp
->ai_next
) {
153 sfd
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
);
158 if (connect(sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
164 if (rp
== NULL
) { /* No address succeeded */
165 PrintAndLogEx(ERR
, "error: Could not connect");
169 return INVALID_SERIAL_PORT
;
178 int res
= setsockopt(sp
->fd
, SOL_TCP
, TCP_NODELAY
, &one
, sizeof(one
));
181 return INVALID_SERIAL_PORT
;
186 if (memcmp(prefix
, "bt:", 3) == 0) {
190 if (strlen(pcPortName
) != 20) {
192 return INVALID_SERIAL_PORT
;
195 char *addrstr
= strndup(pcPortName
+ 3, 17);
196 if (addrstr
== NULL
) {
197 PrintAndLogEx(ERR
, "error: malloc");
199 return INVALID_SERIAL_PORT
;
202 struct sockaddr_rc addr
= { 0 };
203 addr
.rc_family
= AF_BLUETOOTH
;
204 addr
.rc_channel
= (uint8_t) 1;
205 if (str2ba(addrstr
, &addr
.rc_bdaddr
) != 0) {
206 PrintAndLogEx(ERR
, "Invalid Bluetooth MAC address " _RED_("%s"), addrstr
);
209 return INVALID_SERIAL_PORT
;
211 int sfd
= socket(AF_BLUETOOTH
, SOCK_STREAM
, BTPROTO_RFCOMM
);
213 PrintAndLogEx(ERR
, "Error opening Bluetooth socket");
216 return INVALID_SERIAL_PORT
;
218 if (connect(sfd
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1) {
219 PrintAndLogEx(ERR
, "Error: cannot connect device " _YELLOW_("%s") " over Bluetooth", addrstr
);
223 return INVALID_SERIAL_PORT
;
229 PrintAndLogEx(ERR
, "Sorry, this client doesn't support native Bluetooth addresses");
231 return INVALID_SERIAL_PORT
;
234 // The socket for abstract namespace implement.
235 // Is local socket buffer, not a TCP or any net connection!
236 // so, you can't connect with address like: 127.0.0.1, or any IP
237 // see http://man7.org/linux/man-pages/man7/unix.7.html
238 if (memcmp(prefix
, "socket:", 7) == 0) {
241 if (strlen(pcPortName
) <= 7) {
243 return INVALID_SERIAL_PORT
;
246 // we must use max timeout!
247 timeout
.tv_usec
= UART_TCP_CLIENT_RX_TIMEOUT_MS
* 1000;
249 size_t servernameLen
= (strlen(pcPortName
) - 7) + 1;
250 char serverNameBuf
[servernameLen
];
251 memset(serverNameBuf
, '\0', servernameLen
);
252 for (int i
= 7, j
= 0; j
< servernameLen
; ++i
, ++j
) {
253 serverNameBuf
[j
] = pcPortName
[i
];
255 serverNameBuf
[servernameLen
- 1] = '\0';
257 int localsocket
, len
;
258 struct sockaddr_un remote
;
260 remote
.sun_path
[0] = '\0'; // abstract namespace
261 strcpy(remote
.sun_path
+ 1, serverNameBuf
);
262 remote
.sun_family
= AF_LOCAL
;
263 int nameLen
= strlen(serverNameBuf
);
264 len
= 1 + nameLen
+ offsetof(struct sockaddr_un
, sun_path
);
266 if ((localsocket
= socket(PF_LOCAL
, SOCK_STREAM
, 0)) == -1) {
268 return INVALID_SERIAL_PORT
;
271 if (connect(localsocket
, (struct sockaddr
*) &remote
, len
) == -1) {
274 return INVALID_SERIAL_PORT
;
277 sp
->fd
= localsocket
;
283 sp
->fd
= open(pcPortName
, O_RDWR
| O_NOCTTY
| O_NDELAY
| O_NONBLOCK
);
286 return INVALID_SERIAL_PORT
;
289 // Finally figured out a way to claim a serial port interface under unix
290 // We just try to set a (advisory) lock on the file descriptor
293 fl
.l_whence
= SEEK_SET
;
298 // Does the system allows us to place a lock on this file descriptor
299 if (fcntl(sp
->fd
, F_SETLK
, &fl
) == -1) {
300 // A conflicting lock is held by another process
302 return CLAIMED_SERIAL_PORT
;
305 // Try to retrieve the old (current) terminal info struct
306 if (tcgetattr(sp
->fd
, &sp
->tiOld
) == -1) {
308 return INVALID_SERIAL_PORT
;
311 // Duplicate the (old) terminal info struct
312 sp
->tiNew
= sp
->tiOld
;
314 // Configure the serial port
315 sp
->tiNew
.c_cflag
= CS8
| CLOCAL
| CREAD
;
316 sp
->tiNew
.c_iflag
= IGNPAR
;
317 sp
->tiNew
.c_oflag
= 0;
318 sp
->tiNew
.c_lflag
= 0;
320 // Block until n bytes are received
321 sp
->tiNew
.c_cc
[VMIN
] = 0;
322 // Block until a timer expires (n * 100 mSec.)
323 sp
->tiNew
.c_cc
[VTIME
] = 0;
325 // Try to set the new terminal info struct
326 if (tcsetattr(sp
->fd
, TCSANOW
, &sp
->tiNew
) == -1) {
328 return INVALID_SERIAL_PORT
;
331 // Flush all lingering data that may exist
332 tcflush(sp
->fd
, TCIOFLUSH
);
334 if (!uart_set_speed(sp
, speed
)) {
335 // try fallback automatically
337 if (!uart_set_speed(sp
, speed
)) {
339 PrintAndLogEx(ERR
, "UART error while setting baudrate");
340 return INVALID_SERIAL_PORT
;
343 conn
.uart_speed
= uart_get_speed(sp
);
347 void uart_close(const serial_port sp
) {
348 serial_port_unix
*spu
= (serial_port_unix
*)sp
;
349 tcflush(spu
->fd
, TCIOFLUSH
);
350 tcsetattr(spu
->fd
, TCSANOW
, &(spu
->tiOld
));
353 fl
.l_whence
= SEEK_SET
;
358 // Does the system allows us to place a lock on this file descriptor
359 int err
= fcntl(spu
->fd
, F_SETLK
, &fl
);
361 //silent error message as it can be called from uart_open failing modes, e.g. when waiting for port to appear
362 //PrintAndLogEx(ERR, "UART error while closing port");
368 int uart_receive(const serial_port sp
, uint8_t *pbtRx
, uint32_t pszMaxRxLen
, uint32_t *pszRxLen
) {
369 uint32_t byteCount
; // FIONREAD returns size on 32b
373 if (newtimeout_pending
) {
374 timeout
.tv_usec
= newtimeout_value
* 1000;
375 newtimeout_pending
= false;
377 // Reset the output count
380 // Reset file descriptor
382 FD_SET(((serial_port_unix
*)sp
)->fd
, &rfds
);
384 int res
= select(((serial_port_unix
*)sp
)->fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
393 if (*pszRxLen
== 0) {
394 // We received no data
397 // We received some data, but nothing more is available
402 // Retrieve the count of the incoming bytes
403 res
= ioctl(((serial_port_unix
*)sp
)->fd
, FIONREAD
, &byteCount
);
404 // PrintAndLogEx(ERR, "UART:: RX ioctl res %d byteCount %u", res, byteCount);
405 if (res
< 0) return PM3_ENOTTY
;
407 // Cap the number of bytes, so we don't overrun the buffer
408 if (pszMaxRxLen
- (*pszRxLen
) < byteCount
) {
409 // PrintAndLogEx(ERR, "UART:: RX prevent overrun (have %u, need %u)", pszMaxRxLen - (*pszRxLen), byteCount);
410 byteCount
= pszMaxRxLen
- (*pszRxLen
);
413 // There is something available, read the data
414 res
= read(((serial_port_unix
*)sp
)->fd
, pbtRx
+ (*pszRxLen
), byteCount
);
416 // Stop if the OS has some troubles reading the data
423 if (*pszRxLen
== pszMaxRxLen
) {
424 // We have all the data we wanted.
432 int uart_send(const serial_port sp
, const uint8_t *pbtTx
, const uint32_t len
) {
438 // Reset file descriptor
440 FD_SET(((serial_port_unix
*)sp
)->fd
, &rfds
);
442 int res
= select(((serial_port_unix
*)sp
)->fd
+ 1, NULL
, &rfds
, NULL
, &tv
);
446 PrintAndLogEx(ERR
, "UART:: write error (%d)", res
);
452 PrintAndLogEx(ERR
, "UART:: write time-out");
456 // Send away the bytes
457 res
= write(((serial_port_unix
*)sp
)->fd
, pbtTx
+ pos
, len
- pos
);
459 // Stop if the OS has some troubles sending the data
468 bool uart_set_speed(serial_port sp
, const uint32_t uiPortSpeed
) {
469 const serial_port_unix
*spu
= (serial_port_unix
*)sp
;
471 switch (uiPortSpeed
) {
512 stPortSpeed
= B19200
;
515 stPortSpeed
= B38400
;
519 stPortSpeed
= B57600
;
524 stPortSpeed
= B115200
;
529 stPortSpeed
= B230400
;
534 stPortSpeed
= B460800
;
539 stPortSpeed
= B921600
;
544 stPortSpeed
= B1382400
;
553 if (tcgetattr(spu
->fd
, &ti
) == -1)
556 // Set port speed (Input and Output)
557 cfsetispeed(&ti
, stPortSpeed
);
558 cfsetospeed(&ti
, stPortSpeed
);
559 bool result
= tcsetattr(spu
->fd
, TCSANOW
, &ti
) != -1;
561 conn
.uart_speed
= uiPortSpeed
;
565 uint32_t uart_get_speed(const serial_port sp
) {
567 uint32_t uiPortSpeed
;
568 const serial_port_unix
*spu
= (serial_port_unix
*)sp
;
570 if (tcgetattr(spu
->fd
, &ti
) == -1)
573 // Set port speed (Input)
574 speed_t stPortSpeed
= cfgetispeed(&ti
);
575 switch (stPortSpeed
) {
628 uiPortSpeed
= 115200;
633 uiPortSpeed
= 230400;
638 uiPortSpeed
= 460800;
643 uiPortSpeed
= 921600;