cleaning up uart_posix.c

* whitespace fixes
* sorting out #includes
This commit is contained in:
pwpiwi 2020-01-24 03:24:39 -05:00
parent ac37ee816b
commit fd66752193

780
uart/uart_posix.c Normal file → Executable file
View file

@ -1,391 +1,389 @@
/* /*
* Generic uart / rs232/ serial port library * Generic uart / rs232/ serial port library
* *
* Copyright (c) 2013, Roel Verdult * Copyright (c) 2013, Roel Verdult
* Copyright (c) 2018 Google * Copyright (c) 2018 Google
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the * 3. Neither the name of the copyright holders nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* @file uart_posix.c * @file uart_posix.c
* *
* This version of the library has functionality removed which was not used by * This version of the library has functionality removed which was not used by
* proxmark3 project. * proxmark3 project.
*/ */
// Test if we are dealing with posix operating systems // Test if we are dealing with posix operating systems
#ifndef _WIN32 #ifndef _WIN32
#define _DEFAULT_SOURCE #define _DEFAULT_SOURCE
#include "uart.h" #include "uart.h"
#include <termios.h> #include <stdlib.h>
#include <sys/ioctl.h> #include <stdio.h>
#include <unistd.h> #include <string.h>
#include <fcntl.h> #include <stdbool.h>
#include <sys/types.h> #include <termios.h>
#include <sys/stat.h> #include <sys/ioctl.h>
#include <limits.h> #include <unistd.h>
#include <sys/time.h> #include <fcntl.h>
#include <errno.h> #include <sys/types.h>
#include <sys/types.h> #include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/tcp.h>
#include <netinet/tcp.h> #include <netdb.h>
#include <arpa/inet.h>
#include <netdb.h> // Fix missing definition on OS X.
// Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7
// Fix missing definition on OS X. #ifndef SOL_TCP
// Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7 #define SOL_TCP IPPROTO_TCP
#ifndef SOL_TCP #endif
#define SOL_TCP IPPROTO_TCP
#endif typedef struct termios term_info;
typedef struct {
typedef struct termios term_info; int fd; // Serial port file descriptor
typedef struct { term_info tiOld; // Terminal info before using the port
int fd; // Serial port file descriptor term_info tiNew; // Terminal info during the transaction
term_info tiOld; // Terminal info before using the port } serial_port_unix;
term_info tiNew; // Terminal info during the transaction
} serial_port_unix; // Set time-out on 30 miliseconds
static struct timeval timeout = {
// Set time-out on 30 miliseconds .tv_sec = 0, // 0 second
struct timeval timeout = { .tv_usec = 30000 // 30000 micro seconds
.tv_sec = 0, // 0 second };
.tv_usec = 30000 // 30000 micro seconds
};
void uart_close(const serial_port sp) {
serial_port uart_open(const char* pcPortName) serial_port_unix* spu = (serial_port_unix*)sp;
{ tcflush(spu->fd,TCIOFLUSH);
serial_port_unix* sp = malloc(sizeof(serial_port_unix)); tcsetattr(spu->fd,TCSANOW,&(spu->tiOld));
if (sp == 0) return INVALID_SERIAL_PORT; struct flock fl;
fl.l_type = F_UNLCK;
if (memcmp(pcPortName, "tcp:", 4) == 0) { fl.l_whence = SEEK_SET;
struct addrinfo *addr = NULL, *rp; fl.l_start = 0;
char *addrstr = strdup(pcPortName + 4); fl.l_len = 0;
if (addrstr == NULL) { fl.l_pid = getpid();
printf("Error: strdup\n"); fcntl(spu->fd, F_SETLK, &fl);
return INVALID_SERIAL_PORT; close(spu->fd);
} free(sp);
char *colon = strrchr(addrstr, ':'); }
char *portstr;
// Set time-out to 300 miliseconds only for TCP port serial_port uart_open(const char* pcPortName) {
timeout.tv_usec = 300000;
serial_port_unix* sp = malloc(sizeof(serial_port_unix));
if (colon) { if (sp == 0) return INVALID_SERIAL_PORT;
portstr = colon + 1;
*colon = '\0'; if (memcmp(pcPortName, "tcp:", 4) == 0) {
} else struct addrinfo *addr = NULL, *rp;
portstr = "7901"; char *addrstr = strdup(pcPortName + 4);
if (addrstr == NULL) {
struct addrinfo info; printf("Error: strdup\n");
return INVALID_SERIAL_PORT;
memset (&info, 0, sizeof(info)); }
char *colon = strrchr(addrstr, ':');
info.ai_socktype = SOCK_STREAM; char *portstr;
int s = getaddrinfo(addrstr, portstr, &info, &addr); // Set time-out to 300 milliseconds only for TCP port
if (s != 0) { timeout.tv_usec = 300000;
printf("Error: getaddrinfo: %s\n", gai_strerror(s));
return INVALID_SERIAL_PORT; if (colon) {
} portstr = colon + 1;
*colon = '\0';
int sfd; } else {
for (rp = addr; rp != NULL; rp = rp->ai_next) { portstr = "7901";
sfd = socket(rp->ai_family, rp->ai_socktype, }
rp->ai_protocol);
if (sfd == -1) struct addrinfo info;
continue;
memset(&info, 0, sizeof(info));
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; info.ai_socktype = SOCK_STREAM;
close(sfd); int s = getaddrinfo(addrstr, portstr, &info, &addr);
} if (s != 0) {
printf("Error: getaddrinfo: %s\n", gai_strerror(s));
if (rp == NULL) { /* No address succeeded */ return INVALID_SERIAL_PORT;
printf("Error: Could not connect\n"); }
return INVALID_SERIAL_PORT;
} int sfd;
for (rp = addr; rp != NULL; rp = rp->ai_next) {
freeaddrinfo(addr); sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
free(addrstr); if (sfd == -1)
continue;
sp->fd = sfd; if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break;
int one = 1; close(sfd);
setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); }
return sp;
} if (rp == NULL) { /* No address succeeded */
printf("Error: Could not connect\n");
sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); return INVALID_SERIAL_PORT;
if(sp->fd == -1) { }
uart_close(sp);
return INVALID_SERIAL_PORT; freeaddrinfo(addr);
} free(addrstr);
// Finally figured out a way to claim a serial port interface under unix sp->fd = sfd;
// We just try to set a (advisory) lock on the file descriptor
struct flock fl; int one = 1;
fl.l_type = F_WRLCK; setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
fl.l_whence = SEEK_SET; return sp;
fl.l_start = 0; }
fl.l_len = 0;
fl.l_pid = getpid(); sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (sp->fd == -1) {
// Does the system allows us to place a lock on this file descriptor uart_close(sp);
if (fcntl(sp->fd, F_SETLK, &fl) == -1) { return INVALID_SERIAL_PORT;
// A conflicting lock is held by another process }
free(sp);
return CLAIMED_SERIAL_PORT; // Finally figured out a way to claim a serial port interface under unix
} // We just try to set a (advisory) lock on the file descriptor
struct flock fl;
// Try to retrieve the old (current) terminal info struct fl.l_type = F_WRLCK;
if(tcgetattr(sp->fd,&sp->tiOld) == -1) { fl.l_whence = SEEK_SET;
uart_close(sp); fl.l_start = 0;
return INVALID_SERIAL_PORT; fl.l_len = 0;
} fl.l_pid = getpid();
// Duplicate the (old) terminal info struct // Does the system allows us to place a lock on this file descriptor
sp->tiNew = sp->tiOld; if (fcntl(sp->fd, F_SETLK, &fl) == -1) {
// A conflicting lock is held by another process
// Configure the serial port free(sp);
sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD; return CLAIMED_SERIAL_PORT;
sp->tiNew.c_iflag = IGNPAR; }
sp->tiNew.c_oflag = 0;
sp->tiNew.c_lflag = 0; // Try to retrieve the old (current) terminal info struct
if(tcgetattr(sp->fd,&sp->tiOld) == -1) {
// Block until n bytes are received uart_close(sp);
sp->tiNew.c_cc[VMIN] = 0; return INVALID_SERIAL_PORT;
// Block until a timer expires (n * 100 mSec.) }
sp->tiNew.c_cc[VTIME] = 0;
// Duplicate the (old) terminal info struct
// Try to set the new terminal info struct sp->tiNew = sp->tiOld;
if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) {
uart_close(sp); // Configure the serial port
return INVALID_SERIAL_PORT; sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
} sp->tiNew.c_iflag = IGNPAR;
sp->tiNew.c_oflag = 0;
// Flush all lingering data that may exist sp->tiNew.c_lflag = 0;
tcflush(sp->fd, TCIOFLUSH);
// Block until n bytes are received
return sp; sp->tiNew.c_cc[VMIN] = 0;
} // Block until a timer expires (n * 100 mSec.)
sp->tiNew.c_cc[VTIME] = 0;
void uart_close(const serial_port sp) {
serial_port_unix* spu = (serial_port_unix*)sp; // Try to set the new terminal info struct
tcflush(spu->fd,TCIOFLUSH); if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) {
tcsetattr(spu->fd,TCSANOW,&(spu->tiOld)); uart_close(sp);
struct flock fl; return INVALID_SERIAL_PORT;
fl.l_type = F_UNLCK; }
fl.l_whence = SEEK_SET;
fl.l_start = 0; // Flush all lingering data that may exist
fl.l_len = 0; tcflush(sp->fd, TCIOFLUSH);
fl.l_pid = getpid();
fcntl(spu->fd, F_SETLK, &fl); return sp;
close(spu->fd); }
free(sp);
}
bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) {
bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) { int byteCount;
int res; fd_set rfds;
int byteCount; struct timeval tv;
fd_set rfds;
struct timeval tv; // Reset the output count
*pszRxLen = 0;
// Reset the output count
*pszRxLen = 0; do {
// Reset file descriptor
do { FD_ZERO(&rfds);
// Reset file descriptor FD_SET(((serial_port_unix*)sp)->fd,&rfds);
FD_ZERO(&rfds); tv = timeout;
FD_SET(((serial_port_unix*)sp)->fd,&rfds); int res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv);
tv = timeout;
res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv); // Read error
if (res < 0) {
// Read error return false;
if (res < 0) { }
return false;
} // Read time-out
if (res == 0) {
// Read time-out if (*pszRxLen == 0) {
if (res == 0) { // Error, we received no data
if (*pszRxLen == 0) { return false;
// Error, we received no data } else {
return false; // We received some data, but nothing more is available
} else { return true;
// We received some data, but nothing more is available }
return true; }
}
} // Retrieve the count of the incoming bytes
res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
// Retrieve the count of the incoming bytes if (res < 0) return false;
res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
if (res < 0) return false; // Cap the number of bytes, so we don't overrun the buffer
if (pszMaxRxLen - (*pszRxLen) < byteCount) {
// Cap the number of bytes, so we don't overrun the buffer byteCount = pszMaxRxLen - (*pszRxLen);
if (pszMaxRxLen - (*pszRxLen) < byteCount) { }
byteCount = pszMaxRxLen - (*pszRxLen);
} // There is something available, read the data
res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount);
// There is something available, read the data
res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount); // Stop if the OS has some troubles reading the data
if (res <= 0) return false;
// Stop if the OS has some troubles reading the data
if (res <= 0) return false; *pszRxLen += res;
*pszRxLen += res; if (*pszRxLen == pszMaxRxLen) {
// We have all the data we wanted.
if (*pszRxLen == pszMaxRxLen) { return true;
// We have all the data we wanted. }
return true;
} } while (byteCount);
} while (byteCount); return true;
}
return true;
}
bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) {
bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) { size_t szPos = 0;
int32_t res; fd_set rfds;
size_t szPos = 0; struct timeval tv;
fd_set rfds;
struct timeval tv; while (szPos < szTxLen) {
// Reset file descriptor
while (szPos < szTxLen) { FD_ZERO(&rfds);
// Reset file descriptor FD_SET(((serial_port_unix*)sp)->fd,&rfds);
FD_ZERO(&rfds); tv = timeout;
FD_SET(((serial_port_unix*)sp)->fd,&rfds); int res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv);
tv = timeout;
res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv); // Write error
if (res < 0) {
// Write error return false;
if (res < 0) { }
return false;
} // Write time-out
if (res == 0) {
// Write time-out return false;
if (res == 0) { }
return false;
} // Send away the bytes
res = write(((serial_port_unix*)sp)->fd, pbtTx+szPos, szTxLen-szPos);
// Send away the bytes
res = write(((serial_port_unix*)sp)->fd,pbtTx+szPos,szTxLen-szPos); // Stop if the OS has some troubles sending the data
if (res <= 0) return false;
// Stop if the OS has some troubles sending the data
if (res <= 0) return false; szPos += res;
}
szPos += res; return true;
} }
return true;
}
bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { const serial_port_unix* spu = (serial_port_unix*)sp;
const serial_port_unix* spu = (serial_port_unix*)sp; speed_t stPortSpeed;
speed_t stPortSpeed; switch (uiPortSpeed) {
switch (uiPortSpeed) { case 0: stPortSpeed = B0; break;
case 0: stPortSpeed = B0; break; case 50: stPortSpeed = B50; break;
case 50: stPortSpeed = B50; break; case 75: stPortSpeed = B75; break;
case 75: stPortSpeed = B75; break; case 110: stPortSpeed = B110; break;
case 110: stPortSpeed = B110; break; case 134: stPortSpeed = B134; break;
case 134: stPortSpeed = B134; break; case 150: stPortSpeed = B150; break;
case 150: stPortSpeed = B150; break; case 300: stPortSpeed = B300; break;
case 300: stPortSpeed = B300; break; case 600: stPortSpeed = B600; break;
case 600: stPortSpeed = B600; break; case 1200: stPortSpeed = B1200; break;
case 1200: stPortSpeed = B1200; break; case 1800: stPortSpeed = B1800; break;
case 1800: stPortSpeed = B1800; break; case 2400: stPortSpeed = B2400; break;
case 2400: stPortSpeed = B2400; break; case 4800: stPortSpeed = B4800; break;
case 4800: stPortSpeed = B4800; break; case 9600: stPortSpeed = B9600; break;
case 9600: stPortSpeed = B9600; break; case 19200: stPortSpeed = B19200; break;
case 19200: stPortSpeed = B19200; break; case 38400: stPortSpeed = B38400; break;
case 38400: stPortSpeed = B38400; break; # ifdef B57600
# ifdef B57600 case 57600: stPortSpeed = B57600; break;
case 57600: stPortSpeed = B57600; break; # endif
# endif # ifdef B115200
# ifdef B115200 case 115200: stPortSpeed = B115200; break;
case 115200: stPortSpeed = B115200; break; # endif
# endif # ifdef B230400
# ifdef B230400 case 230400: stPortSpeed = B230400; break;
case 230400: stPortSpeed = B230400; break; # endif
# endif # ifdef B460800
# ifdef B460800 case 460800: stPortSpeed = B460800; break;
case 460800: stPortSpeed = B460800; break; # endif
# endif # ifdef B921600
# ifdef B921600 case 921600: stPortSpeed = B921600; break;
case 921600: stPortSpeed = B921600; break; # endif
# endif default: return false;
default: return false; };
}; struct termios ti;
struct termios ti; if (tcgetattr(spu->fd, &ti) == -1) return false;
if (tcgetattr(spu->fd,&ti) == -1) return false; // Set port speed (Input and Output)
// Set port speed (Input and Output) cfsetispeed(&ti,stPortSpeed);
cfsetispeed(&ti,stPortSpeed); cfsetospeed(&ti,stPortSpeed);
cfsetospeed(&ti,stPortSpeed); return (tcsetattr(spu->fd, TCSANOW, &ti) != -1);
return (tcsetattr(spu->fd,TCSANOW,&ti) != -1); }
}
uint32_t uart_get_speed(const serial_port sp) {
uint32_t uart_get_speed(const serial_port sp) { struct termios ti;
struct termios ti; uint32_t uiPortSpeed;
uint32_t uiPortSpeed; const serial_port_unix* spu = (serial_port_unix*)sp;
const serial_port_unix* spu = (serial_port_unix*)sp; if (tcgetattr(spu->fd, &ti) == -1) return 0;
if (tcgetattr(spu->fd,&ti) == -1) return 0; // Set port speed (Input)
// Set port speed (Input) speed_t stPortSpeed = cfgetispeed(&ti);
speed_t stPortSpeed = cfgetispeed(&ti); switch (stPortSpeed) {
switch (stPortSpeed) { case B0: uiPortSpeed = 0; break;
case B0: uiPortSpeed = 0; break; case B50: uiPortSpeed = 50; break;
case B50: uiPortSpeed = 50; break; case B75: uiPortSpeed = 75; break;
case B75: uiPortSpeed = 75; break; case B110: uiPortSpeed = 110; break;
case B110: uiPortSpeed = 110; break; case B134: uiPortSpeed = 134; break;
case B134: uiPortSpeed = 134; break; case B150: uiPortSpeed = 150; break;
case B150: uiPortSpeed = 150; break; case B300: uiPortSpeed = 300; break;
case B300: uiPortSpeed = 300; break; case B600: uiPortSpeed = 600; break;
case B600: uiPortSpeed = 600; break; case B1200: uiPortSpeed = 1200; break;
case B1200: uiPortSpeed = 1200; break; case B1800: uiPortSpeed = 1800; break;
case B1800: uiPortSpeed = 1800; break; case B2400: uiPortSpeed = 2400; break;
case B2400: uiPortSpeed = 2400; break; case B4800: uiPortSpeed = 4800; break;
case B4800: uiPortSpeed = 4800; break; case B9600: uiPortSpeed = 9600; break;
case B9600: uiPortSpeed = 9600; break; case B19200: uiPortSpeed = 19200; break;
case B19200: uiPortSpeed = 19200; break; case B38400: uiPortSpeed = 38400; break;
case B38400: uiPortSpeed = 38400; break; # ifdef B57600
# ifdef B57600 case B57600: uiPortSpeed = 57600; break;
case B57600: uiPortSpeed = 57600; break; # endif
# endif # ifdef B115200
# ifdef B115200 case B115200: uiPortSpeed = 115200; break;
case B115200: uiPortSpeed = 115200; break; # endif
# endif # ifdef B230400
# ifdef B230400 case B230400: uiPortSpeed = 230400; break;
case B230400: uiPortSpeed = 230400; break; # endif
# endif # ifdef B460800
# ifdef B460800 case B460800: uiPortSpeed = 460800; break;
case B460800: uiPortSpeed = 460800; break; # endif
# endif # ifdef B921600
# ifdef B921600 case B921600: uiPortSpeed = 921600; break;
case B921600: uiPortSpeed = 921600; break; # endif
# endif default: return 0;
default: return 0; };
}; return uiPortSpeed;
return uiPortSpeed; }
}
#endif
#endif