123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <malloc.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <termios.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <sys/file.h>
- #include "gfaserial.h"
- #define min(a, b) (((a) < (b)) ? (a) : (b))
- /////////////////////////////////////////////////////////////////////////////
- // https://blog.mbedded.ninja/programming/operating-systems/linux/linux-serial-ports-using-c-cpp/#everything-is-a-file
- /////////////////////////////////////////////////////////////////////////////
- typedef struct _GFA_SERIAL_DEVICE
- {
- int fd;
- char *pszDeviceName;
- GFA_SER_CFG_PARAMS cfg;
- struct termios tty;
- struct termios ttySave;
- struct timeval tvRX;
- struct timeval tvTX;
- struct timeval tvEcho;
- struct timeval tvPurge;
- }GFA_SERIAL_DEVICE, *LPGFA_SERIAL_DEVICE;
- typedef const GFA_SERIAL_DEVICE *LPCGFA_SERIAL_DEVICE;
- /////////////////////////////////////////////////////////////////////////////
- static speed_t _MapBaudrate(uint32_t b)
- {
- speed_t s;
- switch(b)
- {
- case 0: s = B0; break;
- case 50: s = B50; break;
- case 75: s = B75; break;
- case 110: s = B110; break;
- case 134: s = B134; break;
- case 150: s = B150; break;
- case 200: s = B200; break;
- case 300: s = B300; break;
- case 600: s = B600; break;
- case 1200: s = B1200; break;
- case 1800: s = B1800; break;
- case 2400: s = B2400; break;
- case 4800: s = B4800; break;
- case 9600: s = B9600; break;
- case 19200: s = B19200; break;
- case 38400: s = B38400; break;
- case 57600: s = B57600; break;
- case 115200: s = B115200; break;
- case 230400: s = B230400; break;
- case 460800: s = B460800; break;
- case 921600: s = B921600; break;
- default: s = (speed_t)-1; break;
- }
- return s;
- }
- /////////////////////////////////////////////////////////////////////////////
- static void _SetDefaultTimeouts(LPGFA_SERIAL_DEVICE psd)
- {
- if(psd)
- {
- psd->tvRX.tv_sec = 0;
- psd->tvRX.tv_usec = 200000;
- psd->tvTX.tv_sec = 0;
- psd->tvTX.tv_usec = 100000;
- psd->tvEcho.tv_sec = 0;
- psd->tvEcho.tv_usec = 50000;
- psd->tvPurge.tv_sec = 0;
- psd->tvPurge.tv_usec = 10000;
- }
- }
- static void _CopyTimeval(struct timeval *ptvTo, const struct timeval *ptvFrom)
- {
- ptvTo->tv_sec = ptvFrom->tv_sec;
- ptvTo->tv_usec = ptvFrom->tv_usec;
- }
- /////////////////////////////////////////////////////////////////////////////
- static bool _ReadEcho(HGFADEVICE hSer, const void *pData, size_t nWritten)
- {
- uint8_t b[256];
- ssize_t nRet;
- struct timeval tvSave;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- ssize_t nLeft = (ssize_t)nWritten, nRead = 0, nToRead;
- const char *pszData = (const char*)pData;
- if(!nLeft)
- return false;
- if( !GfaSerialGetTimeouts(hSer, &tvSave, NULL) ||
- !GfaSerialSetTimeouts(hSer, &psd->tvEcho, NULL))
- return false;
- do
- {
- nToRead = min(nLeft, (ssize_t)sizeof(b));
- if((nRet = GfaSerialReceive(hSer, b, nToRead)) <= 0)
- {
- GfaSerialSetTimeouts(hSer, &tvSave, NULL);
- return false;
- }
- if(memcmp(b, pszData, nRet))
- {
- GfaSerialSetTimeouts(hSer, &tvSave, NULL);
- return false;
- }
- pszData += nRet;
- nRead += nRet;
- nLeft = (ssize_t)nWritten - nRead;
- }
- while(nLeft > 0);
- GfaSerialSetTimeouts(hSer, &tvSave, NULL);
- return (nRead == (ssize_t)nWritten);
- }
- /////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////////////
- HGFADEVICE GfaSerialOpen(const char *pszDeviceName, LPCGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
- {
- if(pszDeviceName && *pszDeviceName && pscp && nSizeCfgParams >= sizeof(GFA_SER_CFG_PARAMS))
- {
- LPGFA_SERIAL_DEVICE psd = malloc(sizeof(GFA_SERIAL_DEVICE));
- memset(psd, 0, sizeof(GFA_SERIAL_DEVICE));
-
- /////////////////////////////////////////////////////////////////////
- // Open the device
- if((psd->fd = open(pszDeviceName, O_RDWR | O_NONBLOCK)) < 0)
- {
- GfaSerialClose(psd);
- return NULL;
- }
-
- /////////////////////////////////////////////////////////////////////
- // Lock device descriptor exclusive
- if(flock(psd->fd, LOCK_EX | LOCK_NB) < 0)
- {
- GfaSerialClose(psd);
- return NULL;
- }
-
- /////////////////////////////////////////////////////////////////////
- // Get current config and save it for restore on close
- if(tcgetattr(psd->fd, &psd->tty) != 0)
- {
- GfaSerialClose(psd);
- return NULL;
- }
- memcpy(&psd->ttySave, &psd->tty, sizeof(struct termios));
-
- /////////////////////////////////////////////////////////////////////
- // Set new config
- if(GfaSerialSetConfig(psd, pscp, nSizeCfgParams) < 0)
- {
- GfaSerialClose(psd);
- return NULL;
- }
- /////////////////////////////////////////////////////////////////////
- // Set deault timeouts.
- _SetDefaultTimeouts(psd);
- /////////////////////////////////////////////////////////////////////
- // Everything ok.
- psd->pszDeviceName = strdup(pszDeviceName);
- GfaSerialPurgeRXBuffer((HGFADEVICE)psd); // clear RX buffer
- return (HGFADEVICE)psd;
- }
- errno = EINVAL;
- return NULL;
- }
- /////////////////////////////////////////////////////////////////////////////
- void GfaSerialClose(HGFADEVICE hSer)
- {
- if(hSer)
- {
- int nErrno = errno;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- if(psd->fd >= 0)
- {
- tcsetattr(psd->fd, TCSAFLUSH, &psd->ttySave);
- flock(psd->fd, LOCK_UN | LOCK_NB);
- close(psd->fd);
- }
- if(psd->pszDeviceName)
- free(psd->pszDeviceName);
- free(psd);
- errno = nErrno;
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialGetConfig(HGFADEVICE hSer, LPGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
- {
- if(hSer && pscp && nSizeCfgParams >= sizeof(GFA_SER_CFG_PARAMS))
- {
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- memcpy(pscp, &psd->cfg, sizeof(GFA_SER_CFG_PARAMS));
- return sizeof(GFA_SER_CFG_PARAMS);
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- int GfaSerialSetConfig(HGFADEVICE hSer, LPCGFA_SER_CFG_PARAMS pscp, size_t nSizeCfgParams)
- {
- if(hSer && pscp && nSizeCfgParams >= sizeof(GFA_SER_CFG_PARAMS))
- {
- int nRet;
- speed_t s;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- /////////////////////////////////////////////////////////////////////
- // Baud Rate
- if((s = _MapBaudrate(pscp->baud)) == (speed_t)-1)
- {
- errno = EINVAL;
- return -1;
- }
- if( ((nRet = cfsetispeed(&psd->tty, s)) < 0) ||
- ((nRet = cfsetospeed(&psd->tty, s)) < 0))
- {
- return nRet;
- }
- /////////////////////////////////////////////////////////////////////
- // data bits
- switch(pscp->data)
- {
- case 5:
- psd->tty.c_cflag &= ~CSIZE;
- psd->tty.c_cflag |= CS5; // 5 bits per byte
- break;
- case 6:
- psd->tty.c_cflag &= ~CSIZE;
- psd->tty.c_cflag |= CS6; // 6 bits per byte
- break;
- case 7:
- psd->tty.c_cflag &= ~CSIZE;
- psd->tty.c_cflag |= CS7; // 7 bits per byte
- break;
- case 8:
- psd->tty.c_cflag &= ~CSIZE;
- psd->tty.c_cflag |= CS8; // 8 bits per byte
- break;
- default:
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////
- // stop bits
- switch(pscp->stop)
- {
- case 1:
- psd->tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication
- break;
- case 2:
- psd->tty.c_cflag |= CSTOPB; // Set stop field, two stop bits used in communication
- break;
- default:
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////
- // parity
- switch(toupper(pscp->parity))
- {
- case 'N':
- psd->tty.c_cflag &= ~(PARENB | PARODD); // Clear parity bit, disabling parity
- break;
- case 'E':
- psd->tty.c_cflag |= PARENB; // Set parity bit, enabling parity
- psd->tty.c_cflag &= ~PARODD; // Clear odd parity bit, enabling even parity
- break;
- case 'O':
- psd->tty.c_cflag |= (PARENB | PARODD); // Set parity bits, enabling odd parity
- break;
- default:
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////
- // RTS/CTS flow control
- // If the CRTSCTS field is set, hardware RTS/CTS flow control is enabled. The most common setting here is to disable it.
- // Enabling this when it should be disabled can result in your serial port receiving no data, as the sender will buffer
- // it indefinitely, waiting for you to be “ready”.
- if(pscp->flowHW)
- psd->tty.c_cflag |= CRTSCTS; // Enable RTS/CTS hardware flow control
- else
- psd->tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
- /////////////////////////////////////////////////////////////////////
- // Setting CLOCAL disables modem-specific signal lines such as carrier detect. It also
- // prevents the controlling process from getting sent a SIGHUP signal when a modem disconnect
- // is detected, which is usually a good thing here. Setting CLOCAL allows us to read data (we definitely want that!).
- psd->tty.c_cflag |= (CREAD | CLOCAL); // Turn on READ & ignore ctrl lines (CLOCAL = 1)
- /////////////////////////////////////////////////////////////////////
- // UNIX systems provide two basic modes of input, canonical and non-canonical mode. In canonical mode, input is
- // processed when a new line character is received. The receiving application receives that data line-by-line.
- // This is usually undesirable when dealing with a serial port, and so we normally want to disable canonical mode.
- // Also, in canonical mode, some characters such as backspace are treated specially, and are used to edit the
- // current line of text (erase). Again, we don’t want this feature if processing raw serial data, as it will
- // cause particular bytes to go missing!
- psd->tty.c_lflag &= ~ICANON;
- /////////////////////////////////////////////////////////////////////
- // Echo
- // If this bit is set, sent characters will be echoed back. Because we disabled canonical mode,
- // I don’t think these bits actually do anything, but it doesn’t harm to disable them just in case!
- psd->tty.c_lflag &= ~ECHO; // Disable echo
- psd->tty.c_lflag &= ~ECHOE; // Disable erasure
- psd->tty.c_lflag &= ~ECHONL; // Disable new-line echo
- /////////////////////////////////////////////////////////////////////
- // Signal chars
- // When the ISIG bit is set, INTR, QUIT and SUSP characters are interpreted.
- // We don’t want this with a serial port, so clear this bit.
- psd->tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
- /////////////////////////////////////////////////////////////////////
- // Software Flow Control (IXOFF, IXON, IXANY)
- // Clearing IXOFF, IXON and IXANY disables software flow control.
- if(pscp->flowSW)
- psd->tty.c_iflag |= (IXON | IXOFF); // Turn on s/w flow ctrl
- else
- psd->tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
- /////////////////////////////////////////////////////////////////////
- // Disabling Special Handling Of Bytes On Receive
- // Clearing all of the following bits disables any special handling of the bytes as they
- // are received by the serial port, before they are passed to the application. We just want the raw data!
- psd->tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes
- /////////////////////////////////////////////////////////////////////
- // When configuring a serial port, we want to disable any special handling of output chars/bytes.
- psd->tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
- psd->tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
- /////////////////////////////////////////////////////////////////////
- // VMIN and VTIME
- psd->tty.c_cc[VTIME] = psd->tty.c_cc[VMIN] = 0; // No blocking, return immediately with what is available
- /////////////////////////////////////////////////////////////////////
- // set configuration
- if((nRet = tcsetattr(psd->fd, TCSAFLUSH, &psd->tty)) == 0)
- memcpy(&psd->cfg, pscp, sizeof(GFA_SER_CFG_PARAMS));
- return nRet;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- bool GfaSerialGetDeviceInterface(LPGFA_GENERIC_DEVICE_INTERFACE pDevItf)
- {
- if(pDevItf)
- {
- pDevItf->pfnOpen = (PFN_GFA_GENERIC_DEV_OPEN)GfaSerialOpen;
- pDevItf->pfnClose = GfaSerialClose;
- pDevItf->pfnGetConfig = (PFN_GFA_GENERIC_DEV_GET_CONFIG)GfaSerialGetConfig;
- pDevItf->pfnSetConfig = (PFN_GFA_GENERIC_DEV_SET_CONFIG)GfaSerialSetConfig;
- pDevItf->pfnGetTimeouts = GfaSerialGetTimeouts;
- pDevItf->pfnSetTimeouts = GfaSerialSetTimeouts;
- pDevItf->pfnPurgeRXBuffer = GfaSerialPurgeRXBuffer;
- pDevItf->pfnReceive = GfaSerialReceive;
- pDevItf->pfnRead = GfaSerialRead;
- pDevItf->pfnPop = GfaSerialPop;
- pDevItf->pfnPeek = GfaSerialPeek;
- pDevItf->pfnTransmit = GfaSerialTransmit;
- pDevItf->pfnWrite = GfaSerialWrite;
- pDevItf->pfnPush = GfaSerialPush;
- return true;
- }
- errno = EINVAL;
- return false;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialPurgeRXBuffer(HGFADEVICE hSer)
- {
- struct timeval tvSave;
- if(hSer && GfaSerialGetTimeouts(hSer, &tvSave, NULL))
- {
- uint8_t b[256];
- ssize_t nRet = 0, nRx;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- GfaSerialSetTimeouts(hSer, &psd->tvPurge, NULL);
- while((nRx = GfaSerialReceive(hSer, b, sizeof(b))) > 0)
- nRet += nRx;
- GfaSerialSetTimeouts(hSer, &tvSave, NULL);
- return nRet;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- bool GfaSerialGetTimeouts(HGFADEVICE hSer, struct timeval *ptvRX, struct timeval *ptvTX)
- {
- if(hSer && (ptvRX || ptvTX))
- {
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- if(ptvRX)
- memcpy(ptvRX, &psd->tvRX, sizeof(struct timeval));
- if(ptvTX)
- memcpy(ptvTX, &psd->tvTX, sizeof(struct timeval));
- return true;
- }
- errno = EINVAL;
- return false;
- }
- /////////////////////////////////////////////////////////////////////////////
- bool GfaSerialSetTimeouts(HGFADEVICE hSer, const struct timeval *ptvRX, const struct timeval *ptvTX)
- {
- if(hSer && (ptvRX || ptvTX))
- {
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- if(ptvRX)
- memcpy(&psd->tvRX, ptvRX, sizeof(struct timeval));
- if(ptvTX)
- memcpy(&psd->tvTX, ptvTX, sizeof(struct timeval));
- return true;
- }
- errno = EINVAL;
- return false;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialTransmit(HGFADEVICE hSer, const void *pData, size_t nCbToWrite)
- {
- if(hSer && pData && nCbToWrite)
- {
- fd_set fds;
- struct timeval tv;
- ssize_t nRet = 0;
- ssize_t nWritten = 0;
- const char *pszData = (const char*)pData;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- _CopyTimeval(&tv, &psd->tvTX);
- while(nWritten < (ssize_t)nCbToWrite)
- {
- FD_ZERO(&fds);
- FD_SET(psd->fd, &fds);
- nRet = select(psd->fd + 1, NULL, &fds, NULL, &tv);
- if(nRet < 0)
- return -1;
- else if(nRet == 0)
- {
- errno = ETIMEDOUT;
- break;
- }
- nRet = write(psd->fd, pszData, nCbToWrite - nWritten);
- if(nRet < 0)
- return -1;
- else if(nRet == 0)
- {
- // should never happen!
- errno = ENODATA;
- return -1;
- }
- else
- {
- if( psd->cfg.bHandleTxEcho &&
- !_ReadEcho(hSer, pszData, nRet))
- {
- GfaSerialPurgeRXBuffer(hSer);
- errno = ECOMM;
- return -1;
- }
- pszData += nRet;
- nWritten += nRet;
- }
- }
- return nWritten;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialWrite(HGFADEVICE hSer, const void *pData, size_t nCbData)
- {
- if(hSer && pData && nCbData)
- {
- ssize_t nRet;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- if((nRet = write(psd->fd, pData, nCbData)) > 0)
- {
- if( psd->cfg.bHandleTxEcho &&
- !_ReadEcho(hSer, pData, nRet))
- {
- GfaSerialPurgeRXBuffer(hSer);
- errno = ECOMM;
- return -1;
- }
- }
- return nRet;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialPush(HGFADEVICE hSer, uint8_t b)
- {
- if(hSer)
- {
- fd_set fds;
- struct timeval tv;
- ssize_t nRet = 0;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- _CopyTimeval(&tv, &psd->tvTX);
- FD_ZERO(&fds);
- FD_SET(psd->fd, &fds);
- nRet = select(psd->fd + 1, NULL, &fds, NULL, &tv);
- if(nRet < 0)
- return -1;
- else if(nRet == 0)
- {
- errno = ETIMEDOUT;
- return 0;
- }
- if((nRet = write(psd->fd, &b, 1)) == 1)
- {
- if( psd->cfg.bHandleTxEcho &&
- !_ReadEcho(hSer, &b, 1))
- {
- GfaSerialPurgeRXBuffer(hSer);
- errno = ECOMM;
- return -1;
- }
- }
- return nRet;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialReceive(HGFADEVICE hSer, void *pBuf, size_t nCbToRead)
- {
- if(hSer && pBuf && nCbToRead)
- {
- fd_set fds;
- struct timeval tv;
- ssize_t nRet = 0;
- ssize_t nRead = 0;
- char *pszBuf = (char*)pBuf;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- _CopyTimeval(&tv, &psd->tvRX);
- while(nRead < (ssize_t)nCbToRead)
- {
- FD_ZERO(&fds);
- FD_SET(psd->fd, &fds);
- nRet = select(psd->fd + 1, &fds, NULL, NULL, &tv);
- if(nRet < 0)
- return -1;
- else if(nRet == 0)
- {
- errno = ETIMEDOUT;
- break;
- }
- nRet = read(psd->fd, pszBuf, nCbToRead - nRead);
- if(nRet < 0)
- return -1;
- else if(nRet == 0)
- {
- // should never happen!
- errno = ENODATA;
- return -1;
- }
- else
- {
- pszBuf += nRet;
- nRead += nRet;
- }
- }
- return nRead;
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialRead(HGFADEVICE hSer, void *pBuf, size_t nCbToRead)
- {
- if(hSer && pBuf && nCbToRead)
- {
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- return read(psd->fd, pBuf, nCbToRead);
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialPop(HGFADEVICE hSer, uint8_t *pb)
- {
- if(hSer && pb)
- {
- fd_set fds;
- struct timeval tv;
- ssize_t nRet = 0;
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- FD_ZERO(&fds);
- FD_SET(psd->fd, &fds);
- _CopyTimeval(&tv, &psd->tvRX);
- nRet = select(psd->fd + 1, &fds, NULL, NULL, &tv);
- if(nRet < 0)
- return -1;
- else if(nRet == 0)
- {
- errno = ETIMEDOUT;
- return 0;
- }
- return read(psd->fd, pb, 1);
- }
- errno = EINVAL;
- return -1;
- }
- /////////////////////////////////////////////////////////////////////////////
- ssize_t GfaSerialPeek(HGFADEVICE hSer)
- {
- if(hSer)
- {
- fd_set fds;
- struct timeval tvNull = {0, 0};
- LPGFA_SERIAL_DEVICE psd = (LPGFA_SERIAL_DEVICE)hSer;
- FD_ZERO(&fds);
- FD_SET(psd->fd, &fds);
- return select(psd->fd + 1, &fds, NULL, NULL, &tvNull);
- }
- errno = EINVAL;
- return -1;
- }
|