From 283a0febd517b78a042a2f44c7b3d5761f82544c Mon Sep 17 00:00:00 2001 From: Andy Regensky Date: Thu, 25 Jul 2024 17:37:07 +0200 Subject: [PATCH] Bugfix: Did not release exclusive access to serial port on close, New feature: Allow configuration of exclusive access for serial port --- src/SerialPort.cpp | 52 +++++++++++++++++++++++++-------- src/SerialStream.cpp | 10 ++++--- src/SerialStreamBuf.cpp | 32 +++++++++++++------- src/libserial/SerialPort.h | 8 +++-- src/libserial/SerialStream.h | 9 ++++-- src/libserial/SerialStreamBuf.h | 9 ++++-- 6 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/SerialPort.cpp b/src/SerialPort.cpp index 4b779127..b6959135 100644 --- a/src/SerialPort.cpp +++ b/src/SerialPort.cpp @@ -70,13 +70,15 @@ namespace LibSerial * @param parityType The parity type for the serial port. * @param stopBits The number of stop bits for the serial port. * @param flowControlType The flow control type for the serial port. + * @param exclusive Set exclusive access for the serial port. */ Implementation(const std::string& fileName, const BaudRate& baudRate, const CharacterSize& characterSize, const FlowControl& flowControlType, const Parity& parityType, - const StopBits& stopBits) ; + const StopBits& stopBits, + bool exclusive) ; /** * @brief Default Destructor for a SerialPort object. Closes the @@ -110,9 +112,11 @@ namespace LibSerial * @param fileName The file name of the serial port. * @param openMode The communication mode status when the serial * communication port is opened. + * @param exclusive Set exclusive access for this serial port. */ void Open(const std::string& fileName, - const std::ios_base::openmode& openMode) ; + const std::ios_base::openmode& openMode, + bool exclusive) ; /** * @brief Closes the serial port. All settings of the serial port will be @@ -466,6 +470,12 @@ namespace LibSerial */ int mByteArrivalTimeDelta = 1 ; + /** + * Whether the process that opened the serial port has exclusive + * access to it. + */ + bool mExclusiveAccess = true; + /** * Serial port settings are saved into this struct immediately after * the port is opened. These settings are restored when the serial port @@ -485,13 +495,15 @@ namespace LibSerial const CharacterSize& characterSize, const FlowControl& flowControlType, const Parity& parityType, - const StopBits& stopBits) + const StopBits& stopBits, + bool exclusive) : mImpl(new Implementation(fileName, baudRate, characterSize, flowControlType, parityType, - stopBits)) + stopBits, + exclusive)) { /* Empty */ } @@ -512,10 +524,12 @@ namespace LibSerial void SerialPort::Open(const std::string& fileName, - const std::ios_base::openmode& openMode) + const std::ios_base::openmode& openMode, + bool exclusive) { mImpl->Open(fileName, - openMode) ; + openMode, + exclusive) ; } void @@ -809,9 +823,10 @@ namespace LibSerial const CharacterSize& characterSize, const FlowControl& flowControlType, const Parity& parityType, - const StopBits& stopBits) + const StopBits& stopBits, + bool exclusive) { - this->Open(fileName, std::ios_base::in | std::ios_base::out) ; + this->Open(fileName, std::ios_base::in | std::ios_base::out, exclusive) ; this->SetBaudRate(baudRate) ; this->SetCharacterSize(characterSize) ; this->SetFlowControl(flowControlType) ; @@ -843,7 +858,8 @@ namespace LibSerial inline void SerialPort::Implementation::Open(const std::string& fileName, - const std::ios_base::openmode& openMode) + const std::ios_base::openmode& openMode, + bool exclusive) { // Throw an exception if the port is already open. if (this->IsOpen()) @@ -885,9 +901,10 @@ namespace LibSerial // Set the serial port to exclusive access to this process. // NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg) - if (call_with_retry(ioctl, - this->mFileDescriptor, - TIOCEXCL) == -1) + mExclusiveAccess = exclusive; + if (mExclusiveAccess && call_with_retry(ioctl, + this->mFileDescriptor, + TIOCEXCL) == -1) { throw std::runtime_error(std::strerror(errno)) ; } @@ -935,6 +952,17 @@ namespace LibSerial err_msg = std::strerror(errno) ; } + // Release the serial port from exclusive access. + if (mExclusiveAccess) + { + // NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg) + if(call_with_retry(ioctl, this->mFileDescriptor, TIOCNXCL) == -1) + { + err_msg += ", "; + err_msg += std::strerror(errno); + } + } + // Otherwise, close the serial port and set the file descriptor // to an invalid value. bool is_failed = false ; diff --git a/src/SerialStream.cpp b/src/SerialStream.cpp index 3ac98133..9da1b4b4 100644 --- a/src/SerialStream.cpp +++ b/src/SerialStream.cpp @@ -46,10 +46,11 @@ namespace LibSerial const CharacterSize& characterSize, const FlowControl& flowControlType, const Parity& parityType, - const StopBits& stopBits) : + const StopBits& stopBits, + bool exclusive) : std::iostream(nullptr) { - this->Open(fileName) ; // NOLINT (fuchsia-default-arguments) + this->Open(fileName, std::ios_base::in | std::ios_base::out, exclusive) ; // NOLINT (fuchsia-default-arguments) this->SetBaudRate(baudRate) ; this->SetCharacterSize(characterSize) ; this->SetFlowControl(flowControlType) ; @@ -81,7 +82,8 @@ namespace LibSerial void SerialStream::Open(const std::string& fileName, - const std::ios_base::openmode& openMode) + const std::ios_base::openmode& openMode, + bool exclusive) try { // Create a new SerialStreamBuf if one does not exist. @@ -93,7 +95,7 @@ namespace LibSerial } // Open the serial port. - mIOBuffer->Open(fileName, openMode) ; + mIOBuffer->Open(fileName, openMode, exclusive) ; } catch (const std::exception&) { diff --git a/src/SerialStreamBuf.cpp b/src/SerialStreamBuf.cpp index 729c7b3b..963e6924 100644 --- a/src/SerialStreamBuf.cpp +++ b/src/SerialStreamBuf.cpp @@ -69,13 +69,15 @@ namespace LibSerial * @param parityType The parity type for the serial stream. * @param stopBits The number of stop bits for the serial stream. * @param flowControlType The flow control type for the serial stream. + * @param exclusive Set exclusive access for the serial stream. */ Implementation(const std::string& fileName, const BaudRate& baudRate, const CharacterSize& characterSize, const FlowControl& flowControlType, const Parity& parityType, - const StopBits& stopBits) ; + const StopBits& stopBits, + bool exclusive) ; /** * @brief Copy construction is disallowed. @@ -103,9 +105,11 @@ namespace LibSerial * @param fileName The file name of the serial port. * @param openMode The communication mode status when the serial * communication port is opened. + * @param exclusive Set exclusive access for this serial port. */ void Open(const std::string& fileName, - const std::ios_base::openmode& openMode) ; + const std::ios_base::openmode& openMode, + bool exclusive) ; /** * @brief Closes the serial port. All settings of the serial port will be @@ -390,13 +394,15 @@ namespace LibSerial const CharacterSize& characterSize, const FlowControl& flowControlType, const Parity& parityType, - const StopBits& stopBits) + const StopBits& stopBits, + bool exclusive) : mImpl(new Implementation(fileName, baudRate, characterSize, flowControlType, parityType, - stopBits)) + stopBits, + exclusive)) { setbuf(nullptr, 0) ; } @@ -405,10 +411,12 @@ namespace LibSerial void SerialStreamBuf::Open(const std::string& fileName, - const std::ios_base::openmode& openMode) + const std::ios_base::openmode& openMode, + bool exclusive) { mImpl->Open(fileName, - openMode) ; + openMode, + exclusive) ; } void @@ -656,13 +664,15 @@ namespace LibSerial const CharacterSize& characterSize, const FlowControl& flowControlType, const Parity& parityType, - const StopBits& stopBits) + const StopBits& stopBits, + bool exclusive) try : mSerialPort(fileName, baudRate, characterSize, flowControlType, parityType, - stopBits) + stopBits, + exclusive) { // empty } @@ -695,11 +705,13 @@ namespace LibSerial inline void SerialStreamBuf::Implementation::Open(const std::string& fileName, - const std::ios_base::openmode& openMode) + const std::ios_base::openmode& openMode, + bool exclusive) try { mSerialPort.Open(fileName, - openMode) ; + openMode, + exclusive) ; // @note - Stream communications need to happen in blocking mode. mSerialPort.SetSerialPortBlockingStatus(true) ; diff --git a/src/libserial/SerialPort.h b/src/libserial/SerialPort.h index 09ed2bd0..2fae61e4 100644 --- a/src/libserial/SerialPort.h +++ b/src/libserial/SerialPort.h @@ -72,13 +72,15 @@ namespace LibSerial * @param parityType The parity type for the serial port. * @param stopBits The number of stop bits for the serial port. * @param flowControlType The flow control type for the serial port. + * @param exclusive Set exclusive access for the serial port. */ explicit SerialPort(const std::string& fileName, const BaudRate& baudRate = BaudRate::BAUD_DEFAULT, const CharacterSize& characterSize = CharacterSize::CHAR_SIZE_DEFAULT, const FlowControl& flowControlType = FlowControl::FLOW_CONTROL_DEFAULT, const Parity& parityType = Parity::PARITY_DEFAULT, - const StopBits& stopBits = StopBits::STOP_BITS_DEFAULT) ; + const StopBits& stopBits = StopBits::STOP_BITS_DEFAULT, + bool exclusive = true) ; /** * @brief Default Destructor for a SerialPort object. Closes the @@ -112,9 +114,11 @@ namespace LibSerial * @param fileName The file name of the serial port. * @param openMode The communication mode status when the serial * communication port is opened. + * @param exclusive Set exclusive access for the serial port. */ void Open(const std::string& fileName, - const std::ios_base::openmode& openMode = std::ios_base::in | std::ios_base::out) ; + const std::ios_base::openmode& openMode = std::ios_base::in | std::ios_base::out, + bool exclusive = true) ; /** * @brief Closes the serial port. All settings of the serial port will be diff --git a/src/libserial/SerialStream.h b/src/libserial/SerialStream.h index f6e483d2..817dc1b8 100644 --- a/src/libserial/SerialStream.h +++ b/src/libserial/SerialStream.h @@ -96,13 +96,15 @@ namespace LibSerial * @param parityType The parity type for the serial stream. * @param stopBits The number of stop bits for the serial stream. * @param flowControlType The flow control type for the serial stream. + * @param exclusive Set exclusive access for the serial stream. */ explicit SerialStream(const std::string& fileName, const BaudRate& baudRate = BaudRate::BAUD_DEFAULT, const CharacterSize& characterSize = CharacterSize::CHAR_SIZE_DEFAULT, const FlowControl& flowControlType = FlowControl::FLOW_CONTROL_DEFAULT, const Parity& parityType = Parity::PARITY_DEFAULT, - const StopBits& stopBits = StopBits::STOP_BITS_DEFAULT) ; + const StopBits& stopBits = StopBits::STOP_BITS_DEFAULT, + bool exclusive = true) ; /** * @brief Default Destructor for a SerialStream object @@ -140,9 +142,12 @@ namespace LibSerial * @param fileName The file name of the serial port. * @param openMode The communication mode status when the serial * communication port is opened. + * @param exclusive Set exclusive access for this process to the + * serial port. */ void Open(const std::string& fileName, - const std::ios_base::openmode& openMode = std::ios_base::in | std::ios_base::out) ; + const std::ios_base::openmode& openMode = std::ios_base::in | std::ios_base::out, + bool exclusive = true) ; /** * @brief Closes the serial port. All settings of the serial port will be diff --git a/src/libserial/SerialStreamBuf.h b/src/libserial/SerialStreamBuf.h index a2f74967..a579b6ce 100644 --- a/src/libserial/SerialStreamBuf.h +++ b/src/libserial/SerialStreamBuf.h @@ -75,13 +75,15 @@ namespace LibSerial * @param parityType The parity type for the serial stream. * @param stopBits The number of stop bits for the serial stream. * @param flowControlType The flow control type for the serial stream. + * @param exclusive Set exclusive access for the serial stream */ explicit SerialStreamBuf(const std::string& fileName, const BaudRate& baudRate = BaudRate::BAUD_DEFAULT, const CharacterSize& characterSize = CharacterSize::CHAR_SIZE_DEFAULT, const FlowControl& flowControlType = FlowControl::FLOW_CONTROL_DEFAULT, const Parity& parityType = Parity::PARITY_DEFAULT, - const StopBits& stopBits = StopBits::STOP_BITS_DEFAULT) ; + const StopBits& stopBits = StopBits::STOP_BITS_DEFAULT, + bool exclusive = true) ; /** * @brief Default Destructor for a SerialStreamBuf object. Closes the @@ -115,9 +117,12 @@ namespace LibSerial * @param fileName The file name of the serial port. * @param openMode The communication mode status when the serial * communication port is opened. + * @param exclusive Set exclusive access for this process to the + * serial port. */ void Open(const std::string& fileName, - const std::ios_base::openmode& openMode = std::ios_base::in | std::ios_base::out) ; + const std::ios_base::openmode& openMode = std::ios_base::in | std::ios_base::out, + bool exclusive = true) ; /** * @brief Closes the serial port. All settings of the serial port will be