123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134 |
- /*!
- \file serialib.cpp
- \brief Source file of the class serialib. This class is used for communication over a serial device.
- \author Philippe Lucidarme (University of Angers)
- \version 2.0
- \date december the 27th of 2019
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- This is a licence-free software, it can be used by anyone who try to build a better world.
- */
- #include "serialib.h"
- //_____________________________________
- // ::: Constructors and destructors :::
- /*!
- \brief Constructor of the class serialib.
- */
- serialib::serialib()
- //serialib()
- {
- #if defined (_WIN32) || defined( _WIN64)
- // Set default value for RTS and DTR (Windows only)
- currentStateRTS=true;
- currentStateDTR=true;
- hSerial = INVALID_HANDLE_VALUE;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- fd = -1;
- #endif
- }
- /*!
- \brief Destructor of the class serialib. It close the connection
- */
- // Class desctructor
- serialib::~serialib()
- {
- closeDevice();
- }
- //_________________________________________
- // ::: Configuration and initialization :::
- /*!
- \brief Open the serial port
- \param Device : Port name (COM1, COM2, ... for Windows ) or (/dev/ttyS0, /dev/ttyACM0, /dev/ttyUSB0 ... for linux)
- \param Bauds : Baud rate of the serial port.
- \n Supported baud rate for Windows :
- - 110
- - 300
- - 600
- - 1200
- - 2400
- - 4800
- - 9600
- - 14400
- - 19200
- - 38400
- - 56000
- - 57600
- - 115200
- - 128000
- - 256000
- \n Supported baud rate for Linux :\n
- - 110
- - 300
- - 600
- - 1200
- - 2400
- - 4800
- - 9600
- - 19200
- - 38400
- - 57600
- - 115200
- \n Optionally supported baud rates, depending on Linux kernel:\n
- - 230400
- - 460800
- - 500000
- - 576000
- - 921600
- - 1000000
- - 1152000
- - 1500000
- - 2000000
- - 2500000
- - 3000000
- - 3500000
- - 4000000
- \param Databits : Number of data bits in one UART transmission.
- \n Supported values: \n
- - SERIAL_DATABITS_5 (5)
- - SERIAL_DATABITS_6 (6)
- - SERIAL_DATABITS_7 (7)
- - SERIAL_DATABITS_8 (8)
- - SERIAL_DATABITS_16 (16) (not supported on Unix)
- \param Parity: Parity type
- \n Supported values: \n
- - SERIAL_PARITY_NONE (N)
- - SERIAL_PARITY_EVEN (E)
- - SERIAL_PARITY_ODD (O)
- - SERIAL_PARITY_MARK (MARK) (not supported on Unix)
- - SERIAL_PARITY_SPACE (SPACE) (not supported on Unix)
- \param Stopbit: Number of stop bits
- \n Supported values:
- - SERIAL_STOPBITS_1 (1)
- - SERIAL_STOPBITS_1_5 (1.5) (not supported on Unix)
- - SERIAL_STOPBITS_2 (2)
- \return 1 success
- \return -1 device not found
- \return -2 error while opening the device
- \return -3 error while getting port parameters
- \return -4 Speed (Bauds) not recognized
- \return -5 error while writing port parameters
- \return -6 error while writing timeout parameters
- \return -7 Databits not recognized
- \return -8 Stopbits not recognized
- \return -9 Parity not recognized
- */
- char serialib::openDevice(const char *Device, const unsigned int Bauds,
- SerialDataBits Databits,
- SerialParity Parity,
- SerialStopBits Stopbits) {
- #if defined (_WIN32) || defined( _WIN64)
- // Open serial port
- hSerial = CreateFileA(Device,GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,/*FILE_ATTRIBUTE_NORMAL*/0,0);
- if(hSerial==INVALID_HANDLE_VALUE) {
- if(GetLastError()==ERROR_FILE_NOT_FOUND)
- return -1; // Device not found
- // Error while opening the device
- return -2;
- }
- // Set parameters
- // Structure for the port parameters
- DCB dcbSerialParams;
- dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
- // Get the port parameters
- if (!GetCommState(hSerial, &dcbSerialParams)) return -3;
- // Set the speed (Bauds)
- switch (Bauds)
- {
- case 110 : dcbSerialParams.BaudRate=CBR_110; break;
- case 300 : dcbSerialParams.BaudRate=CBR_300; break;
- case 600 : dcbSerialParams.BaudRate=CBR_600; break;
- case 1200 : dcbSerialParams.BaudRate=CBR_1200; break;
- case 2400 : dcbSerialParams.BaudRate=CBR_2400; break;
- case 4800 : dcbSerialParams.BaudRate=CBR_4800; break;
- case 9600 : dcbSerialParams.BaudRate=CBR_9600; break;
- case 14400 : dcbSerialParams.BaudRate=CBR_14400; break;
- case 19200 : dcbSerialParams.BaudRate=CBR_19200; break;
- case 38400 : dcbSerialParams.BaudRate=CBR_38400; break;
- case 56000 : dcbSerialParams.BaudRate=CBR_56000; break;
- case 57600 : dcbSerialParams.BaudRate=CBR_57600; break;
- case 115200 : dcbSerialParams.BaudRate=CBR_115200; break;
- case 128000 : dcbSerialParams.BaudRate=CBR_128000; break;
- case 256000 : dcbSerialParams.BaudRate=CBR_256000; break;
- default : return -4;
- }
- //select data size
- BYTE bytesize = 0;
- switch(Databits) {
- case SERIAL_DATABITS_5: bytesize = 5; break;
- case SERIAL_DATABITS_6: bytesize = 6; break;
- case SERIAL_DATABITS_7: bytesize = 7; break;
- case SERIAL_DATABITS_8: bytesize = 8; break;
- case SERIAL_DATABITS_16: bytesize = 16; break;
- default: return -7;
- }
- BYTE stopBits = 0;
- switch(Stopbits) {
- case SERIAL_STOPBITS_1: stopBits = ONESTOPBIT; break;
- case SERIAL_STOPBITS_1_5: stopBits = ONE5STOPBITS; break;
- case SERIAL_STOPBITS_2: stopBits = TWOSTOPBITS; break;
- default: return -8;
- }
- BYTE parity = 0;
- switch(Parity) {
- case SERIAL_PARITY_NONE: parity = NOPARITY; break;
- case SERIAL_PARITY_EVEN: parity = EVENPARITY; break;
- case SERIAL_PARITY_ODD: parity = ODDPARITY; break;
- case SERIAL_PARITY_MARK: parity = MARKPARITY; break;
- case SERIAL_PARITY_SPACE: parity = SPACEPARITY; break;
- default: return -9;
- }
- // configure byte size
- dcbSerialParams.ByteSize = bytesize;
- // configure stop bits
- dcbSerialParams.StopBits = stopBits;
- // configure parity
- dcbSerialParams.Parity = parity;
- // Write the parameters
- if(!SetCommState(hSerial, &dcbSerialParams)) return -5;
- // Set TimeOut
- // Set the Timeout parameters
- timeouts.ReadIntervalTimeout=0;
- // No TimeOut
- timeouts.ReadTotalTimeoutConstant=MAXDWORD;
- timeouts.ReadTotalTimeoutMultiplier=0;
- timeouts.WriteTotalTimeoutConstant=MAXDWORD;
- timeouts.WriteTotalTimeoutMultiplier=0;
- // Write the parameters
- if(!SetCommTimeouts(hSerial, &timeouts)) return -6;
- // Opening successfull
- return 1;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Structure with the device's options
- struct termios options;
- // Open device
- fd = open(Device, O_RDWR | O_NOCTTY | O_NDELAY);
- // If the device is not open, return -1
- if (fd == -1) return -2;
- // Open the device in nonblocking mode
- fcntl(fd, F_SETFL, FNDELAY);
- // Get the current options of the port
- tcgetattr(fd, &options);
- // Clear all the options
- bzero(&options, sizeof(options));
- // Prepare speed (Bauds)
- speed_t Speed;
- switch (Bauds)
- {
- case 110 : Speed=B110; break;
- case 300 : Speed=B300; break;
- case 600 : Speed=B600; break;
- case 1200 : Speed=B1200; break;
- case 2400 : Speed=B2400; break;
- case 4800 : Speed=B4800; break;
- case 9600 : Speed=B9600; break;
- case 19200 : Speed=B19200; break;
- case 38400 : Speed=B38400; break;
- case 57600 : Speed=B57600; break;
- case 115200 : Speed=B115200; break;
- #if defined (B230400)
- case 230400 : Speed=B230400; break;
- #endif
- #if defined (B460800)
- case 460800 : Speed=B460800; break;
- #endif
- #if defined (B500000)
- case 500000 : Speed=B500000; break;
- #endif
- #if defined (B576000)
- case 576000 : Speed=B576000; break;
- #endif
- #if defined (B921600)
- case 921600 : Speed=B921600; break;
- #endif
- #if defined (B1000000)
- case 1000000 : Speed=B1000000; break;
- #endif
- #if defined (B1152000)
- case 1152000 : Speed=B1152000; break;
- #endif
- #if defined (B1500000)
- case 1500000 : Speed=B1500000; break;
- #endif
- #if defined (B2000000)
- case 2000000 : Speed=B2000000; break;
- #endif
- #if defined (B2500000)
- case 2500000 : Speed=B2500000; break;
- #endif
- #if defined (B3000000)
- case 3000000 : Speed=B3000000; break;
- #endif
- #if defined (B3500000)
- case 3500000 : Speed=B3500000; break;
- #endif
- #if defined (B4000000)
- case 4000000 : Speed=B4000000; break;
- #endif
- default : return -4;
- }
- int databits_flag = 0;
- switch(Databits) {
- case SERIAL_DATABITS_5: databits_flag = CS5; break;
- case SERIAL_DATABITS_6: databits_flag = CS6; break;
- case SERIAL_DATABITS_7: databits_flag = CS7; break;
- case SERIAL_DATABITS_8: databits_flag = CS8; break;
- //16 bits and everything else not supported
- default: return -7;
- }
- int stopbits_flag = 0;
- switch(Stopbits) {
- case SERIAL_STOPBITS_1: stopbits_flag = 0; break;
- case SERIAL_STOPBITS_2: stopbits_flag = CSTOPB; break;
- //1.5 stopbits and everything else not supported
- default: return -8;
- }
- int parity_flag = 0;
- switch(Parity) {
- case SERIAL_PARITY_NONE: parity_flag = 0; break;
- case SERIAL_PARITY_EVEN: parity_flag = PARENB; break;
- case SERIAL_PARITY_ODD: parity_flag = (PARENB | PARODD); break;
- //mark and space parity not supported
- default: return -9;
- }
- // Set the baud rate
- cfsetispeed(&options, Speed);
- cfsetospeed(&options, Speed);
- // Configure the device : data bits, stop bits, parity, no control flow
- // Ignore modem control lines (CLOCAL) and Enable receiver (CREAD)
- options.c_cflag |= ( CLOCAL | CREAD | databits_flag | parity_flag | stopbits_flag);
- options.c_iflag |= ( IGNPAR | IGNBRK );
- // Timer unused
- options.c_cc[VTIME]=0;
- // At least on character before satisfy reading
- options.c_cc[VMIN]=0;
- // Activate the settings
- tcsetattr(fd, TCSANOW, &options);
- // Success
- return (1);
- #endif
- }
- bool serialib::isDeviceOpen()
- {
- #if defined (_WIN32) || defined( _WIN64)
- return hSerial != INVALID_HANDLE_VALUE;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- return fd >= 0;
- #endif
- }
- /*!
- \brief Close the connection with the current device
- */
- void serialib::closeDevice()
- {
- #if defined (_WIN32) || defined( _WIN64)
- CloseHandle(hSerial);
- hSerial = INVALID_HANDLE_VALUE;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- close (fd);
- fd = -1;
- #endif
- }
- //___________________________________________
- // ::: Read/Write operation on characters :::
- /*!
- \brief Write a char on the current serial port
- \param Byte : char to send on the port (must be terminated by '\0')
- \return 1 success
- \return -1 error while writting data
- */
- int serialib::writeChar(const char Byte)
- {
- #if defined (_WIN32) || defined( _WIN64)
- // Number of bytes written
- DWORD dwBytesWritten;
- // Write the char to the serial device
- // Return -1 if an error occured
- if(!WriteFile(hSerial,&Byte,1,&dwBytesWritten,NULL)) return -1;
- // Write operation successfull
- return 1;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Write the char
- if (write(fd,&Byte,1)!=1) return -1;
- // Write operation successfull
- return 1;
- #endif
- }
- //________________________________________
- // ::: Read/Write operation on strings :::
- /*!
- \brief Write a string on the current serial port
- \param receivedString : string to send on the port (must be terminated by '\0')
- \return 1 success
- \return -1 error while writting data
- */
- int serialib::writeString(const char *receivedString)
- {
- #if defined (_WIN32) || defined( _WIN64)
- // Number of bytes written
- DWORD dwBytesWritten;
- // Write the string
- if(!WriteFile(hSerial,receivedString,strlen(receivedString),&dwBytesWritten,NULL))
- // Error while writing, return -1
- return -1;
- // Write operation successfull
- return 1;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Lenght of the string
- int Lenght=strlen(receivedString);
- // Write the string
- if (write(fd,receivedString,Lenght)!=Lenght) return -1;
- // Write operation successfull
- return 1;
- #endif
- }
- // _____________________________________
- // ::: Read/Write operation on bytes :::
- /*!
- \brief Write an array of data on the current serial port
- \param Buffer : array of bytes to send on the port
- \param NbBytes : number of byte to send
- \return 1 success
- \return -1 error while writting data
- */
- int serialib::writeBytes(const void *Buffer, const unsigned int NbBytes)
- {
- #if defined (_WIN32) || defined( _WIN64)
- // Number of bytes written
- DWORD dwBytesWritten;
- // Write data
- if(!WriteFile(hSerial, Buffer, NbBytes, &dwBytesWritten, NULL))
- // Error while writing, return -1
- return -1;
- // Write operation successfull
- return 1;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Write data
- if (write (fd,Buffer,NbBytes)!=(ssize_t)NbBytes) return -1;
- // Write operation successfull
- return 1;
- #endif
- }
- /*!
- \brief Wait for a byte from the serial device and return the data read
- \param pByte : data read on the serial device
- \param timeOut_ms : delay of timeout before giving up the reading
- If set to zero, timeout is disable (Optional)
- \return 1 success
- \return 0 Timeout reached
- \return -1 error while setting the Timeout
- \return -2 error while reading the byte
- */
- int serialib::readChar(char *pByte,unsigned int timeOut_ms)
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Number of bytes read
- DWORD dwBytesRead = 0;
- // Set the TimeOut
- timeouts.ReadTotalTimeoutConstant=timeOut_ms;
- // Write the parameters, return -1 if an error occured
- if(!SetCommTimeouts(hSerial, &timeouts)) return -1;
- // Read the byte, return -2 if an error occured
- if(!ReadFile(hSerial,pByte, 1, &dwBytesRead, NULL)) return -2;
- // Return 0 if the timeout is reached
- if (dwBytesRead==0) return 0;
- // The byte is read
- return 1;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Timer used for timeout
- timeOut timer;
- // Initialise the timer
- timer.initTimer();
- // While Timeout is not reached
- while (timer.elapsedTime_ms()<timeOut_ms || timeOut_ms==0)
- {
- // Try to read a byte on the device
- switch (read(fd,pByte,1)) {
- case 1 : return 1; // Read successfull
- case -1 : return -2; // Error while reading
- }
- }
- return 0;
- #endif
- }
- /*!
- \brief Read a string from the serial device (without TimeOut)
- \param receivedString : string read on the serial device
- \param FinalChar : final char of the string
- \param MaxNbBytes : maximum allowed number of bytes read
- \return >0 success, return the number of bytes read
- \return -1 error while setting the Timeout
- \return -2 error while reading the byte
- \return -3 MaxNbBytes is reached
- */
- int serialib::readStringNoTimeOut(char *receivedString,char finalChar,unsigned int maxNbBytes)
- {
- // Number of characters read
- unsigned int NbBytes=0;
- // Returned value from Read
- char charRead;
- // While the buffer is not full
- while (NbBytes<maxNbBytes)
- {
- // Read a character with the restant time
- charRead=readChar(&receivedString[NbBytes]);
- // Check a character has been read
- if (charRead==1)
- {
- // Check if this is the final char
- if (receivedString[NbBytes]==finalChar)
- {
- // This is the final char, add zero (end of string)
- receivedString [++NbBytes]=0;
- // Return the number of bytes read
- return NbBytes;
- }
- // The character is not the final char, increase the number of bytes read
- NbBytes++;
- }
- // An error occured while reading, return the error number
- if (charRead<0) return charRead;
- }
- // Buffer is full : return -3
- return -3;
- }
- /*!
- \brief Read a string from the serial device (with timeout)
- \param receivedString : string read on the serial device
- \param finalChar : final char of the string
- \param maxNbBytes : maximum allowed number of characters read
- \param timeOut_ms : delay of timeout before giving up the reading (optional)
- \return >0 success, return the number of bytes read (including the null character)
- \return 0 timeout is reached
- \return -1 error while setting the Timeout
- \return -2 error while reading the character
- \return -3 MaxNbBytes is reached
- */
- int serialib::readString(char *receivedString,char finalChar,unsigned int maxNbBytes,unsigned int timeOut_ms)
- {
- // Check if timeout is requested
- if (timeOut_ms==0) return readStringNoTimeOut(receivedString,finalChar,maxNbBytes);
- // Number of bytes read
- unsigned int nbBytes=0;
- // Character read on serial device
- char charRead;
- // Timer used for timeout
- timeOut timer;
- long int timeOutParam;
- // Initialize the timer (for timeout)
- timer.initTimer();
- // While the buffer is not full
- while (nbBytes<maxNbBytes)
- {
- // Compute the TimeOut for the next call of ReadChar
- timeOutParam = timeOut_ms-timer.elapsedTime_ms();
- // If there is time remaining
- if (timeOutParam>0)
- {
- // Wait for a byte on the serial link with the remaining time as timeout
- charRead=readChar(&receivedString[nbBytes],timeOutParam);
- // If a byte has been received
- if (charRead==1)
- {
- // Check if the character received is the final one
- if (receivedString[nbBytes]==finalChar)
- {
- // Final character: add the end character 0
- receivedString [++nbBytes]=0;
- // Return the number of bytes read
- return nbBytes;
- }
- // This is not the final character, just increase the number of bytes read
- nbBytes++;
- }
- // Check if an error occured during reading char
- // If an error occurend, return the error number
- if (charRead<0) return charRead;
- }
- // Check if timeout is reached
- if (timer.elapsedTime_ms()>timeOut_ms)
- {
- // Add the end caracter
- receivedString[nbBytes]=0;
- // Return 0 (timeout reached)
- return 0;
- }
- }
- // Buffer is full : return -3
- return -3;
- }
- /*!
- \brief Read an array of bytes from the serial device (with timeout)
- \param buffer : array of bytes read from the serial device
- \param maxNbBytes : maximum allowed number of bytes read
- \param timeOut_ms : delay of timeout before giving up the reading
- \param sleepDuration_us : delay of CPU relaxing in microseconds (Linux only)
- In the reading loop, a sleep can be performed after each reading
- This allows CPU to perform other tasks
- \return >=0 return the number of bytes read before timeout or
- requested data is completed
- \return -1 error while setting the Timeout
- \return -2 error while reading the byte
- */
- int serialib::readBytes (void *buffer,unsigned int maxNbBytes,unsigned int timeOut_ms, unsigned int sleepDuration_us)
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Avoid warning while compiling
- UNUSED(sleepDuration_us);
- // Number of bytes read
- DWORD dwBytesRead = 0;
- // Set the TimeOut
- timeouts.ReadTotalTimeoutConstant=(DWORD)timeOut_ms;
- // Write the parameters and return -1 if an error occrured
- if(!SetCommTimeouts(hSerial, &timeouts)) return -1;
- // Read the bytes from the serial device, return -2 if an error occured
- if(!ReadFile(hSerial,buffer,(DWORD)maxNbBytes,&dwBytesRead, NULL)) return -2;
- // Return the byte read
- return dwBytesRead;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Timer used for timeout
- timeOut timer;
- // Initialise the timer
- timer.initTimer();
- unsigned int NbByteRead=0;
- // While Timeout is not reached
- while (timer.elapsedTime_ms()<timeOut_ms || timeOut_ms==0)
- {
- // Compute the position of the current byte
- unsigned char* Ptr=(unsigned char*)buffer+NbByteRead;
- // Try to read a byte on the device
- int Ret=read(fd,(void*)Ptr,maxNbBytes-NbByteRead);
- // Error while reading
- if (Ret==-1) return -2;
- // One or several byte(s) has been read on the device
- if (Ret>0)
- {
- // Increase the number of read bytes
- NbByteRead+=Ret;
- // Success : bytes has been read
- if (NbByteRead>=maxNbBytes)
- return NbByteRead;
- }
- // Suspend the loop to avoid charging the CPU
- usleep (sleepDuration_us);
- }
- // Timeout reached, return the number of bytes read
- return NbByteRead;
- #endif
- }
- // _________________________
- // ::: Special operation :::
- /*!
- \brief Empty receiver buffer
- \return If the function succeeds, the return value is nonzero.
- If the function fails, the return value is zero.
- */
- char serialib::flushReceiver()
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Purge receiver
- return PurgeComm (hSerial, PURGE_RXCLEAR);
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Purge receiver
- tcflush(fd,TCIFLUSH);
- return true;
- #endif
- }
- /*!
- \brief Return the number of bytes in the received buffer (UNIX only)
- \return The number of bytes received by the serial provider but not yet read.
- */
- int serialib::available()
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Device errors
- DWORD commErrors;
- // Device status
- COMSTAT commStatus;
- // Read status
- ClearCommError(hSerial, &commErrors, &commStatus);
- // Return the number of pending bytes
- return commStatus.cbInQue;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- int nBytes=0;
- // Return number of pending bytes in the receiver
- ioctl(fd, FIONREAD, &nBytes);
- return nBytes;
- #endif
- }
- // __________________
- // ::: I/O Access :::
- /*!
- \brief Set or unset the bit DTR (pin 4)
- DTR stands for Data Terminal Ready
- Convenience method :This method calls setDTR and clearDTR
- \param status = true set DTR
- status = false unset DTR
- \return If the function fails, the return value is false
- If the function succeeds, the return value is true.
- */
- bool serialib::DTR(bool status)
- {
- if (status)
- // Set DTR
- return this->setDTR();
- else
- // Unset DTR
- return this->clearDTR();
- }
- /*!
- \brief Set the bit DTR (pin 4)
- DTR stands for Data Terminal Ready
- \return If the function fails, the return value is false
- If the function succeeds, the return value is true.
- */
- bool serialib::setDTR()
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Set DTR
- currentStateDTR=true;
- return EscapeCommFunction(hSerial,SETDTR);
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Set DTR
- int status_DTR=0;
- ioctl(fd, TIOCMGET, &status_DTR);
- status_DTR |= TIOCM_DTR;
- ioctl(fd, TIOCMSET, &status_DTR);
- return true;
- #endif
- }
- /*!
- \brief Clear the bit DTR (pin 4)
- DTR stands for Data Terminal Ready
- \return If the function fails, the return value is false
- If the function succeeds, the return value is true.
- */
- bool serialib::clearDTR()
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Clear DTR
- currentStateDTR=true;
- return EscapeCommFunction(hSerial,CLRDTR);
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Clear DTR
- int status_DTR=0;
- ioctl(fd, TIOCMGET, &status_DTR);
- status_DTR &= ~TIOCM_DTR;
- ioctl(fd, TIOCMSET, &status_DTR);
- return true;
- #endif
- }
- /*!
- \brief Set or unset the bit RTS (pin 7)
- RTS stands for Data Termina Ready
- Convenience method :This method calls setDTR and clearDTR
- \param status = true set DTR
- status = false unset DTR
- \return false if the function fails
- \return true if the function succeeds
- */
- bool serialib::RTS(bool status)
- {
- if (status)
- // Set RTS
- return this->setRTS();
- else
- // Unset RTS
- return this->clearRTS();
- }
- /*!
- \brief Set the bit RTS (pin 7)
- RTS stands for Data Terminal Ready
- \return If the function fails, the return value is false
- If the function succeeds, the return value is true.
- */
- bool serialib::setRTS()
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Set RTS
- currentStateRTS=false;
- return EscapeCommFunction(hSerial,SETRTS);
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Set RTS
- int status_RTS=0;
- ioctl(fd, TIOCMGET, &status_RTS);
- status_RTS |= TIOCM_RTS;
- ioctl(fd, TIOCMSET, &status_RTS);
- return true;
- #endif
- }
- /*!
- \brief Clear the bit RTS (pin 7)
- RTS stands for Data Terminal Ready
- \return If the function fails, the return value is false
- If the function succeeds, the return value is true.
- */
- bool serialib::clearRTS()
- {
- #if defined (_WIN32) || defined(_WIN64)
- // Clear RTS
- currentStateRTS=false;
- return EscapeCommFunction(hSerial,CLRRTS);
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- // Clear RTS
- int status_RTS=0;
- ioctl(fd, TIOCMGET, &status_RTS);
- status_RTS &= ~TIOCM_RTS;
- ioctl(fd, TIOCMSET, &status_RTS);
- return true;
- #endif
- }
- /*!
- \brief Get the CTS's status (pin 8)
- CTS stands for Clear To Send
- \return Return true if CTS is set otherwise false
- */
- bool serialib::isCTS()
- {
- #if defined (_WIN32) || defined(_WIN64)
- DWORD modemStat;
- GetCommModemStatus(hSerial, &modemStat);
- return modemStat & MS_CTS_ON;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- int status=0;
- //Get the current status of the CTS bit
- ioctl(fd, TIOCMGET, &status);
- return status & TIOCM_CTS;
- #endif
- }
- /*!
- \brief Get the DSR's status (pin 6)
- DSR stands for Data Set Ready
- \return Return true if DTR is set otherwise false
- */
- bool serialib::isDSR()
- {
- #if defined (_WIN32) || defined(_WIN64)
- DWORD modemStat;
- GetCommModemStatus(hSerial, &modemStat);
- return modemStat & MS_DSR_ON;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- int status=0;
- //Get the current status of the DSR bit
- ioctl(fd, TIOCMGET, &status);
- return status & TIOCM_DSR;
- #endif
- }
- /*!
- \brief Get the DCD's status (pin 1)
- CDC stands for Data Carrier Detect
- \return true if DCD is set
- \return false otherwise
- */
- bool serialib::isDCD()
- {
- #if defined (_WIN32) || defined(_WIN64)
- DWORD modemStat;
- GetCommModemStatus(hSerial, &modemStat);
- return modemStat & MS_RLSD_ON;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- int status=0;
- //Get the current status of the DCD bit
- ioctl(fd, TIOCMGET, &status);
- return status & TIOCM_CAR;
- #endif
- }
- /*!
- \brief Get the RING's status (pin 9)
- Ring Indicator
- \return Return true if RING is set otherwise false
- */
- bool serialib::isRI()
- {
- #if defined (_WIN32) || defined(_WIN64)
- DWORD modemStat;
- GetCommModemStatus(hSerial, &modemStat);
- return modemStat & MS_RING_ON;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- int status=0;
- //Get the current status of the RING bit
- ioctl(fd, TIOCMGET, &status);
- return status & TIOCM_RNG;
- #endif
- }
- /*!
- \brief Get the DTR's status (pin 4)
- DTR stands for Data Terminal Ready
- May behave abnormally on Windows
- \return Return true if CTS is set otherwise false
- */
- bool serialib::isDTR()
- {
- #if defined (_WIN32) || defined( _WIN64)
- return currentStateDTR;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- int status=0;
- //Get the current status of the DTR bit
- ioctl(fd, TIOCMGET, &status);
- return status & TIOCM_DTR ;
- #endif
- }
- /*!
- \brief Get the RTS's status (pin 7)
- RTS stands for Request To Send
- May behave abnormally on Windows
- \return Return true if RTS is set otherwise false
- */
- bool serialib::isRTS()
- {
- #if defined (_WIN32) || defined(_WIN64)
- return currentStateRTS;
- #endif
- #if defined (__linux__) || defined(__APPLE__)
- int status=0;
- //Get the current status of the CTS bit
- ioctl(fd, TIOCMGET, &status);
- return status & TIOCM_RTS;
- #endif
- }
- // ******************************************
- // Class timeOut
- // ******************************************
- /*!
- \brief Constructor of the class timeOut.
- */
- // Constructor
- timeOut::timeOut()
- {}
- /*!
- \brief Initialise the timer. It writes the current time of the day in the structure PreviousTime.
- */
- //Initialize the timer
- void timeOut::initTimer()
- {
- #if defined (NO_POSIX_TIME)
- LARGE_INTEGER tmp;
- QueryPerformanceFrequency(&tmp);
- counterFrequency = tmp.QuadPart;
- // Used to store the previous time (for computing timeout)
- QueryPerformanceCounter(&tmp);
- previousTime = tmp.QuadPart;
- #else
- gettimeofday(&previousTime, NULL);
- #endif
- }
- /*!
- \brief Returns the time elapsed since initialization. It write the current time of the day in the structure CurrentTime.
- Then it returns the difference between CurrentTime and PreviousTime.
- \return The number of microseconds elapsed since the functions InitTimer was called.
- */
- //Return the elapsed time since initialization
- unsigned long int timeOut::elapsedTime_ms()
- {
- #if defined (NO_POSIX_TIME)
- // Current time
- LARGE_INTEGER CurrentTime;
- // Number of ticks since last call
- int sec;
- // Get current time
- QueryPerformanceCounter(&CurrentTime);
- // Compute the number of ticks elapsed since last call
- sec=CurrentTime.QuadPart-previousTime;
- // Return the elapsed time in milliseconds
- return sec/(counterFrequency/1000);
- #else
- // Current time
- struct timeval CurrentTime;
- // Number of seconds and microseconds since last call
- int sec,usec;
- // Get current time
- gettimeofday(&CurrentTime, NULL);
- // Compute the number of seconds and microseconds elapsed since last call
- sec=CurrentTime.tv_sec-previousTime.tv_sec;
- usec=CurrentTime.tv_usec-previousTime.tv_usec;
- // If the previous usec is higher than the current one
- if (usec<0)
- {
- // Recompute the microseonds and substract one second
- usec=1000000-previousTime.tv_usec+CurrentTime.tv_usec;
- sec--;
- }
- // Return the elapsed time in milliseconds
- return sec*1000+usec/1000;
- #endif
- }
|