Mercurial > public > ostc_companion
diff Serial.cpp @ 10:9a3c1a6f9833
TODO: FIX HW flow control definitions in case of problem during communication. Background: Flags are not defined in terminos header
| author | Ideenmodellierer |
|---|---|
| date | Mon, 12 Jan 2026 13:55:38 +0000 |
| parents | 177f640940f2 |
| children |
line wrap: on
line diff
--- a/Serial.cpp Mon Jan 12 13:52:28 2026 +0000 +++ b/Serial.cpp Mon Jan 12 13:55:38 2026 +0000 @@ -36,58 +36,62 @@ #include "Serial.h" +#include "Utils/Exception.h" #include "Utils/Log.h" -#include "Utils/Exception.h" #include <QString> +#ifdef Q_OS_LINUX +#include <termios.h> +#endif + #ifdef WIN32 -# define S_WRITE(p, b, li, lo) WriteFile(p, b, li, &lo, NULL) -# define S_READ(p, b, li, lo) ReadFile(p, b, li, &lo, NULL) -# define S_LEN DWORD -# define S_FLUSH(p) FlushFileBuffers(p) -# define S_PURGE(p) PurgeComm(p, PURGE_RXCLEAR | PURGE_TXCLEAR) -# define S_CLOSE(p) CloseHandle(p) +#define S_WRITE(p, b, li, lo) WriteFile(p, b, li, &lo, NULL) +#define S_READ(p, b, li, lo) ReadFile(p, b, li, &lo, NULL) +#define S_LEN DWORD +#define S_FLUSH(p) FlushFileBuffers(p) +#define S_PURGE(p) PurgeComm(p, PURGE_RXCLEAR | PURGE_TXCLEAR) +#define S_CLOSE(p) CloseHandle(p) #else -# include <fcntl.h> -# include <termios.h> -# include <sys/ioctl.h> -# include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <unistd.h> -# define INVALID_HANDLE_VALUE (-1) -# define S_WRITE(p, b, li, lo) (lo = write(p, b, li)) -# define S_READ(p, b, li, lo) (lo = read (p, b, li)) -# define S_LEN ssize_t -# define S_FLUSH(p) tcdrain(p) -# define S_PURGE(p) tcflush(p,TCIOFLUSH) -# define S_CLOSE(p) ::close(p) +#define INVALID_HANDLE_VALUE (-1) +#define S_WRITE(p, b, li, lo) (lo = write(p, b, li)) +#define S_READ(p, b, li, lo) (lo = read(p, b, li)) +#define S_LEN ssize_t +#define S_FLUSH(p) tcdrain(p) +#define S_PURGE(p) tcflush(p, TCIOFLUSH) +#define S_CLOSE(p) ::close(p) #endif /////////////////////////////////////////////////////////////////////////////// -Serial::~Serial() -{} +Serial::~Serial() {} /////////////////////////////////////////////////////////////////////////////// -void Serial::open(const QString& port, const QString &type) +void Serial::open(const QString &port, const QString &type) { - if( _isOpen ) return; + if (_isOpen) + return; LOG_TRACE("Open " << port << " ..."); _hSerial = INVALID_HANDLE_VALUE; //------------------------------------------------------------------------ // Sanity checks. - if( port.isEmpty() ) - LOG_THROW( "Port is not defined." ); - if( type.isEmpty() ) - LOG_THROW( "Port type is not defined." ); + if (port.isEmpty()) + LOG_THROW("Port is not defined."); + if (type.isEmpty()) + LOG_THROW("Port type is not defined."); - bool usbMode = type.contains("ostc2c", Qt::CaseInsensitive) - || ( type.contains("ostc3", Qt::CaseInsensitive) - && !type.contains("ostc3p", Qt::CaseInsensitive)) - || type.contains("ostc_cr", Qt::CaseInsensitive); + bool usbMode = type.contains("ostc2c", Qt::CaseInsensitive) + || (type.contains("ostc3", Qt::CaseInsensitive) + && !type.contains("ostc3p", Qt::CaseInsensitive)) + || type.contains("ostc_cr", Qt::CaseInsensitive); LOG_TRACE((usbMode ? "Fast USB" : "Slow Bluetooth") << " connection mode."); //------------------------------------------------------------------------ @@ -96,104 +100,105 @@ // hence we have to prepend DEVICE NAMESPACE... // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx QByteArray com = port.toLatin1() + "\0"; - if( !com.startsWith("\\\\.\\") ) + if (!com.startsWith("\\\\.\\")) com = "\\\\.\\" + com; _hSerial = CreateFileA(com.data(), - GENERIC_READ | GENERIC_WRITE, - 0, // Exclusive access. - NULL, // No security - OPEN_EXISTING, - FILE_ATTRIBUTE_DEVICE | FILE_FLAG_NO_BUFFERING, - 0); - if(_hSerial==INVALID_HANDLE_VALUE) - { - if(GetLastError()==ERROR_FILE_NOT_FOUND) - LOG_THROW( "Unknown port" ); - LOG_THROW( "Unable to open port" ); + GENERIC_READ | GENERIC_WRITE, + 0, // Exclusive access. + NULL, // No security + OPEN_EXISTING, + FILE_ATTRIBUTE_DEVICE | FILE_FLAG_NO_BUFFERING, + 0); + if (_hSerial == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + LOG_THROW("Unknown port"); + LOG_THROW("Unable to open port"); } S_PURGE(_hSerial); DCB dcbSerial = {sizeof(dcbSerial), 0}; - if( !GetCommState(_hSerial, &dcbSerial) ) - LOG_THROW( "Unable to get COM port config" ); + if (!GetCommState(_hSerial, &dcbSerial)) + LOG_THROW("Unable to get COM port config"); - dcbSerial.BaudRate = CBR_115200; - dcbSerial.ByteSize = 8; - dcbSerial.Parity = NOPARITY; - dcbSerial.StopBits = ONESTOPBIT; - dcbSerial.fOutxCtsFlow = DTR_CONTROL_ENABLE; // NO HARDWARE FLOW CONTROL - dcbSerial.fRtsControl = RTS_CONTROL_ENABLE; //RTS_CONTROL_DISABLE; // NO HARDWARE FLOW CONTROL + dcbSerial.BaudRate = CBR_115200; + dcbSerial.ByteSize = 8; + dcbSerial.Parity = NOPARITY; + dcbSerial.StopBits = ONESTOPBIT; + dcbSerial.fOutxCtsFlow = DTR_CONTROL_ENABLE; // NO HARDWARE FLOW CONTROL + dcbSerial.fRtsControl = RTS_CONTROL_ENABLE; //RTS_CONTROL_DISABLE; // NO HARDWARE FLOW CONTROL - if( !SetCommState(_hSerial, &dcbSerial) ) - LOG_THROW( "Unable to set COM port config" ); + if (!SetCommState(_hSerial, &dcbSerial)) + LOG_THROW("Unable to set COM port config"); - COMMTIMEOUTS timeouts={0}; - if( usbMode ) { - timeouts.ReadTotalTimeoutConstant = 500; // 0.5 sec - timeouts.WriteTotalTimeoutConstant = 1000; // 1.0 sec + COMMTIMEOUTS timeouts = {0}; + if (usbMode) { + timeouts.ReadTotalTimeoutConstant = 500; // 0.5 sec + timeouts.WriteTotalTimeoutConstant = 1000; // 1.0 sec } else { - timeouts.ReadTotalTimeoutConstant = 2000; // 2.0 sec timeout. + timeouts.ReadTotalTimeoutConstant = 2000; // 2.0 sec timeout. } - if( !SetCommTimeouts(_hSerial, &timeouts) ) - LOG_THROW( "Unable to configure port" ); + if (!SetCommTimeouts(_hSerial, &timeouts)) + LOG_THROW("Unable to configure port"); LOG_TRACE("Connection:"); LOG_TRACE(" " << dcbSerial.BaudRate << " bauds."); - LOG_TRACE(" " << (int)dcbSerial.ByteSize << " bits, " - << (dcbSerial.Parity ? "+parity, " : "no parity, ") - << (dcbSerial.StopBits ? QString(" +%1").arg(dcbSerial.StopBits) : QString("no")) << " stops bits."); + LOG_TRACE( + " " << (int) dcbSerial.ByteSize << " bits, " + << (dcbSerial.Parity ? "+parity, " : "no parity, ") + << (dcbSerial.StopBits ? QString(" +%1").arg(dcbSerial.StopBits) : QString("no")) + << " stops bits."); LOG_TRACE(" CTS is " << (dcbSerial.fOutxCtsFlow ? "ON." : "OFF.")); LOG_TRACE(" RTS is " << ((dcbSerial.fRtsControl == RTS_CONTROL_HANDSHAKE) ? "ON." - : (dcbSerial.fRtsControl == RTS_CONTROL_ENABLE) ? "FORCED." - : "OFF.")); - LOG_TRACE(" Read timeout " << timeouts.ReadTotalTimeoutConstant << " msec."); + : (dcbSerial.fRtsControl == RTS_CONTROL_ENABLE) ? "FORCED." + : "OFF.")); + LOG_TRACE(" Read timeout " << timeouts.ReadTotalTimeoutConstant << " msec."); LOG_TRACE(" Write timeout " << timeouts.WriteTotalTimeoutConstant << " msec."); #endif //------------------------------------------------------------------------ #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) QByteArray p = port.toLatin1(); - if( ! p.startsWith("/dev/") ) + if (!p.startsWith("/dev/")) p = "/dev/" + p; - _hSerial = ::open( p.constData(), O_RDWR | O_NOCTTY | O_NONBLOCK, 0); - if( _hSerial<0 ) - LOG_THROW( "Unable to open port " << p); + _hSerial = ::open(p.constData(), O_RDWR | O_NOCTTY | O_NONBLOCK, 0); + if (_hSerial < 0) + LOG_THROW("Unable to open port " << p); - if( ioctl(_hSerial, TIOCEXCL) < 0 ) - LOG_THROW( "Port in use" ); + if (ioctl(_hSerial, TIOCEXCL) < 0) + LOG_THROW("Port in use"); // Once opened, clearing the O_NONBLOCK flag. - if( fcntl(_hSerial, F_SETFL, 0) < 0 ) - LOG_THROW( "Can't reset non-blocking I/O" ); + if (fcntl(_hSerial, F_SETFL, 0) < 0) + LOG_THROW("Can't reset non-blocking I/O"); struct termios termios; tcgetattr(_hSerial, &termios); cfmakeraw(&termios); - if( cfsetspeed(&termios, B115200) < 0 ) - LOG_THROW( "Bad port speed" ); + if (cfsetspeed(&termios, B115200) < 0) + LOG_THROW("Bad port speed"); - termios.c_cflag |= CLOCAL| CS8 | CREAD; // No DTR/DSR/DCD, 8bit. - termios.c_cflag &= ~( PARENB | CSTOPB // No parity, one stop bit. - | CCTS_OFLOW | CRTS_IFLOW); // No hardware flow control. + termios.c_cflag |= CLOCAL | CS8 | CREAD; // No DTR/DSR/DCD, 8bit. + termios.c_cflag &= ~(PARENB | CSTOPB ); // No parity, one stop bit. + // | CCTS_OFLOW | CRTS_IFLOW); // No hardware flow control. - if( usbMode ) { + if (usbMode) { // FAST USB: Fix timeout to 0.5 seconde: - termios.c_cc[VMIN] = 0; // Pure timout mode (no char needed). - termios.c_cc[VTIME] = 5; // 0.5s timeout after last received byte. + termios.c_cc[VMIN] = 0; // Pure timout mode (no char needed). + termios.c_cc[VTIME] = 5; // 0.5s timeout after last received byte. } else { // SLOW BLUETOOTH: Fix timeout to 2.0 sec: - termios.c_cc[VMIN] = 0; // Pure timout mode (no char needed). - termios.c_cc[VTIME] = 20; // 2.0sec timeout after last received byte. + termios.c_cc[VMIN] = 0; // Pure timout mode (no char needed). + termios.c_cc[VTIME] = 20; // 2.0sec timeout after last received byte. } - if( tcsetattr(_hSerial, TCSANOW, &termios) < 0 ) - LOG_THROW( "Unable to configure port" ); + if (tcsetattr(_hSerial, TCSANOW, &termios) < 0) + LOG_THROW("Unable to configure port"); #endif - if( _hSerial == INVALID_HANDLE_VALUE ) - LOG_THROW( "Port not open" ); + if (_hSerial == INVALID_HANDLE_VALUE) + LOG_THROW("Port not open"); _isOpen = true; LOG_TRACE("Device open successfull."); @@ -203,20 +208,21 @@ void Serial::close() { - if( !_isOpen ) return; + if (!_isOpen) + return; LOG_TRACE("Device close ..."); #ifdef Q_OS_MAC - if( ioctl(_hSerial, TIOCNXCL) < 0 ) - LOG_THROW( "Port in use" ); + if (ioctl(_hSerial, TIOCNXCL) < 0) + LOG_THROW("Port in use"); #endif - if( _hSerial == INVALID_HANDLE_VALUE ) - LOG_THROW( "Port not open" ); + if (_hSerial == INVALID_HANDLE_VALUE) + LOG_THROW("Port not open"); S_CLOSE(_hSerial); _hSerial = INVALID_HANDLE_VALUE; - _isOpen = false; + _isOpen = false; LOG_TRACE("Device close successfull."); } @@ -224,38 +230,38 @@ unsigned char Serial::readByte() const { - if( !_isOpen ) - LOG_THROW( "Port not open" ); + if (!_isOpen) + LOG_THROW("Port not open"); unsigned char byte = 0; S_LEN len = 0; S_READ(_hSerial, &byte, 1, len); - if( len != 1 ) - LOG_THROW_E(ReadTimeout, "< timeout" ); + if (len != 1) + LOG_THROW_E(ReadTimeout, "< timeout"); - if( isprint(byte) ) + if (isprint(byte)) LOG_DEBUG("< " << QString::asprintf("%02x '%c'", byte, byte)); else - LOG_DEBUG("< " << QString::asprintf("%02x", byte) ); + LOG_DEBUG("< " << QString::asprintf("%02x", byte)); return byte; } void Serial::writeByte(unsigned char byte) const { - if( !_isOpen ) - LOG_THROW( "Port not open" ); + if (!_isOpen) + LOG_THROW("Port not open"); - if( isprint(byte) ) - LOG_DEBUG("> " << QString::asprintf("%02x '%c'", byte, byte) ); + if (isprint(byte)) + LOG_DEBUG("> " << QString::asprintf("%02x '%c'", byte, byte)); else - LOG_DEBUG("> " << QString::asprintf("%02x", byte) ); + LOG_DEBUG("> " << QString::asprintf("%02x", byte)); S_LEN len = 0; S_WRITE(_hSerial, &byte, 1, len); - if( len != 1 ) - // LOG_THROW_E(WriteTimeout, "> timeout"); - LOG_THROW("> timeout"); + if (len != 1) + // LOG_THROW_E(WriteTimeout, "> timeout"); + LOG_THROW("> timeout"); } /////////////////////////////////////////////////////////////////////////////// @@ -271,7 +277,8 @@ { unsigned char lo = word & 0xFF; unsigned char hi = word >> 8; - writeByte(lo); writeByte(hi); + writeByte(lo); + writeByte(hi); } /////////////////////////////////////////////////////////////////////////////// @@ -279,9 +286,11 @@ void Serial::writeInt24(unsigned int int24) const { unsigned char lo = int24 & 0xFF; - unsigned char hi = (int24 >> 8) & 0xFF; + unsigned char hi = (int24 >> 8) & 0xFF; unsigned char up = (int24 >> 16) & 0xFF; - writeByte(lo); writeByte(hi); writeByte(up); + writeByte(lo); + writeByte(hi); + writeByte(up); } unsigned int Serial::readInt24() const @@ -294,51 +303,46 @@ /////////////////////////////////////////////////////////////////////////////// -unsigned int Serial::readBlock(unsigned char* ptr, unsigned int size) const +unsigned int Serial::readBlock(unsigned char *ptr, unsigned int size) const { - if( !_isOpen ) - LOG_THROW( "Port not open" ); + if (!_isOpen) + LOG_THROW("Port not open"); unsigned int bytes = 0; bool timeout = false; - while( size > 0 ) - { + while (size > 0) { // Allow up to 1.0sec for each 4K block. S_LEN todo = (size > 4096) ? 4096 : size; S_LEN done = 0; - S_READ(_hSerial, ptr+bytes, todo, done); + S_READ(_hSerial, ptr + bytes, todo, done); - if( done == 0 ) { + if (done == 0) { timeout = true; break; } size -= done; - bytes += (unsigned int)done; + bytes += (unsigned int) done; } - if( Log::minLevel <= Log::LEVEL_DEBUG ) - { + if (Log::minLevel <= Log::LEVEL_DEBUG) { const int DUMP_LINE = 16; - const int DUMP_MAX = 3*DUMP_LINE; + const int DUMP_MAX = 3 * DUMP_LINE; const unsigned int length = (bytes < DUMP_MAX) ? bytes : DUMP_MAX; - for(unsigned int i=0; i<length; i += DUMP_LINE) - { - LogAction logger(Log::LEVEL_DEBUG, __FILE__ ,__LINE__, "readBlock()"); + for (unsigned int i = 0; i < length; i += DUMP_LINE) { + LogAction logger(Log::LEVEL_DEBUG, __FILE__, __LINE__, "readBlock()"); logger << "< "; - for(unsigned int j=i; j<bytes && j<(i+DUMP_LINE); ++j) + for (unsigned int j = i; j < bytes && j < (i + DUMP_LINE); ++j) logger << QString::asprintf("%02x ", ptr[j]); - for(unsigned int j=i; j<bytes && j<(i+DUMP_LINE); ++j) - logger << (isprint( ptr[j] ) - ? ptr[j] - : (unsigned char)'.'); + for (unsigned int j = i; j < bytes && j < (i + DUMP_LINE); ++j) + logger << (isprint(ptr[j]) ? ptr[j] : (unsigned char) '.'); } - if( length < bytes ) - LOG_DEBUG("< ... " << (bytes-length) << " more bytes."); + if (length < bytes) + LOG_DEBUG("< ... " << (bytes - length) << " more bytes."); } - if( timeout ) + if (timeout) LOG_THROW_E(ReadTimeout, "< block timeout (missing " << size << " bytes)"); return bytes; @@ -346,43 +350,38 @@ /////////////////////////////////////////////////////////////////////////////// -void Serial::writeBlock(const unsigned char* ptr, unsigned int size) const +void Serial::writeBlock(const unsigned char *ptr, unsigned int size) const { - if( !_isOpen ) - LOG_THROW( "Port not open" ); + if (!_isOpen) + LOG_THROW("Port not open"); - if( Log::minLevel <= Log::LEVEL_DEBUG ) - { + if (Log::minLevel <= Log::LEVEL_DEBUG) { const int DUMP_LINE = 16; - const int DUMP_MAX = 3*DUMP_LINE; + const int DUMP_MAX = 3 * DUMP_LINE; const unsigned int length = (size < DUMP_MAX) ? size : DUMP_MAX; - for(unsigned int i=0; i<length; i += DUMP_LINE) - { - LogAction logger(Log::LEVEL_DEBUG, __FILE__ ,__LINE__, "writeBlock()"); + for (unsigned int i = 0; i < length; i += DUMP_LINE) { + LogAction logger(Log::LEVEL_DEBUG, __FILE__, __LINE__, "writeBlock()"); logger << "> "; - for(unsigned int j=i; j<size && j<(i+DUMP_LINE); ++j) + for (unsigned int j = i; j < size && j < (i + DUMP_LINE); ++j) logger << QString::asprintf("%02x ", ptr[j]); - for(unsigned int j=i; j<size && j<(i+DUMP_LINE); ++j) - logger << (isprint( ptr[j] ) - ? ptr[j] - : (unsigned char)'.'); + for (unsigned int j = i; j < size && j < (i + DUMP_LINE); ++j) + logger << (isprint(ptr[j]) ? ptr[j] : (unsigned char) '.'); } - if( length < size ) - LOG_DEBUG("> ... " << (size-length) << " more bytes."); + if (length < size) + LOG_DEBUG("> ... " << (size - length) << " more bytes."); } - while( size > 0 ) - { + while (size > 0) { // Allow up to 1.0sec for each 4K block. S_LEN chunck = (size > 4096) ? 4096 : size; S_LEN len = 0; S_WRITE(_hSerial, ptr, chunck, len); - if( len == 0 ) + if (len == 0) LOG_THROW_E(WriteTimeout, "> block timeout"); size -= len; - ptr += len; + ptr += len; } // Auto-fluh on each write. @@ -393,8 +392,8 @@ void Serial::purge() { - if( !_isOpen ) - LOG_THROW( "Port not open" ); + if (!_isOpen) + LOG_THROW("Port not open"); // Empty incomming buffer S_PURGE(_hSerial); @@ -406,8 +405,8 @@ void Serial::flush() const { - if( !_isOpen ) - LOG_THROW( "Port not open" ); + if (!_isOpen) + LOG_THROW("Port not open"); S_FLUSH(_hSerial); } @@ -419,6 +418,6 @@ #ifdef WIN32 Sleep(msec); #else - usleep(msec*1000); + usleep(msec * 1000); #endif }
