uart_posix.c rework
[proxmark3-svn] / uart / uart_posix.c
index 7eeb1a8385bd871b9dd6640cb63c4b553d970640..f6e6519de885472ff5f138a0cca29ab59d86bd47 100755 (executable)
@@ -52,6 +52,8 @@
 #include <sys/socket.h>\r
 #include <netinet/tcp.h>\r
 #include <netdb.h>\r
+#include <sys/time.h>\r
+#include <errno.h>\r
 \r
 // Fix missing definition on OS X.\r
 // Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7\r
@@ -75,8 +77,8 @@ static struct timeval timeout = {
 \r
 void uart_close(const serial_port sp) {\r
        serial_port_unix* spu = (serial_port_unix*)sp;\r
-       tcflush(spu->fd,TCIOFLUSH);\r
-       tcsetattr(spu->fd,TCSANOW,&(spu->tiOld));\r
+       tcflush(spu->fd, TCIOFLUSH);\r
+       tcsetattr(spu->fd, TCSANOW, &(spu->tiOld));\r
        struct flock fl;\r
        fl.l_type   = F_UNLCK;\r
        fl.l_whence = SEEK_SET;\r
@@ -174,7 +176,7 @@ serial_port uart_open(const char* pcPortName) {
        }\r
 \r
        // Try to retrieve the old (current) terminal info struct\r
-       if(tcgetattr(sp->fd,&sp->tiOld) == -1) {\r
+       if (tcgetattr(sp->fd,&sp->tiOld) == -1) {\r
                uart_close(sp);\r
                return INVALID_SERIAL_PORT;\r
        }\r
@@ -183,18 +185,16 @@ serial_port uart_open(const char* pcPortName) {
        sp->tiNew = sp->tiOld;\r
 \r
        // Configure the serial port\r
-       sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;\r
-       sp->tiNew.c_iflag = IGNPAR;\r
-       sp->tiNew.c_oflag = 0;\r
-       sp->tiNew.c_lflag = 0;\r
+       sp->tiNew.c_cflag &= ~(CSIZE | PARENB);\r
+       sp->tiNew.c_cflag |= (CS8 | CLOCAL | CREAD);\r
+       sp->tiNew.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);\r
+       sp->tiNew.c_iflag |= IGNPAR;\r
+       sp->tiNew.c_oflag &= ~OPOST;\r
+       sp->tiNew.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);\r
 \r
-       // Block until n bytes are received\r
-       sp->tiNew.c_cc[VMIN] = 0;\r
-       // Block until a timer expires (n * 100 mSec.)\r
-       sp->tiNew.c_cc[VTIME] = 0;\r
 \r
        // Try to set the new terminal info struct\r
-       if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) {\r
+       if (tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) {\r
                uart_close(sp);\r
                return INVALID_SERIAL_PORT;\r
        }\r
@@ -206,94 +206,75 @@ serial_port uart_open(const char* pcPortName) {
 }\r
 \r
 \r
-bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) {\r
-       int byteCount;\r
-       fd_set rfds;\r
-       struct timeval tv;\r
+bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t szMaxRxLen, size_t* pszRxLen) {\r
 \r
-       // Reset the output count\r
        *pszRxLen = 0;\r
 \r
-       do {\r
-               // Reset file descriptor\r
-               FD_ZERO(&rfds);\r
-               FD_SET(((serial_port_unix*)sp)->fd,&rfds);\r
-               tv = timeout;\r
-               int res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv);\r
+       if (szMaxRxLen == 0) return true;\r
 \r
-               // Read error\r
-               if (res < 0) {\r
-                       return false;\r
-               }\r
+       struct timeval t_current;\r
+       gettimeofday(&t_current, NULL);\r
+       struct timeval t_end;\r
+       timeradd(&t_current, &timeout, &t_end);\r
 \r
-               // Read time-out\r
-               if (res == 0) {\r
-                       if (*pszRxLen == 0) {\r
-                               // Error, we received no data\r
-                               return false;\r
-                       } else {\r
-                               // We received some data, but nothing more is available\r
-                               return true;\r
-                       }\r
+       while (true) {\r
+               int res = read(((serial_port_unix*)sp)->fd, pbtRx, szMaxRxLen - *pszRxLen);\r
+               if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) return false;\r
+               if (res > 0) {\r
+                       *pszRxLen += res;\r
+                       pbtRx += res;\r
                }\r
-\r
-               // Retrieve the count of the incoming bytes\r
-               res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);\r
+               if (*pszRxLen == szMaxRxLen) return true; // we could read all requested bytes in time\r
+               gettimeofday(&t_current, NULL);\r
+               if (timercmp(&t_current, &t_end, >)) return true; // timeout\r
+               // set next select timeout\r
+               struct timeval t_remains;\r
+               timersub(&t_end, &t_current, &t_remains);\r
+               // Set the file descriptor set\r
+               fd_set rfds;\r
+               FD_ZERO(&rfds);\r
+               FD_SET(((serial_port_unix*)sp)->fd, &rfds);\r
+               // wait for more bytes available\r
+               res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &t_remains);\r
                if (res < 0) return false;\r
-\r
-               // Cap the number of bytes, so we don't overrun the buffer\r
-               if (pszMaxRxLen - (*pszRxLen) < byteCount) {\r
-                       byteCount = pszMaxRxLen - (*pszRxLen);\r
-               }\r
-\r
-               // There is something available, read the data\r
-               res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount);\r
-\r
-               // Stop if the OS has some troubles reading the data\r
-               if (res <= 0) return false;\r
-\r
-               *pszRxLen += res;\r
-\r
-               if (*pszRxLen == pszMaxRxLen) {\r
-                       // We have all the data we wanted.\r
-                       return true;\r
-               }\r
-\r
-       } while (byteCount);\r
-\r
-       return true;\r
+               if (res == 0) return true; // timeout\r
+       }\r
+       return true; // should never come here\r
 }\r
 \r
 \r
 bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) {\r
-       size_t szPos = 0;\r
-       fd_set rfds;\r
-       struct timeval tv;\r
-\r
-       while (szPos < szTxLen) {\r
-               // Reset file descriptor\r
-               FD_ZERO(&rfds);\r
-               FD_SET(((serial_port_unix*)sp)->fd,&rfds);\r
-               tv = timeout;\r
-               int res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv);\r
 \r
-               // Write error\r
-               if (res < 0) {\r
-                       return false;\r
-               }\r
+       if (szTxLen == 0) return true;\r
 \r
-               // Write time-out\r
-               if (res == 0) {\r
-                       return false;\r
-               }\r
+       size_t bytes_written = 0;\r
 \r
-               // Send away the bytes\r
-               res = write(((serial_port_unix*)sp)->fd, pbtTx+szPos, szTxLen-szPos);\r
+       struct timeval t_current;\r
+       gettimeofday(&t_current, NULL);\r
+       struct timeval t_end;\r
+       timeradd(&t_current, &timeout, &t_end);\r
 \r
-               // Stop if the OS has some troubles sending the data\r
-               if (res <= 0) return false;\r
-\r
-               szPos += res;\r
+       while (true) {\r
+               int res = write(((serial_port_unix*)sp)->fd, pbtTx, szTxLen - bytes_written);\r
+               if (res < 0 && res != EAGAIN && res != EWOULDBLOCK) return false;\r
+               if (res > 0) {\r
+                       pbtTx += res;\r
+                       bytes_written += res;\r
+               }\r
+               if (bytes_written == szTxLen) return true; // we could write all bytes\r
+               gettimeofday(&t_current, NULL);\r
+               if (timercmp(&t_current, &t_end, >)) return false; // timeout\r
+               // set next select timeout\r
+               struct timeval t_remains;\r
+               timersub(&t_end, &t_current, &t_remains);\r
+               // Set the file descriptor set\r
+               fd_set wfds;\r
+               FD_ZERO(&wfds);\r
+               FD_SET(((serial_port_unix*)sp)->fd, &wfds);\r
+               // wait until more bytes can be written\r
+               res = select(((serial_port_unix*)sp)->fd+1, NULL, &wfds, NULL, &t_remains);\r
+               if (res < 0) return false;  // error\r
+               if (res == 0) return false; // timeout\r
        }\r
        return true;\r
 }\r
Impressum, Datenschutz