]>
git.zerfleddert.de Git - proxmark3-svn/blob - uart/uart_posix.c
2 * Generic uart / rs232/ serial port library
4 * Copyright (c) 2013, Roel Verdult
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * This version of the library has functionality removed which was not used by
37 // Test if we are dealing with posix operating systems
40 #include <sys/ioctl.h>
43 #include <sys/types.h>
49 typedef struct termios term_info
;
51 int fd
; // Serial port file descriptor
52 term_info tiOld
; // Terminal info before using the port
53 term_info tiNew
; // Terminal info during the transaction
56 // Set time-out on 30 miliseconds
57 const struct timeval timeout
= {
58 .tv_sec
= 0, // 0 second
59 .tv_usec
= 30000 // 30000 micro seconds
62 serial_port
uart_open(const char* pcPortName
)
64 serial_port_unix
* sp
= malloc(sizeof(serial_port_unix
));
65 if (sp
== 0) return INVALID_SERIAL_PORT
;
67 sp
->fd
= open(pcPortName
, O_RDWR
| O_NOCTTY
| O_NDELAY
| O_NONBLOCK
);
70 return INVALID_SERIAL_PORT
;
73 // Finally figured out a way to claim a serial port interface under unix
74 // We just try to set a (advisory) lock on the file descriptor
77 fl
.l_whence
= SEEK_SET
;
82 // Does the system allows us to place a lock on this file descriptor
83 if (fcntl(sp
->fd
, F_SETLK
, &fl
) == -1) {
84 // A conflicting lock is held by another process
86 return CLAIMED_SERIAL_PORT
;
89 // Try to retrieve the old (current) terminal info struct
90 if(tcgetattr(sp
->fd
,&sp
->tiOld
) == -1) {
92 return INVALID_SERIAL_PORT
;
95 // Duplicate the (old) terminal info struct
96 sp
->tiNew
= sp
->tiOld
;
98 // Configure the serial port
99 sp
->tiNew
.c_cflag
= CS8
| CLOCAL
| CREAD
;
100 sp
->tiNew
.c_iflag
= IGNPAR
;
101 sp
->tiNew
.c_oflag
= 0;
102 sp
->tiNew
.c_lflag
= 0;
104 // Block until n bytes are received
105 sp
->tiNew
.c_cc
[VMIN
] = 0;
106 // Block until a timer expires (n * 100 mSec.)
107 sp
->tiNew
.c_cc
[VTIME
] = 0;
109 // Try to set the new terminal info struct
110 if(tcsetattr(sp
->fd
,TCSANOW
,&sp
->tiNew
) == -1) {
112 return INVALID_SERIAL_PORT
;
115 // Flush all lingering data that may exist
116 tcflush(sp
->fd
, TCIOFLUSH
);
121 void uart_close(const serial_port sp
) {
122 serial_port_unix
* spu
= (serial_port_unix
*)sp
;
123 tcflush(spu
->fd
,TCIOFLUSH
);
124 tcsetattr(spu
->fd
,TCSANOW
,&(spu
->tiOld
));
127 fl
.l_whence
= SEEK_SET
;
131 fcntl(spu
->fd
, F_SETLK
, &fl
);
136 bool uart_receive(const serial_port sp
, uint8_t* pbtRx
, size_t pszMaxRxLen
, size_t* pszRxLen
) {
142 // Reset the output count
146 // Reset file descriptor
148 FD_SET(((serial_port_unix
*)sp
)->fd
,&rfds
);
150 res
= select(((serial_port_unix
*)sp
)->fd
+1, &rfds
, NULL
, NULL
, &tv
);
159 if (*pszRxLen
== 0) {
160 // Error, we received no data
163 // We received some data, but nothing more is available
168 // Retrieve the count of the incoming bytes
169 res
= ioctl(((serial_port_unix
*)sp
)->fd
, FIONREAD
, &byteCount
);
170 if (res
< 0) return false;
172 // Cap the number of bytes, so we don't overrun the buffer
173 if (pszMaxRxLen
- (*pszRxLen
) < byteCount
) {
174 byteCount
= pszMaxRxLen
- (*pszRxLen
);
177 // There is something available, read the data
178 res
= read(((serial_port_unix
*)sp
)->fd
, pbtRx
+(*pszRxLen
), byteCount
);
180 // Stop if the OS has some troubles reading the data
181 if (res
<= 0) return false;
185 if (*pszRxLen
== pszMaxRxLen
) {
186 // We have all the data we wanted.
195 bool uart_send(const serial_port sp
, const uint8_t* pbtTx
, const size_t szTxLen
) {
201 while (szPos
< szTxLen
) {
202 // Reset file descriptor
204 FD_SET(((serial_port_unix
*)sp
)->fd
,&rfds
);
206 res
= select(((serial_port_unix
*)sp
)->fd
+1, NULL
, &rfds
, NULL
, &tv
);
218 // Send away the bytes
219 res
= write(((serial_port_unix
*)sp
)->fd
,pbtTx
+szPos
,szTxLen
-szPos
);
221 // Stop if the OS has some troubles sending the data
222 if (res
<= 0) return false;
229 bool uart_set_speed(serial_port sp
, const uint32_t uiPortSpeed
) {
230 const serial_port_unix
* spu
= (serial_port_unix
*)sp
;
232 switch (uiPortSpeed
) {
233 case 0: stPortSpeed
= B0
; break;
234 case 50: stPortSpeed
= B50
; break;
235 case 75: stPortSpeed
= B75
; break;
236 case 110: stPortSpeed
= B110
; break;
237 case 134: stPortSpeed
= B134
; break;
238 case 150: stPortSpeed
= B150
; break;
239 case 300: stPortSpeed
= B300
; break;
240 case 600: stPortSpeed
= B600
; break;
241 case 1200: stPortSpeed
= B1200
; break;
242 case 1800: stPortSpeed
= B1800
; break;
243 case 2400: stPortSpeed
= B2400
; break;
244 case 4800: stPortSpeed
= B4800
; break;
245 case 9600: stPortSpeed
= B9600
; break;
246 case 19200: stPortSpeed
= B19200
; break;
247 case 38400: stPortSpeed
= B38400
; break;
249 case 57600: stPortSpeed
= B57600
; break;
252 case 115200: stPortSpeed
= B115200
; break;
255 case 230400: stPortSpeed
= B230400
; break;
258 case 460800: stPortSpeed
= B460800
; break;
261 case 921600: stPortSpeed
= B921600
; break;
263 default: return false;
266 if (tcgetattr(spu
->fd
,&ti
) == -1) return false;
267 // Set port speed (Input and Output)
268 cfsetispeed(&ti
,stPortSpeed
);
269 cfsetospeed(&ti
,stPortSpeed
);
270 return (tcsetattr(spu
->fd
,TCSANOW
,&ti
) != -1);
273 uint32_t uart_get_speed(const serial_port sp
) {
275 uint32_t uiPortSpeed
;
276 const serial_port_unix
* spu
= (serial_port_unix
*)sp
;
277 if (tcgetattr(spu
->fd
,&ti
) == -1) return 0;
278 // Set port speed (Input)
279 speed_t stPortSpeed
= cfgetispeed(&ti
);
280 switch (stPortSpeed
) {
281 case B0
: uiPortSpeed
= 0; break;
282 case B50
: uiPortSpeed
= 50; break;
283 case B75
: uiPortSpeed
= 75; break;
284 case B110
: uiPortSpeed
= 110; break;
285 case B134
: uiPortSpeed
= 134; break;
286 case B150
: uiPortSpeed
= 150; break;
287 case B300
: uiPortSpeed
= 300; break;
288 case B600
: uiPortSpeed
= 600; break;
289 case B1200
: uiPortSpeed
= 1200; break;
290 case B1800
: uiPortSpeed
= 1800; break;
291 case B2400
: uiPortSpeed
= 2400; break;
292 case B4800
: uiPortSpeed
= 4800; break;
293 case B9600
: uiPortSpeed
= 9600; break;
294 case B19200
: uiPortSpeed
= 19200; break;
295 case B38400
: uiPortSpeed
= 38400; break;
297 case B57600
: uiPortSpeed
= 57600; break;
300 case B115200
: uiPortSpeed
= 115200; break;
303 case B230400
: uiPortSpeed
= 230400; break;
306 case B460800
: uiPortSpeed
= 460800; break;
309 case B921600
: uiPortSpeed
= 921600; break;