]>
cvs.zerfleddert.de Git - proxmark3-svn/blob - uart/uart_posix.c
7eeb1a8385bd871b9dd6640cb63c4b553d970640
   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> 
  56 // Fix missing definition on OS X. 
  57 // Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7 
  59 #define SOL_TCP IPPROTO_TCP 
  62 typedef struct termios term_info
; 
  64         int fd
;           // Serial port file descriptor 
  65         term_info tiOld
;  // Terminal info before using the port 
  66         term_info tiNew
;  // Terminal info during the transaction 
  69 // Set time-out on 30 miliseconds 
  70 static struct timeval timeout 
= { 
  71         .tv_sec  
=     0, // 0 second 
  72         .tv_usec 
= 30000  // 30000 micro seconds 
  76 void uart_close(const serial_port sp
) { 
  77         serial_port_unix
* spu 
= (serial_port_unix
*)sp
; 
  78         tcflush(spu
->fd
,TCIOFLUSH
); 
  79         tcsetattr(spu
->fd
,TCSANOW
,&(spu
->tiOld
)); 
  82         fl
.l_whence 
= SEEK_SET
; 
  86         fcntl(spu
->fd
, F_SETLK
, &fl
); 
  92 serial_port 
uart_open(const char* pcPortName
) { 
  94         serial_port_unix
* sp 
= malloc(sizeof(serial_port_unix
)); 
  95         if (sp 
== 0) return INVALID_SERIAL_PORT
; 
  97         if (memcmp(pcPortName
, "tcp:", 4) == 0) { 
  98                 struct addrinfo 
*addr 
= NULL
, *rp
; 
  99                 char *addrstr 
= strdup(pcPortName 
+ 4); 
 100                 if (addrstr 
== NULL
) { 
 101                         printf("Error: strdup\n"); 
 102                         return INVALID_SERIAL_PORT
; 
 104                 char *colon 
= strrchr(addrstr
, ':'); 
 107                 // Set time-out to 300 milliseconds only for TCP port 
 108                 timeout
.tv_usec 
= 300000; 
 117                 struct addrinfo info
; 
 119                 memset(&info
, 0, sizeof(info
)); 
 121                 info
.ai_socktype 
= SOCK_STREAM
; 
 123                 int s 
= getaddrinfo(addrstr
, portstr
, &info
, &addr
); 
 125                         printf("Error: getaddrinfo: %s\n", gai_strerror(s
)); 
 126                         return INVALID_SERIAL_PORT
; 
 130                 for (rp 
= addr
; rp 
!= NULL
; rp 
= rp
->ai_next
) { 
 131                         sfd 
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
); 
 134                         if (connect(sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1) 
 139                 if (rp 
== NULL
) {               /* No address succeeded */ 
 140                         printf("Error: Could not connect\n"); 
 141                         return INVALID_SERIAL_PORT
; 
 150                 setsockopt(sp
->fd
, SOL_TCP
, TCP_NODELAY
, &one
, sizeof(one
)); 
 154         sp
->fd 
= open(pcPortName
, O_RDWR 
| O_NOCTTY 
| O_NDELAY 
| O_NONBLOCK
); 
 157                 return INVALID_SERIAL_PORT
; 
 160         // Finally figured out a way to claim a serial port interface under unix 
 161         // We just try to set a (advisory) lock on the file descriptor 
 164         fl
.l_whence 
= SEEK_SET
; 
 169         // Does the system allows us to place a lock on this file descriptor 
 170         if (fcntl(sp
->fd
, F_SETLK
, &fl
) == -1) { 
 171                 // A conflicting lock is held by another process 
 173                 return CLAIMED_SERIAL_PORT
; 
 176         // Try to retrieve the old (current) terminal info struct 
 177         if(tcgetattr(sp
->fd
,&sp
->tiOld
) == -1) { 
 179                 return INVALID_SERIAL_PORT
; 
 182         // Duplicate the (old) terminal info struct 
 183         sp
->tiNew 
= sp
->tiOld
; 
 185         // Configure the serial port 
 186         sp
->tiNew
.c_cflag 
= CS8 
| CLOCAL 
| CREAD
; 
 187         sp
->tiNew
.c_iflag 
= IGNPAR
; 
 188         sp
->tiNew
.c_oflag 
= 0; 
 189         sp
->tiNew
.c_lflag 
= 0; 
 191         // Block until n bytes are received 
 192         sp
->tiNew
.c_cc
[VMIN
] = 0; 
 193         // Block until a timer expires (n * 100 mSec.) 
 194         sp
->tiNew
.c_cc
[VTIME
] = 0; 
 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 pszMaxRxLen
, size_t* pszRxLen
) { 
 214         // Reset the output count 
 218                 // Reset file descriptor 
 220                 FD_SET(((serial_port_unix
*)sp
)->fd
,&rfds
); 
 222                 int res 
= select(((serial_port_unix
*)sp
)->fd
+1, &rfds
, NULL
, NULL
, &tv
); 
 231                         if (*pszRxLen 
== 0) { 
 232                                 // Error, we received no data 
 235                                 // We received some data, but nothing more is available 
 240                 // Retrieve the count of the incoming bytes 
 241                 res 
= ioctl(((serial_port_unix
*)sp
)->fd
, FIONREAD
, &byteCount
); 
 242                 if (res 
< 0) return false; 
 244                 // Cap the number of bytes, so we don't overrun the buffer 
 245                 if (pszMaxRxLen 
- (*pszRxLen
) < byteCount
) { 
 246                         byteCount 
= pszMaxRxLen 
- (*pszRxLen
); 
 249                 // There is something available, read the data 
 250                 res 
= read(((serial_port_unix
*)sp
)->fd
, pbtRx
+(*pszRxLen
), byteCount
); 
 252                 // Stop if the OS has some troubles reading the data 
 253                 if (res 
<= 0) return false; 
 257                 if (*pszRxLen 
== pszMaxRxLen
) { 
 258                         // We have all the data we wanted. 
 268 bool uart_send(const serial_port sp
, const uint8_t* pbtTx
, const size_t szTxLen
) { 
 273         while (szPos 
< szTxLen
) { 
 274                 // Reset file descriptor 
 276                 FD_SET(((serial_port_unix
*)sp
)->fd
,&rfds
); 
 278                 int res 
= select(((serial_port_unix
*)sp
)->fd
+1, NULL
, &rfds
, NULL
, &tv
); 
 290                 // Send away the bytes 
 291                 res 
= write(((serial_port_unix
*)sp
)->fd
, pbtTx
+szPos
, szTxLen
-szPos
); 
 293                 // Stop if the OS has some troubles sending the data 
 294                 if (res 
<= 0) return false; 
 302 bool uart_set_speed(serial_port sp
, const uint32_t uiPortSpeed
) { 
 303         const serial_port_unix
* spu 
= (serial_port_unix
*)sp
; 
 305         switch (uiPortSpeed
) { 
 306                 case 0: stPortSpeed 
= B0
; break; 
 307                 case 50: stPortSpeed 
= B50
; break; 
 308                 case 75: stPortSpeed 
= B75
; break; 
 309                 case 110: stPortSpeed 
= B110
; break; 
 310                 case 134: stPortSpeed 
= B134
; break; 
 311                 case 150: stPortSpeed 
= B150
; break; 
 312                 case 300: stPortSpeed 
= B300
; break; 
 313                 case 600: stPortSpeed 
= B600
; break; 
 314                 case 1200: stPortSpeed 
= B1200
; break; 
 315                 case 1800: stPortSpeed 
= B1800
; break; 
 316                 case 2400: stPortSpeed 
= B2400
; break; 
 317                 case 4800: stPortSpeed 
= B4800
; break; 
 318                 case 9600: stPortSpeed 
= B9600
; break; 
 319                 case 19200: stPortSpeed 
= B19200
; break; 
 320                 case 38400: stPortSpeed 
= B38400
; break; 
 322                 case 57600: stPortSpeed 
= B57600
; break; 
 325                 case 115200: stPortSpeed 
= B115200
; break; 
 328                 case 230400: stPortSpeed 
= B230400
; break; 
 331                 case 460800: stPortSpeed 
= B460800
; break; 
 334                 case 921600: stPortSpeed 
= B921600
; break; 
 336                 default: return false; 
 339         if (tcgetattr(spu
->fd
, &ti
) == -1) return false; 
 340         // Set port speed (Input and Output) 
 341         cfsetispeed(&ti
,stPortSpeed
); 
 342         cfsetospeed(&ti
,stPortSpeed
); 
 343         return (tcsetattr(spu
->fd
, TCSANOW
, &ti
) != -1); 
 346 uint32_t uart_get_speed(const serial_port sp
) { 
 348         uint32_t uiPortSpeed
; 
 349         const serial_port_unix
* spu 
= (serial_port_unix
*)sp
; 
 350         if (tcgetattr(spu
->fd
, &ti
) == -1) return 0; 
 351         // Set port speed (Input) 
 352         speed_t stPortSpeed 
= cfgetispeed(&ti
); 
 353         switch (stPortSpeed
) { 
 354                 case B0
: uiPortSpeed 
= 0; break; 
 355                 case B50
: uiPortSpeed 
= 50; break; 
 356                 case B75
: uiPortSpeed 
= 75; break; 
 357                 case B110
: uiPortSpeed 
= 110; break; 
 358                 case B134
: uiPortSpeed 
= 134; break; 
 359                 case B150
: uiPortSpeed 
= 150; break; 
 360                 case B300
: uiPortSpeed 
= 300; break; 
 361                 case B600
: uiPortSpeed 
= 600; break; 
 362                 case B1200
: uiPortSpeed 
= 1200; break; 
 363                 case B1800
: uiPortSpeed 
= 1800; break; 
 364                 case B2400
: uiPortSpeed 
= 2400; break; 
 365                 case B4800
: uiPortSpeed 
= 4800; break; 
 366                 case B9600
: uiPortSpeed 
= 9600; break; 
 367                 case B19200
: uiPortSpeed 
= 19200; break; 
 368                 case B38400
: uiPortSpeed 
= 38400; break; 
 370                 case B57600
: uiPortSpeed 
= 57600; break; 
 373                 case B115200
: uiPortSpeed 
= 115200; break; 
 376                 case B230400
: uiPortSpeed 
= 230400; break; 
 379                 case B460800
: uiPortSpeed 
= 460800; break; 
 382                 case B921600
: uiPortSpeed 
= 921600; break;