#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
\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
}\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
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
}\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