Loading...
Searching...
No Matches
SerialPort.cpp
/******************************************************************************
* @file SerialPort.cpp *
* @copyright (C) 2004-2018 LibSerial Development Team. All rights reserved. *
* crayzeewulf@gmail.com *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* 1. Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in *
* the documentation and/or other materials provided with the *
* distribution. *
* 3. Neither the name PX4 nor the names of its contributors may be *
* used to endorse or promote products derived from this software *
* without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED *
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
*****************************************************************************/
#include "libserial/SerialPort.h"
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <sstream>
#include <sys/ioctl.h>
#include <type_traits>
#include <unistd.h>
#ifdef __linux__
#include <linux/serial.h>
#endif
namespace LibSerial
{
class SerialPort::Implementation
{
public:
Implementation() = default ;
Implementation(const std::string& fileName,
const BaudRate& baudRate,
const CharacterSize& characterSize,
const FlowControl& flowControlType,
const Parity& parityType,
const StopBits& stopBits) ;
~Implementation() noexcept ;
Implementation(const Implementation& otherImplementation) = delete ;
Implementation(const Implementation&& otherImplementation) = delete ;
Implementation& operator=(const Implementation& otherImplementation) = delete ;
Implementation& operator=(const Implementation&& otherImplementation) = delete ;
void Open(const std::string& fileName,
const std::ios_base::openmode& openMode) ;
void Close() ;
void DrainWriteBuffer() ;
void FlushInputBuffer() ;
void FlushOutputBuffer() ;
void FlushIOBuffers() ;
bool IsDataAvailable() ;
bool IsOpen() const ;
void SetDefaultSerialPortParameters() ;
void SetBaudRate(const BaudRate& baudRate) ;
BaudRate GetBaudRate() const ;
void SetCharacterSize(const CharacterSize& characterSize) ;
CharacterSize GetCharacterSize() const ;
void SetFlowControl(const FlowControl& flowControlType) ;
FlowControl GetFlowControl() const ;
void SetParity(const Parity& parityType) ;
Parity GetParity() const ;
void SetStopBits(const StopBits& stopBits) ;
StopBits GetStopBits() const ;
void SetVMin(const short vmin) ;
short GetVMin() const ;
void SetVTime(const short vtime) ;
short GetVTime() const ;
void SetDTR(const bool dtrState) ;
bool GetDTR() ;
void SetRTS(const bool rtsState) ;
bool GetRTS() ;
bool GetCTS() ;
bool GetDSR() ;
int GetFileDescriptor() const ;
int GetNumberOfBytesAvailable() ;
#ifdef __linux__
std::vector<std::string> GetAvailableSerialPorts() const ;
#endif
void Read(DataBuffer& dataBuffer,
size_t numberOfBytes = 0,
size_t msTimeout = 0) ;
void Read(std::string& dataString,
size_t numberOfBytes = 0,
size_t msTimeout = 0) ;
template <typename ByteType,
typename = std::enable_if_t<(sizeof(ByteType) == 1)>>
void ReadByte(ByteType& charBuffer,
size_t msTimeout = 0) ;
void ReadLine(std::string& dataString,
char lineTerminator = '\n',
size_t msTimeout = 0) ;
void Write(const DataBuffer& dataBuffer) ;
void Write(const std::string& dataString) ;
void WriteByte(char charBuffer) ;
void WriteByte(unsigned char charBuffer) ;
void SetSerialPortBlockingStatus(bool blockingStatus) ;
bool GetSerialPortBlockingStatus() const ;
void SetModemControlLine(int modemLine,
bool lineState) ;
bool GetModemControlLine(int modemLine) ;
private:
int GetBitRate(const BaudRate& baudRate) const ;
void SetDefaultLinuxSpecificModes() ;
void SetDefaultInputModes() ;
void SetDefaultOutputModes() ;
void SetDefaultControlModes() ;
void SetDefaultLocalModes() ;
int mFileDescriptor = -1 ;
int mByteArrivalTimeDelta = 1 ;
termios mOldPortSettings {} ;
} ;
SerialPort::SerialPort()
: mImpl(new Implementation())
{
/* Empty */
}
SerialPort::SerialPort(const std::string& fileName,
const BaudRate& baudRate,
const CharacterSize& characterSize,
const FlowControl& flowControlType,
const Parity& parityType,
const StopBits& stopBits)
: mImpl(new Implementation(fileName,
baudRate,
characterSize,
flowControlType,
parityType,
stopBits))
{
/* Empty */
}
SerialPort::SerialPort(SerialPort&& otherSerialPort) :
mImpl(std::move(otherSerialPort.mImpl))
{
// empty
}
SerialPort& SerialPort::operator=(SerialPort&& otherSerialPort)
{
mImpl = std::move(otherSerialPort.mImpl);
return *this;
}
SerialPort::~SerialPort() noexcept = default ;
void
SerialPort::Open(const std::string& fileName,
const std::ios_base::openmode& openMode)
{
mImpl->Open(fileName,
openMode) ;
}
void
SerialPort::Close()
{
mImpl->Close() ;
}
void
SerialPort::DrainWriteBuffer()
{
mImpl->DrainWriteBuffer() ;
}
void
SerialPort::FlushInputBuffer()
{
mImpl->FlushInputBuffer() ;
}
void
SerialPort::FlushOutputBuffer()
{
mImpl->FlushOutputBuffer() ;
}
void
SerialPort::FlushIOBuffers()
{
mImpl->FlushIOBuffers() ;
}
bool
SerialPort::IsDataAvailable()
{
return mImpl->IsDataAvailable() ;
}
bool
SerialPort::IsOpen() const
{
return mImpl->IsOpen() ;
}
void
SerialPort::SetDefaultSerialPortParameters()
{
mImpl->SetDefaultSerialPortParameters() ;
}
void
SerialPort::SetBaudRate(const BaudRate& baudRate)
{
mImpl->SetBaudRate(baudRate) ;
}
BaudRate
SerialPort::GetBaudRate() const
{
return mImpl->GetBaudRate() ;
}
void
SerialPort::SetCharacterSize(const CharacterSize& characterSize)
{
mImpl->SetCharacterSize(characterSize) ;
}
CharacterSize
SerialPort::GetCharacterSize() const
{
return mImpl->GetCharacterSize() ;
}
void
SerialPort::SetFlowControl(const FlowControl& flowControlType)
{
mImpl->SetFlowControl(flowControlType) ;
}
FlowControl
SerialPort::GetFlowControl() const
{
return mImpl->GetFlowControl() ;
}
void
SerialPort::SetParity(const Parity& parityType)
{
mImpl->SetParity(parityType) ;
}
Parity
SerialPort::GetParity() const
{
return mImpl->GetParity() ;
}
void
SerialPort::SetStopBits(const StopBits& stopBits)
{
mImpl->SetStopBits(stopBits) ;
}
StopBits
SerialPort::GetStopBits() const
{
return mImpl->GetStopBits() ;
}
void
SerialPort::SetVMin(const short vmin)
{
mImpl->SetVMin(vmin) ;
}
short
SerialPort::GetVMin() const
{
return mImpl->GetVMin() ;
}
void
SerialPort::SetVTime(const short vtime)
{
mImpl->SetVTime(vtime) ;
}
short
SerialPort::GetVTime() const
{
return mImpl->GetVTime() ;
}
void
SerialPort::SetDTR(const bool dtrState)
{
mImpl->SetDTR(dtrState) ;
}
bool
SerialPort::GetDTR() const
{
return mImpl->GetDTR() ;
}
void
SerialPort::SetRTS(const bool rtsState)
{
mImpl->SetRTS(rtsState) ;
}
bool
SerialPort::GetRTS() const
{
return mImpl->GetRTS() ;
}
bool
SerialPort::GetCTS()
{
return mImpl->GetCTS() ;
}
bool
SerialPort::GetDSR()
{
return mImpl->GetDSR() ;
}
int
SerialPort::GetFileDescriptor() const
{
return mImpl->GetFileDescriptor() ;
}
int
SerialPort::GetNumberOfBytesAvailable()
{
return mImpl->GetNumberOfBytesAvailable() ;
}
#ifdef __linux__
std::vector<std::string>
SerialPort::GetAvailableSerialPorts() const
{
return mImpl->GetAvailableSerialPorts() ;
}
#endif
void
SerialPort::Read(DataBuffer& dataBuffer,
const size_t numberOfBytes,
const size_t msTimeout)
{
mImpl->Read(dataBuffer,
numberOfBytes,
msTimeout) ;
}
void
SerialPort::Read(std::string& dataString,
const size_t numberOfBytes,
const size_t msTimeout)
{
mImpl->Read(dataString,
numberOfBytes,
msTimeout) ;
}
void
SerialPort::ReadByte(char& charBuffer,
const size_t msTimeout)
{
mImpl->ReadByte(charBuffer,
msTimeout) ;
}
void
SerialPort::ReadByte(unsigned char& charBuffer,
const size_t msTimeout)
{
mImpl->ReadByte(charBuffer,
msTimeout) ;
}
void
SerialPort::ReadLine(std::string& dataString,
const char lineTerminator,
const size_t msTimeout)
{
mImpl->ReadLine(dataString,
lineTerminator,
msTimeout) ;
}
void
SerialPort::Write(const DataBuffer& dataBuffer)
{
mImpl->Write(dataBuffer) ;
}
void
SerialPort::Write(const std::string& dataString)
{
mImpl->Write(dataString) ;
}
void
SerialPort::WriteByte(const char charBuffer)
{
mImpl->WriteByte(charBuffer) ;
}
void
SerialPort::WriteByte(const unsigned char charBuffer)
{
mImpl->WriteByte(charBuffer) ;
}
void
SerialPort::SetSerialPortBlockingStatus(const bool blockingStatus)
{
mImpl->SetSerialPortBlockingStatus(blockingStatus) ;
}
bool
SerialPort::GetSerialPortBlockingStatus() const
{
return mImpl->GetSerialPortBlockingStatus() ;
}
void
SerialPort::SetModemControlLine(const int modemLine,
const bool lineState)
{
mImpl->SetModemControlLine(modemLine, lineState) ;
}
bool
SerialPort::GetModemControlLine(const int modemLine)
{
return mImpl->GetModemControlLine(modemLine) ;
}
inline
SerialPort::Implementation::Implementation(const std::string& fileName,
const BaudRate& baudRate,
const CharacterSize& characterSize,
const FlowControl& flowControlType,
const Parity& parityType,
const StopBits& stopBits)
{
this->Open(fileName, std::ios_base::in | std::ios_base::out) ;
this->SetBaudRate(baudRate) ;
this->SetCharacterSize(characterSize) ;
this->SetFlowControl(flowControlType) ;
this->SetParity(parityType) ;
this->SetStopBits(stopBits) ;
}
inline
SerialPort::Implementation::~Implementation()
try
{
// Close the serial port if it is open.
if (this->IsOpen())
{
this->Close() ;
}
}
catch(...)
{
//
// :IMPORTANT: We do not let any exceptions escape the destructor.
// (see https://isocpp.org/wiki/faq/exceptions#dtors-shouldnt-throw)
//
// :TODO: Once we add logging to LibSerial, we should issue a warning
// if we reach here.
//
}
inline
void
SerialPort::Implementation::Open(const std::string& fileName,
const std::ios_base::openmode& openMode)
{
// Throw an exception if the port is already open.
if (this->IsOpen())
{
throw AlreadyOpen(ERR_MSG_PORT_ALREADY_OPEN) ;
}
// We only allow three different combinations of ios_base::openmode so
// we can use a switch here to construct the flags to be used with the
// open() system call. Since we are dealing with the serial port we
// need to use the O_NOCTTY option.
int flags = (O_NOCTTY | O_NONBLOCK) ; // NOLINT (hicpp-signed-bitwise)
if (openMode == (std::ios_base::in | std::ios_base::out))
{
flags |= O_RDWR ;
}
else if (openMode == std::ios_base::in)
{
flags |= O_RDONLY ;
}
else if (openMode == std::ios_base::out)
{
flags |= O_WRONLY ;
}
else
{
throw OpenFailed {"Invalid or unsupported open mode"} ;
}
// Try to open the serial port.
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg)
mFileDescriptor = call_with_retry(open, fileName.c_str(), flags) ;
if (this->mFileDescriptor < 0)
{
throw OpenFailed(std::strerror(errno)) ;
}
// Set the serial port to exclusive access to this process.
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg)
if (call_with_retry(ioctl,
this->mFileDescriptor,
TIOCEXCL) == -1)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Save the current settings of the serial port so they can be
// restored when the serial port is closed.
if (tcgetattr(this->mFileDescriptor,
&mOldPortSettings) < 0)
{
throw OpenFailed(std::strerror(errno)) ;
}
// Set up the default configuration for the serial port.
this->SetDefaultSerialPortParameters() ;
// Flush the input and output buffers associated with the port.
this->FlushIOBuffers() ;
}
inline
void
SerialPort::Implementation::Close()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Restore the old settings of the port.
//
// :IMPORTANT: If there is an error while attempting to restore the old
// settings, do not throw an exception here and attempt to close the
// serial port anyways. See issue #135 for the reason for this. The
// serial port device may have been removed when this method is called.
// In such a case we will not be able to restore the old settings. But
// we should still close the serial port file descriptor. Otherwise,
// the user has no way to cleanly recover from this state.
//
std::string err_msg {} ;
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&mOldPortSettings) < 0)
{
err_msg = std::strerror(errno) ;
}
// Otherwise, close the serial port and set the file descriptor
// to an invalid value.
bool is_failed = false ;
if (call_with_retry(close, this->mFileDescriptor) < 0)
{
is_failed = true ;
err_msg += ", " ;
err_msg += std::strerror(errno) ;
}
// Set the file descriptor to an invalid value, -1.
mFileDescriptor = -1 ;
//
// Throw an exception if close() failed
//
if (is_failed)
{
throw std::runtime_error(err_msg) ;
}
}
inline
void
SerialPort::Implementation::DrainWriteBuffer()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (call_with_retry(tcdrain, this->mFileDescriptor) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::FlushInputBuffer()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (tcflush(this->mFileDescriptor, TCIFLUSH) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::FlushOutputBuffer()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (tcflush(this->mFileDescriptor, TCOFLUSH) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::FlushIOBuffers()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (tcflush(this->mFileDescriptor, TCIOFLUSH) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
bool
SerialPort::Implementation::IsOpen() const
{
return (this->mFileDescriptor != -1) ;
}
inline
bool
SerialPort::Implementation::IsDataAvailable()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
int number_of_bytes_available = 0 ;
bool is_data_available = false ;
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg)
const auto ioctl_result = call_with_retry(ioctl,
this->mFileDescriptor,
FIONREAD,
&number_of_bytes_available) ;
if ((ioctl_result >= 0) and
(number_of_bytes_available > 0))
{
is_data_available = true ;
}
return is_data_available ;
}
inline
void
SerialPort::Implementation::SetDefaultSerialPortParameters()
{
// Make sure that the serial port is open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
#ifdef __linux__
SetDefaultLinuxSpecificModes() ;
#endif
SetDefaultInputModes() ;
SetDefaultOutputModes() ;
SetDefaultControlModes() ;
SetDefaultLocalModes() ;
SetBaudRate(BaudRate::BAUD_DEFAULT) ;
SetCharacterSize(CharacterSize::CHAR_SIZE_DEFAULT) ;
SetFlowControl(FlowControl::FLOW_CONTROL_DEFAULT) ;
SetParity(Parity::PARITY_DEFAULT) ;
SetStopBits(StopBits::STOP_BITS_DEFAULT) ;
SetVMin(VMIN_DEFAULT) ;
SetVTime(VTIME_DEFAULT) ;
}
inline
void
SerialPort::Implementation::SetBaudRate(const BaudRate& baudRate)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Set the baud rate for both input and output.
if (0 != cfsetspeed(&port_settings, static_cast<speed_t>(baudRate)))
{
// If applying the baud rate settings fail, throw an exception.
throw std::runtime_error(ERR_MSG_INVALID_BAUD_RATE) ;
}
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
// If applying the settings fails, throw an exception.
throw std::runtime_error(std::strerror(errno)) ;
}
// Set the time interval value (us) required for one byte of data to arrive.
mByteArrivalTimeDelta = (BITS_PER_BYTE * MICROSECONDS_PER_SEC) / GetBitRate(baudRate) ;
}
inline
BaudRate
SerialPort::Implementation::GetBaudRate() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Read the input and output baud rates.
const auto input_baud = cfgetispeed(&port_settings) ;
const auto output_baud = cfgetospeed(&port_settings) ;
// Make sure that the input and output baud rates are
// equal. Otherwise, we do not know which one to return.
if (input_baud != output_baud)
{
throw std::runtime_error(ERR_MSG_INVALID_BAUD_RATE) ;
// return BaudRate::BAUD_INVALID ;
}
// Obtain the input baud rate from the current settings.
return BaudRate(input_baud) ;
}
inline
int
SerialPort::Implementation::GetBitRate(const BaudRate& baudRate) const
{
int baud_rate_as_int = 1 ;
switch (baudRate)
{
case BaudRate::BAUD_50:
baud_rate_as_int = 50 ;
break ;
case BaudRate::BAUD_75:
baud_rate_as_int = 75 ;
break ;
case BaudRate::BAUD_110:
baud_rate_as_int = 110 ;
break ;
case BaudRate::BAUD_134:
baud_rate_as_int = 134 ;
break ;
case BaudRate::BAUD_150:
baud_rate_as_int = 150 ;
break ;
case BaudRate::BAUD_200:
baud_rate_as_int = 200 ;
break ;
case BaudRate::BAUD_300:
baud_rate_as_int = 300 ;
break ;
case BaudRate::BAUD_600:
baud_rate_as_int = 600 ;
break ;
case BaudRate::BAUD_1200:
baud_rate_as_int = 1200 ;
break ;
case BaudRate::BAUD_1800:
baud_rate_as_int = 1800 ;
break ;
case BaudRate::BAUD_2400:
baud_rate_as_int = 2400 ;
break ;
case BaudRate::BAUD_4800:
baud_rate_as_int = 4800 ;
break ;
case BaudRate::BAUD_9600:
baud_rate_as_int = 9600 ;
break ;
case BaudRate::BAUD_19200:
baud_rate_as_int = 19200 ;
break ;
case BaudRate::BAUD_38400:
baud_rate_as_int = 38400 ;
break ;
case BaudRate::BAUD_57600:
baud_rate_as_int = 57600 ;
break ;
case BaudRate::BAUD_115200:
baud_rate_as_int = 115200 ;
break ;
case BaudRate::BAUD_230400:
baud_rate_as_int = 230400 ;
break ;
// @note: >B230400 are defined in Linux but not other POSIX systems, (e.g. Mac OS X).
#ifdef __linux__
case BaudRate::BAUD_460800:
baud_rate_as_int = 460800 ;
break ;
case BaudRate::BAUD_500000:
baud_rate_as_int = 500000 ;
break ;
case BaudRate::BAUD_576000:
baud_rate_as_int = 576000 ;
break ;
case BaudRate::BAUD_921600:
baud_rate_as_int = 921600 ;
break ;
case BaudRate::BAUD_1000000:
baud_rate_as_int = 1000000 ;
break ;
case BaudRate::BAUD_1152000:
baud_rate_as_int = 1152000 ;
break ;
case BaudRate::BAUD_1500000:
baud_rate_as_int = 1500000 ;
break ;
#if __MAX_BAUD > B2000000
case BaudRate::BAUD_2000000:
baud_rate_as_int = 2000000 ;
break ;
case BaudRate::BAUD_2500000:
baud_rate_as_int = 2500000 ;
break ;
case BaudRate::BAUD_3000000:
baud_rate_as_int = 3000000 ;
break ;
case BaudRate::BAUD_3500000:
baud_rate_as_int = 3500000 ;
break ;
case BaudRate::BAUD_4000000:
baud_rate_as_int = 4000000 ;
break ;
#endif // __MAX_BAUD
#endif // __linux__
default:
// If an incorrect baud rate was specified, throw an exception.
throw std::runtime_error(ERR_MSG_INVALID_BAUD_RATE) ;
}
return baud_rate_as_int ;
}
inline
void
SerialPort::Implementation::SetCharacterSize(const CharacterSize& characterSize)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(ERR_MSG_INVALID_CHARACTER_SIZE) ;
}
// Set the character size to the specified value. If the character
// size is not 8 then it is also important to set ISTRIP. Setting
// ISTRIP causes all but the 7 low-order bits to be set to
// zero. Otherwise they are set to unspecified values and may
// cause problems. At the same time, we should clear the ISTRIP
// flag when the character size is 8 otherwise the MSB will always
// be set to zero (ISTRIP does not check the character size
// setting;it just sets every bit above the low 7 bits to zero).
if (characterSize == CharacterSize::CHAR_SIZE_8)
{
// NOLINTNEXTLINE (hicpp-signed-bitwise)
port_settings.c_iflag &= ~ISTRIP ; // Clear the ISTRIP flag.
}
else
{
port_settings.c_iflag |= ISTRIP ; // Set the ISTRIP flag.
}
// Set the character size.
// NOLINTNEXTLINE (hicpp-signed-bitwise)
port_settings.c_cflag &= ~CSIZE ; // Clear all CSIZE bits.
port_settings.c_cflag |= static_cast<tcflag_t>(characterSize) ; // Set the character size.
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
CharacterSize
SerialPort::Implementation::GetCharacterSize() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Read the character size from the setttings.
// NOLINTNEXTLINE (hicpp-signed-bitwise)
return CharacterSize(port_settings.c_cflag & CSIZE) ;
}
inline
void
SerialPort::Implementation::SetFlowControl(const FlowControl& flowControlType)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Flush the input and output buffers associated with the port.
if (tcflush(this->mFileDescriptor,
TCIOFLUSH) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(ERR_MSG_INVALID_FLOW_CONTROL) ;
}
// Set the flow control. Hardware flow control uses the RTS (Ready
// To Send) and CTS (clear to Send) lines. Software flow control
// uses IXON|IXOFF
switch(flowControlType)
{
case FlowControl::FLOW_CONTROL_HARDWARE:
port_settings.c_iflag &= ~ (IXON|IXOFF) ; // NOLINT (hicpp-signed-bitwise)
port_settings.c_cflag |= CRTSCTS ;
port_settings.c_cc[VSTART] = _POSIX_VDISABLE ;
port_settings.c_cc[VSTOP] = _POSIX_VDISABLE ;
break ;
case FlowControl::FLOW_CONTROL_SOFTWARE:
port_settings.c_iflag |= IXON|IXOFF ; // NOLINT(hicpp-signed-bitwise)
port_settings.c_cflag &= ~CRTSCTS ;
port_settings.c_cc[VSTART] = CTRL_Q ; // 0x11 (021) ^q
port_settings.c_cc[VSTOP] = CTRL_S ; // 0x13 (023) ^s
break ;
case FlowControl::FLOW_CONTROL_NONE:
port_settings.c_iflag &= ~(IXON|IXOFF) ; // NOLINT(hicpp-signed-bitwise)
port_settings.c_cflag &= ~CRTSCTS ;
break ;
default:
throw std::invalid_argument(ERR_MSG_INVALID_FLOW_CONTROL) ;
// break ; break not needed after a throw
}
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
FlowControl
SerialPort::Implementation::GetFlowControl() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Check if IXON and IXOFF are set in c_iflag. If both are set and
// VSTART and VSTOP are set to 0x11 (^Q) and 0x13 (^S) respectively,
// then we are using software flow control.
if ((port_settings.c_iflag & IXON) and // NOLINT (hicpp-signed-bitwise)
(port_settings.c_iflag & IXOFF) and // NOLINT (hicpp-signed-bitwise)
(CTRL_Q == port_settings.c_cc[VSTART]) and
(CTRL_S == port_settings.c_cc[VSTOP]))
{
return FlowControl::FLOW_CONTROL_SOFTWARE ;
}
if (not ((port_settings.c_iflag & IXON) or // NOLINT (hicpp-signed-bitwise)
(port_settings.c_iflag & IXOFF))) // NOLINT (hicpp-signed-bitwise)
{
if (0 != (port_settings.c_cflag & CRTSCTS))
{
// If neither IXON or IXOFF is set then we must have hardware flow
// control.
return FlowControl::FLOW_CONTROL_HARDWARE ;
}
return FlowControl::FLOW_CONTROL_NONE ;
}
// If none of the above conditions are satisfied then the serial port
// is using a flow control setup which we do not support at present.
return FlowControl::FLOW_CONTROL_INVALID ;
}
inline
void
SerialPort::Implementation::SetParity(const Parity& parityType)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Set the parity type
switch(parityType)
{
case Parity::PARITY_EVEN:
port_settings.c_cflag |= PARENB ;
port_settings.c_cflag &= ~PARODD ; // NOLINT (hicpp-signed-bitwise)
port_settings.c_iflag |= INPCK ;
break ;
case Parity::PARITY_ODD:
port_settings.c_cflag |= PARENB ;
port_settings.c_cflag |= PARODD ;
port_settings.c_iflag |= INPCK ;
break ;
case Parity::PARITY_NONE:
port_settings.c_cflag &= ~PARENB ; // NOLINT (hicpp-signed-bitwise)
port_settings.c_iflag |= IGNPAR ;
break ;
default:
throw std::invalid_argument(ERR_MSG_INVALID_PARITY) ;
// break ; break not needed after a throw
}
// Apply the modified port settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
Parity
SerialPort::Implementation::GetParity() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Get the parity setting from the termios structure.
if (0 != (port_settings.c_cflag & PARENB)) // NOLINT (hicpp-signed-bitwise)
{
// parity is enabled.
if (port_settings.c_cflag & PARODD) // NOLINT (hicpp-signed-bitwise)
{
return Parity::PARITY_ODD ; // odd parity
}
return Parity::PARITY_EVEN ; // even parity
}
return Parity::PARITY_NONE ; // no parity.
}
inline
void
SerialPort::Implementation::SetStopBits(const StopBits& stopBits)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Set the number of stop bits.
switch(stopBits)
{
case StopBits::STOP_BITS_1:
port_settings.c_cflag &= ~CSTOPB ; // NOLINT (hicpp-signed-bitwise)
break ;
case StopBits::STOP_BITS_2:
port_settings.c_cflag |= CSTOPB ;
break ;
default:
throw std::invalid_argument(ERR_MSG_INVALID_STOP_BITS) ;
// break ; break not needed after a throw
}
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
StopBits
SerialPort::Implementation::GetStopBits() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// If CSTOPB is set then we are using two stop bits, otherwise we
// are using 1 stop bit.
if (port_settings.c_cflag & CSTOPB) // NOLINT (hicpp-signed-bitwise)
{
return StopBits::STOP_BITS_2 ;
}
return StopBits::STOP_BITS_1 ;
}
inline
void
SerialPort::Implementation::SetVMin(const short vmin)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (vmin < 0 || vmin > 255)
{
std::stringstream error_message ;
error_message << "Invalid vmin value: " << vmin << ". " ;
error_message << "Vmin must be in the range [0, 255]." ;
throw std::invalid_argument {error_message.str()} ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
port_settings.c_cc[VMIN] = static_cast<cc_t>(vmin) ;
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
short
SerialPort::Implementation::GetVMin() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
return port_settings.c_cc[VMIN] ;
}
inline
void
SerialPort::Implementation::SetVTime(const short vtime)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (vtime < 0 || vtime > 255)
{
std::stringstream error_message ;
error_message << "Invalid vtime value: " << vtime << ". " ;
error_message << "Vtime must be in the range [0, 255]." ;
throw std::invalid_argument {error_message.str()} ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
port_settings.c_cc[VTIME] = static_cast<cc_t>(vtime) ;
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
short
SerialPort::Implementation::GetVTime() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
return port_settings.c_cc[VTIME] ;
}
inline
void
SerialPort::Implementation::SetDTR(const bool dtrState)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
this->SetModemControlLine(TIOCM_DTR,
dtrState) ;
}
inline
bool
SerialPort::Implementation::GetDTR()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
return this->GetModemControlLine(TIOCM_DTR) ;
}
inline
void
SerialPort::Implementation::SetRTS(const bool rtsState)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
this->SetModemControlLine(TIOCM_RTS,
rtsState) ;
}
inline
bool
SerialPort::Implementation::GetRTS()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
return this->GetModemControlLine(TIOCM_RTS) ;
}
inline
bool
SerialPort::Implementation::GetCTS()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
return this->GetModemControlLine(TIOCM_CTS) ;
}
inline
bool
SerialPort::Implementation::GetDSR()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
return this->GetModemControlLine(TIOCM_DSR) ;
}
inline
int
SerialPort::Implementation::GetFileDescriptor() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
return this->mFileDescriptor ;
}
inline
int
SerialPort::Implementation::GetNumberOfBytesAvailable()
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
int number_of_bytes_available = 0 ;
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg)
if (call_with_retry(ioctl,
this->mFileDescriptor,
FIONREAD,
&number_of_bytes_available) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
return number_of_bytes_available ;
}
#ifdef __linux__
inline
std::vector<std::string>
SerialPort::Implementation::GetAvailableSerialPorts() const
{
constexpr int array_size = 3 ;
constexpr size_t max_port_number = 128 ;
std::string serial_ports[array_size] = {"/dev/ttyS",
"/dev/ttyACM",
"/dev/ttyUSB"} ;
std::vector<std::string> serial_port_names {} ;
for (const auto& port_prefix: serial_ports)
{
for (size_t j = 0 ;j < max_port_number;j++)
{
const auto file_name = port_prefix + std::to_string(j) ;
// Try to open the serial port.
const auto file_desc = call_with_retry(open,
file_name.c_str(),
O_RDWR | O_NOCTTY | O_NONBLOCK) ; // NOLINT (hicpp-vararg)
if (file_desc > 0)
{
serial_struct serial_port_info {} ;
// NOLINTNEXTLINE (hicpp-vararg)
if (call_with_retry(ioctl,
file_desc,
TIOCGSERIAL,
&serial_port_info) == -1)
{
throw std::runtime_error(std::strerror(errno)) ;
}
serial_port_names.push_back(file_name) ;
close(file_desc) ;
}
}
}
return serial_port_names ;
}
#endif
inline
void
SerialPort::Implementation::SetModemControlLine(const int modemLine,
const bool lineState)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (modemLine != TIOCM_LE &&
modemLine != TIOCM_DTR &&
modemLine != TIOCM_RTS &&
modemLine != TIOCM_ST &&
modemLine != TIOCM_SR &&
modemLine != TIOCM_CTS &&
modemLine != TIOCM_CAR &&
modemLine != TIOCM_CD &&
modemLine != TIOCM_RNG &&
modemLine != TIOCM_RI &&
modemLine != TIOCM_DSR)
{
throw std::invalid_argument {ERR_MSG_INVALID_MODEM_LINE} ;
}
// Set or unset the specified bit according to the value of lineState.
int ioctl_result = -1 ;
if (lineState)
{
int set_line_mask = modemLine ;
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg)
ioctl_result = call_with_retry(ioctl,
this->mFileDescriptor,
TIOCMBIS,
&set_line_mask) ;
}
else
{
int reset_line_mask = modemLine ;
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg)
ioctl_result = call_with_retry(ioctl,
this->mFileDescriptor,
TIOCMBIC,
&reset_line_mask) ;
}
// Check for errors.
if (ioctl_result < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
bool
SerialPort::Implementation::GetModemControlLine(const int modemLine)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if (modemLine != TIOCM_LE &&
modemLine != TIOCM_DTR &&
modemLine != TIOCM_RTS &&
modemLine != TIOCM_ST &&
modemLine != TIOCM_SR &&
modemLine != TIOCM_CTS &&
modemLine != TIOCM_CAR &&
modemLine != TIOCM_CD &&
modemLine != TIOCM_RNG &&
modemLine != TIOCM_RI &&
modemLine != TIOCM_DSR)
{
throw std::invalid_argument {ERR_MSG_INVALID_MODEM_LINE} ;
}
// Use an ioctl() call to get the state of the line.
int serial_port_state = 0 ;
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-vararg)
if (call_with_retry(ioctl,
this->mFileDescriptor,
TIOCMGET,
&serial_port_state) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
return (0 != (serial_port_state & modemLine)) ; // NOLINT(hicpp-signed-bitwise)
}
inline
void
SerialPort::Implementation::SetSerialPortBlockingStatus(const bool blockingStatus)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
int flags = fcntl(this->mFileDescriptor, F_GETFL, 0) ;
if (blockingStatus)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg)
if (fcntl(this->mFileDescriptor,
F_SETFL,
flags &~ O_NONBLOCK) < 0) // NOLINT (hicpp-signed-bitwise)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
else
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg)
if (fcntl(this->mFileDescriptor,
F_SETFL,
flags | O_NONBLOCK) < 0) // NOLINT (hicpp-signed-bitwise)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
}
inline
bool
SerialPort::Implementation::GetSerialPortBlockingStatus() const
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
bool blocking_status = false ;
const int flags = fcntl(this->mFileDescriptor, F_GETFL, 0) ;
if (flags == -1)
{
throw std::runtime_error(std::strerror(errno)) ;
}
if (flags == (flags | O_NONBLOCK)) // NOLINT (hicpp-signed-bitwise)
{
blocking_status = true ;
}
return blocking_status ;
}
inline
void
SerialPort::Implementation::SetDefaultLinuxSpecificModes()
{
// Make sure that the serial port is open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// @NOTE - termios.c_line is not a standard element of the termios
// structure, (as per the Single Unix Specification 3).
#ifdef __linux__
port_settings.c_line = '\0' ;
#endif
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::SetDefaultInputModes()
{
// Make sure that the serial port is open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Ignore Break conditions on input.
port_settings.c_iflag = IGNBRK ;
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::SetDefaultOutputModes()
{
// Make sure that the serial port is open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
port_settings.c_oflag = 0 ;
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::SetDefaultControlModes()
{
// Make sure that the serial port is open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Enable the receiver (CREAD) and ignore modem control lines (CLOCAL).
port_settings.c_cflag |= CREAD | CLOCAL ; // NOLINT (hicpp-signed-bitwise)
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::SetDefaultLocalModes()
{
// Make sure that the serial port is open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Get the current serial port settings.
termios port_settings {} ;
std::memset(&port_settings, 0, sizeof(port_settings)) ;
if (tcgetattr(this->mFileDescriptor,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
port_settings.c_lflag = 0 ;
// Apply the modified settings.
if (tcsetattr(this->mFileDescriptor,
TCSANOW,
&port_settings) < 0)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
inline
void
SerialPort::Implementation::Read(DataBuffer& dataBuffer,
const size_t numberOfBytes,
const size_t msTimeout)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if ((numberOfBytes == 0) and
(msTimeout == 0))
{
return ;
}
// Local variables.
size_t number_of_bytes_read = 0 ;
size_t number_of_bytes_remaining = std::max(numberOfBytes, static_cast<size_t>(1)) ;
size_t maximum_number_of_bytes = dataBuffer.max_size() ;
// Clear the data buffer and reserve enough space in the buffer to store the incoming data.
dataBuffer.clear() ;
dataBuffer.resize(number_of_bytes_remaining) ;
// Obtain the entry time.
const auto entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
while (number_of_bytes_remaining > 0)
{
// If insufficient space remains in the buffer, exit the loop and return .
if (number_of_bytes_remaining >= maximum_number_of_bytes - number_of_bytes_read)
{
break ;
}
if (numberOfBytes == 0)
{
// Add an additional element for the read() call.
dataBuffer.resize(number_of_bytes_read + 1) ;
}
const auto read_result = call_with_retry(read,
this->mFileDescriptor,
&dataBuffer[number_of_bytes_read],
number_of_bytes_remaining) ;
if (read_result > 0)
{
number_of_bytes_read += read_result ;
if (numberOfBytes != 0)
{
number_of_bytes_remaining = numberOfBytes - number_of_bytes_read ;
if (number_of_bytes_remaining == 0)
{
break ;
}
}
}
else if ((read_result <= 0) and
(errno != EWOULDBLOCK))
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Obtain the current time.
const auto current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
// Calculate the time delta.
const auto elapsed_time = current_time - entry_time ;
// Calculate the elapsed number of milliseconds.
const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
// If more than msTimeout milliseconds have elapsed while
// waiting for data, then we throw a ReadTimeout exception.
if ((msTimeout > 0) and
(static_cast<size_t>(elapsed_ms) > msTimeout))
{
// Resize the data buffer.
dataBuffer.resize(number_of_bytes_read) ;
throw ReadTimeout(ERR_MSG_READ_TIMEOUT) ;
}
// Allow sufficient time for an additional byte to arrive.
usleep(mByteArrivalTimeDelta) ;
}
}
inline
void
SerialPort::Implementation::Read(std::string& dataString,
const size_t numberOfBytes,
const size_t msTimeout)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
if ((numberOfBytes == 0) and
(msTimeout == 0))
{
return ;
}
// Local variables.
size_t number_of_bytes_read = 0 ;
size_t number_of_bytes_remaining = std::max(numberOfBytes, static_cast<size_t>(1)) ;
size_t maximum_number_of_bytes = dataString.max_size() ;
// Clear the data buffer and reserve enough space in the buffer to store the incoming data.
dataString.clear() ;
dataString.resize(number_of_bytes_remaining) ;
// Obtain the entry time.
const auto entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
while (number_of_bytes_remaining > 0)
{
// If insufficient space remains in the buffer, exit the loop and return .
if (number_of_bytes_remaining >= maximum_number_of_bytes - number_of_bytes_read)
{
break ;
}
if (numberOfBytes == 0)
{
// Add an additional element for the read() call.
dataString.resize(number_of_bytes_read + 1) ;
}
const auto read_result = call_with_retry(read,
this->mFileDescriptor,
&dataString[number_of_bytes_read],
number_of_bytes_remaining) ;
if (read_result > 0)
{
number_of_bytes_read += read_result ;
if (numberOfBytes != 0)
{
number_of_bytes_remaining = numberOfBytes - number_of_bytes_read ;
if (number_of_bytes_remaining == 0)
{
break ;
}
}
}
else if (read_result <= 0 &&
errno != EWOULDBLOCK)
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Obtain the current time.
const auto current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
// Calculate the time delta.
const auto elapsed_time = current_time - entry_time ;
// Calculate the elapsed number of milliseconds.
const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
// If more than msTimeout milliseconds have elapsed while
// waiting for data, then we throw a ReadTimeout exception.
if ((msTimeout > 0) and
(static_cast<size_t>(elapsed_ms) > msTimeout))
{
// Resize the data string.
dataString.resize(number_of_bytes_read) ;
throw ReadTimeout(ERR_MSG_READ_TIMEOUT) ;
}
// Allow sufficient time for an additional byte to arrive.
usleep(mByteArrivalTimeDelta) ;
}
}
template <typename ByteType, typename /* unused */>
inline
void
SerialPort::Implementation::ReadByte(ByteType& charBuffer,
const size_t msTimeout)
{
// Double check to make sure that ByteType is exactly one byte long.
static_assert(sizeof(ByteType) == 1,
"ByteType must have a size of exactly one byte.") ;
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Obtain the entry time.
const auto entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
// Loop until the number of bytes requested have been read or the
// timeout has elapsed.
ssize_t read_result = 0 ;
while (read_result < 1)
{
read_result = call_with_retry(read,
this->mFileDescriptor,
&charBuffer,
sizeof(ByteType)) ;
// If the byte has been successfully read, exit the loop and return.
if (read_result == sizeof(ByteType))
{
break ;
}
if ((read_result <= 0) and
(errno != EWOULDBLOCK))
{
throw std::runtime_error(std::strerror(errno)) ;
}
// Obtain the current time.
const auto current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
// Calculate the time delta.
const auto elapsed_time = current_time - entry_time ;
// Calculate the elapsed number of milliseconds.
const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
// Throw a ReadTimeout exception if more than msTimeout milliseconds
// have elapsed while waiting for data.
if ((msTimeout > 0) and
(static_cast<size_t>(elapsed_ms) > msTimeout))
{
throw ReadTimeout(ERR_MSG_READ_TIMEOUT) ;
}
// Allow sufficient time for an additional byte to arrive.
usleep(mByteArrivalTimeDelta) ;
}
}
inline
void
SerialPort::Implementation::ReadLine(std::string& dataString,
const char lineTerminator,
const size_t msTimeout)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Clear the data string.
dataString.clear() ;
unsigned char next_char = 0 ;
size_t elapsed_ms = 0 ;
ssize_t remaining_ms = 0 ;
std::chrono::high_resolution_clock::duration entry_time ;
std::chrono::high_resolution_clock::duration current_time ;
std::chrono::high_resolution_clock::duration elapsed_time ;
// Obtain the entry time.
entry_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
while (next_char != lineTerminator)
{
// Obtain the current time.
current_time = std::chrono::high_resolution_clock::now().time_since_epoch() ;
// Calculate the time delta.
elapsed_time = current_time - entry_time ;
// Calculate the elapsed number of milliseconds.
elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed_time).count() ;
// If more than msTimeout milliseconds have elapsed while
// waiting for data, then we throw a ReadTimeout exception.
if (msTimeout > 0 &&
elapsed_ms > msTimeout)
{
throw ReadTimeout(ERR_MSG_READ_TIMEOUT) ;
}
remaining_ms = msTimeout - elapsed_ms ;
this->ReadByte(next_char,
remaining_ms) ;
dataString += next_char ;
}
}
inline
void
SerialPort::Implementation::Write(const DataBuffer& dataBuffer)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
size_t number_of_bytes = dataBuffer.size() ;
// Nothing needs to be done if there is no data in the string.
if (number_of_bytes <= 0)
{
return ;
}
// Local variables.
size_t number_of_bytes_written = 0 ;
size_t number_of_bytes_remaining = number_of_bytes ;
// Write the data to the serial port. Keep retrying if EAGAIN
// error is received and EWOULDBLOCK is not received.
ssize_t write_result = 0 ;
while (number_of_bytes_remaining > 0)
{
write_result = call_with_retry(write,
this->mFileDescriptor,
&dataBuffer[number_of_bytes_written],
number_of_bytes_remaining) ;
if (write_result >= 0)
{
number_of_bytes_written += write_result ;
number_of_bytes_remaining = number_of_bytes - number_of_bytes_written ;
if (number_of_bytes_remaining == 0)
{
break ;
}
}
else if (write_result <= 0 &&
errno != EWOULDBLOCK)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
}
inline
void
SerialPort::Implementation::Write(const std::string& dataString)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
size_t number_of_bytes = dataString.size() ;
// Nothing needs to be done if there is no data in the string.
if (number_of_bytes <= 0)
{
return ;
}
// Local variables.
size_t number_of_bytes_written = 0 ;
size_t number_of_bytes_remaining = number_of_bytes ;
// Write the data to the serial port. Keep retrying if EAGAIN
// error is received and EWOULDBLOCK is not received.
ssize_t write_result = 0 ;
while (number_of_bytes_remaining > 0)
{
write_result = call_with_retry(write,
this->mFileDescriptor,
&dataString[number_of_bytes_written],
number_of_bytes_remaining) ;
if (write_result >= 0)
{
number_of_bytes_written += write_result ;
number_of_bytes_remaining = number_of_bytes - number_of_bytes_written ;
if (number_of_bytes_remaining == 0)
{
break ;
}
}
else if (write_result <= 0 &&
errno != EWOULDBLOCK)
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
}
inline
void
SerialPort::Implementation::WriteByte(const char charBuffer)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Write the data to the serial port. Keep retrying if EAGAIN
// error is received and EWOULDBLOCK is not received.
ssize_t write_result = 0 ;
while (write_result <= 0)
{
write_result = call_with_retry(write,
this->mFileDescriptor,
&charBuffer,
1) ;
if (write_result == 1)
{
break ;
}
if ((write_result <= 0) and
(errno != EWOULDBLOCK))
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
}
inline
void
SerialPort::Implementation::WriteByte(const unsigned char charBuffer)
{
// Throw an exception if the serial port is not open.
if (not this->IsOpen())
{
throw NotOpen(ERR_MSG_PORT_NOT_OPEN) ;
}
// Write the data to the serial port. Keep retrying if EAGAIN
// error is received and EWOULDBLOCK is not received.
ssize_t write_result = 0 ;
while (write_result <= 0)
{
write_result = call_with_retry(write,
this->mFileDescriptor,
&charBuffer,
1) ;
if (write_result == 1)
{
break ;
}
if ((write_result <= 0) and
(errno != EWOULDBLOCK))
{
throw std::runtime_error(std::strerror(errno)) ;
}
}
}
} // namespace LibSerial
LibSerial::AlreadyOpen
Exception error thrown when the serial port is already open.
Definition SerialPortConstants.h:141
LibSerial::NotOpen
Exception error thrown when the serial port is not open.
Definition SerialPortConstants.h:126
LibSerial::OpenFailed
Exception error thrown when the serial port could not be opened.
Definition SerialPortConstants.h:156
LibSerial::ReadTimeout
Exception error thrown when data could not be read from the serial port before the timeout had been e...
Definition SerialPortConstants.h:172
LibSerial::SerialPort::Implementation
SerialPort::Implementation is the SerialPort implementation class.
Definition SerialPort.cpp:55
LibSerial::SerialPort::Implementation::SetCharacterSize
void SetCharacterSize(const CharacterSize &characterSize)
Sets the character size for the serial port.
Definition SerialPort.cpp:1305
LibSerial::SerialPort::Implementation::SetSerialPortBlockingStatus
void SetSerialPortBlockingStatus(bool blockingStatus)
Sets the current state of the serial port blocking status.
Definition SerialPort.cpp:2031
LibSerial::SerialPort::Implementation::~Implementation
~Implementation() noexcept
Default Destructor for a SerialPort object. Closes the serial port associated with mFileDescriptor if...
Definition SerialPort.cpp:823
LibSerial::SerialPort::Implementation::GetDTR
bool GetDTR()
Gets the serial port DTR line status.
Definition SerialPort.cpp:1786
LibSerial::SerialPort::Implementation::SetVMin
void SetVMin(const short vmin)
Sets the minimum number of characters for non-canonical reads.
Definition SerialPort.cpp:1648
LibSerial::SerialPort::Implementation::WriteByte
void WriteByte(char charBuffer)
Writes a single byte to the serial port.
Definition SerialPort.cpp:2662
LibSerial::SerialPort::Implementation::ReadLine
void ReadLine(std::string &dataString, char lineTerminator='\n', size_t msTimeout=0)
Reads a line of characters from the serial port. The method will timeout if no data is received in th...
Definition SerialPort.cpp:2504
LibSerial::SerialPort::Implementation::SetDefaultSerialPortParameters
void SetDefaultSerialPortParameters()
Sets all serial port paramters to their default values.
Definition SerialPort.cpp:1061
LibSerial::SerialPort::Implementation::Close
void Close()
Closes the serial port. All settings of the serial port will be lost and no more I/O can be performed...
Definition SerialPort.cpp:912
LibSerial::SerialPort::Implementation::GetCharacterSize
CharacterSize GetCharacterSize() const
Gets the character size being used for serial communication.
Definition SerialPort.cpp:1357
LibSerial::SerialPort::Implementation::GetFileDescriptor
int GetFileDescriptor() const
Gets the serial port file descriptor.
Definition SerialPort.cpp:1852
LibSerial::SerialPort::Implementation::GetCTS
bool GetCTS()
Gets the serial port CTS line status.
Definition SerialPort.cpp:1826
LibSerial::SerialPort::Implementation::DrainWriteBuffer
void DrainWriteBuffer()
Waits until the write buffer is drained and then returns.
Definition SerialPort.cpp:962
LibSerial::SerialPort::Implementation::SetVTime
void SetVTime(const short vtime)
Sets character buffer timeout for non-canonical reads in deciseconds.
Definition SerialPort.cpp:1710
LibSerial::SerialPort::Implementation::GetParity
Parity GetParity() const
Gets the parity type for the serial port.
Definition SerialPort.cpp:1543
LibSerial::SerialPort::Implementation::GetSerialPortBlockingStatus
bool GetSerialPortBlockingStatus() const
Gets the current state of the serial port blocking status.
Definition SerialPort.cpp:2065
LibSerial::SerialPort::Implementation::GetFlowControl
FlowControl GetFlowControl() const
Get the current flow control setting.
Definition SerialPort.cpp:1444
LibSerial::SerialPort::Implementation::GetRTS
bool GetRTS()
Gets the serial port RTS line status.
Definition SerialPort.cpp:1813
LibSerial::SerialPort::Implementation::SetParity
void SetParity(const Parity &parityType)
Sets the parity type for the serial port.
Definition SerialPort.cpp:1492
LibSerial::SerialPort::Implementation::IsOpen
bool IsOpen() const
Determines if the serial port is open for I/O.
Definition SerialPort.cpp:1026
LibSerial::SerialPort::Implementation::SetStopBits
void SetStopBits(const StopBits &stopBits)
Sets the number of stop bits to be used with the serial port.
Definition SerialPort.cpp:1576
LibSerial::SerialPort::Implementation::Write
void Write(const DataBuffer &dataBuffer)
Writes a DataBuffer to the serial port.
Definition SerialPort.cpp:2560
LibSerial::SerialPort::Implementation::GetStopBits
StopBits GetStopBits() const
Gets the number of stop bits currently being used by the serial.
Definition SerialPort.cpp:1619
LibSerial::SerialPort::Implementation::SetBaudRate
void SetBaudRate(const BaudRate &baudRate)
Sets the baud rate for the serial port to the specified value.
Definition SerialPort.cpp:1089
LibSerial::SerialPort::Implementation::GetModemControlLine
bool GetModemControlLine(int modemLine)
Get the current state of the specified modem control line.
Definition SerialPort.cpp:1991
LibSerial::SerialPort::Implementation::FlushOutputBuffer
void FlushOutputBuffer()
Flushes the serial port output buffer.
Definition SerialPort.cpp:994
LibSerial::SerialPort::Implementation::SetRTS
void SetRTS(const bool rtsState)
Sets the serial port RTS line status.
Definition SerialPort.cpp:1799
LibSerial::SerialPort::Implementation::GetBaudRate
BaudRate GetBaudRate() const
Gets the current baud rate for the serial port.
Definition SerialPort.cpp:1129
LibSerial::SerialPort::Implementation::SetModemControlLine
void SetModemControlLine(int modemLine, bool lineState)
Set the specified modem control line to the specified value.
Definition SerialPort.cpp:1936
LibSerial::SerialPort::Implementation::Open
void Open(const std::string &fileName, const std::ios_base::openmode &openMode)
Opens the serial port associated with the specified file name and the specified mode.
Definition SerialPort.cpp:845
LibSerial::SerialPort::Implementation::IsDataAvailable
bool IsDataAvailable()
Determines if data is available at the serial port.
Definition SerialPort.cpp:1033
LibSerial::SerialPort::Implementation::FlushInputBuffer
void FlushInputBuffer()
Flushes the serial port input buffer.
Definition SerialPort.cpp:978
LibSerial::SerialPort::Implementation::SetDTR
void SetDTR(const bool dtrState)
Sets the serial port DTR line status.
Definition SerialPort.cpp:1772
LibSerial::SerialPort::Implementation::ReadByte
void ReadByte(ByteType &charBuffer, size_t msTimeout=0)
Reads a single byte from the serial port. If no data is available within the specified number of mill...
Definition SerialPort.cpp:2442
LibSerial::SerialPort::Implementation::GetVTime
short GetVTime() const
Gets the current timeout value for non-canonical reads in deciseconds.
Definition SerialPort.cpp:1749
LibSerial::SerialPort::Implementation::Read
void Read(DataBuffer &dataBuffer, size_t numberOfBytes=0, size_t msTimeout=0)
Reads the specified number of bytes from the serial port. The method will timeout if no data is recei...
Definition SerialPort.cpp:2253
LibSerial::SerialPort::Implementation::SetFlowControl
void SetFlowControl(const FlowControl &flowControlType)
Sets flow control for the serial port.
Definition SerialPort.cpp:1382
LibSerial::SerialPort::Implementation::FlushIOBuffers
void FlushIOBuffers()
Flushes the serial port input and output buffers.
Definition SerialPort.cpp:1010
LibSerial::SerialPort::Implementation::Implementation
Implementation()=default
Default Constructor.
LibSerial::SerialPort::Implementation::GetNumberOfBytesAvailable
int GetNumberOfBytesAvailable()
Gets the number of bytes available in the read buffer.
Definition SerialPort.cpp:1865
LibSerial::SerialPort::Implementation::GetVMin
short GetVMin() const
Gets the VMIN value for the device, which represents the minimum number of characters for non-canonic...
Definition SerialPort.cpp:1687
LibSerial::SerialPort::Implementation::GetDSR
bool GetDSR()
Gets the serial port DSR line status.
Definition SerialPort.cpp:1839
LibSerial::SerialPort
SerialPort allows an object oriented approach to serial port communication. A serial port object can ...
Definition SerialPort.h:56
LibSerial::SerialPort::SetBaudRate
void SetBaudRate(const BaudRate &baudRate)
Sets the baud rate for the serial port to the specified value.
Definition SerialPort.cpp:570
LibSerial::SerialPort::SetModemControlLine
void SetModemControlLine(int modemLine, bool lineState)
Set the specified modem control line to the specified value.
Definition SerialPort.cpp:792
LibSerial::SerialPort::SetParity
void SetParity(const Parity &parityType)
Sets the parity type for the serial port.
Definition SerialPort.cpp:606
LibSerial::SerialPort::Open
void Open(const std::string &fileName, const std::ios_base::openmode &openMode=std::ios_base::in|std::ios_base::out)
Opens the serial port associated with the specified file name and the specified mode.
Definition SerialPort.cpp:514
LibSerial::SerialPort::GetCTS
bool GetCTS()
Get the status of the CTS line.
Definition SerialPort.cpp:678
LibSerial::SerialPort::GetSerialPortBlockingStatus
bool GetSerialPortBlockingStatus() const
Gets the current state of the serial port blocking status.
Definition SerialPort.cpp:786
LibSerial::SerialPort::WriteByte
void WriteByte(char charbuffer)
Writes a single byte to the serial port.
Definition SerialPort.cpp:768
LibSerial::SerialPort::FlushInputBuffer
void FlushInputBuffer()
Flushes the serial port input buffer.
Definition SerialPort.cpp:534
LibSerial::SerialPort::SetFlowControl
void SetFlowControl(const FlowControl &flowControlType)
Sets flow control for the serial port.
Definition SerialPort.cpp:594
LibSerial::SerialPort::SetDefaultSerialPortParameters
void SetDefaultSerialPortParameters()
Sets all serial port paramters to their default values.
Definition SerialPort.cpp:564
LibSerial::SerialPort::SerialPort
SerialPort()
Default Constructor.
Definition SerialPort.cpp:477
LibSerial::SerialPort::GetFlowControl
FlowControl GetFlowControl() const
Gets the current flow control setting.
Definition SerialPort.cpp:600
LibSerial::SerialPort::GetCharacterSize
CharacterSize GetCharacterSize() const
Gets the character size being used for serial communication.
Definition SerialPort.cpp:588
LibSerial::SerialPort::Write
void Write(const DataBuffer &dataBuffer)
Writes a DataBuffer to the serial port.
Definition SerialPort.cpp:756
LibSerial::SerialPort::GetDTR
bool GetDTR() const
Gets the status of the DTR line.
Definition SerialPort.cpp:660
LibSerial::SerialPort::SetRTS
void SetRTS(const bool rtsState=true)
Set the RTS line to the specified value.
Definition SerialPort.cpp:666
LibSerial::SerialPort::SetVMin
void SetVMin(const short vmin)
Sets the minimum number of characters for non-canonical reads.
Definition SerialPort.cpp:630
LibSerial::SerialPort::~SerialPort
virtual ~SerialPort() noexcept
Default Destructor for a SerialPort object. Closes the serial port associated with mFileDescriptor if...
LibSerial::SerialPort::GetStopBits
StopBits GetStopBits() const
Gets the number of stop bits currently being used by the serial.
Definition SerialPort.cpp:624
LibSerial::SerialPort::GetRTS
bool GetRTS() const
Get the status of the RTS line.
Definition SerialPort.cpp:672
LibSerial::SerialPort::Close
void Close()
Closes the serial port. All settings of the serial port will be lost and no more I/O can be performed...
Definition SerialPort.cpp:522
LibSerial::SerialPort::operator=
SerialPort & operator=(const SerialPort &otherSerialPort)=delete
Copy assignment is disallowed.
LibSerial::SerialPort::SetCharacterSize
void SetCharacterSize(const CharacterSize &characterSize)
Sets the character size for the serial port.
Definition SerialPort.cpp:582
LibSerial::SerialPort::IsDataAvailable
bool IsDataAvailable()
Checks if data is available at the input of the serial port.
Definition SerialPort.cpp:552
LibSerial::SerialPort::GetBaudRate
BaudRate GetBaudRate() const
Gets the current baud rate for the serial port.
Definition SerialPort.cpp:576
LibSerial::SerialPort::SetVTime
void SetVTime(const short vtime)
Sets character buffer timeout for non-canonical reads in deciseconds.
Definition SerialPort.cpp:642
LibSerial::SerialPort::FlushIOBuffers
void FlushIOBuffers()
Flushes the serial port input and output buffers.
Definition SerialPort.cpp:546
LibSerial::SerialPort::FlushOutputBuffer
void FlushOutputBuffer()
Flushes the serial port output buffer.
Definition SerialPort.cpp:540
LibSerial::SerialPort::GetParity
Parity GetParity() const
Gets the parity type for the serial port.
Definition SerialPort.cpp:612
LibSerial::SerialPort::GetVMin
short GetVMin() const
Gets the VMIN value for the device, which represents the minimum number of characters for non-canonic...
Definition SerialPort.cpp:636
LibSerial::SerialPort::GetModemControlLine
bool GetModemControlLine(int modemLine)
Get the current state of the specified modem control line.
Definition SerialPort.cpp:799
LibSerial::SerialPort::GetVTime
short GetVTime() const
Gets the current timeout value for non-canonical reads in deciseconds.
Definition SerialPort.cpp:648
LibSerial::SerialPort::Read
void Read(DataBuffer &dataBuffer, size_t numberOfBytes=0, size_t msTimeout=0)
Reads the specified number of bytes from the serial port. The method will timeout if no data is recei...
Definition SerialPort.cpp:710
LibSerial::SerialPort::GetDSR
bool GetDSR()
Get the status of the DSR line.
Definition SerialPort.cpp:684
LibSerial::SerialPort::ReadByte
void ReadByte(char &charBuffer, size_t msTimeout=0)
Reads a single byte from the serial port. If no data is available within the specified number of mill...
Definition SerialPort.cpp:730
LibSerial::SerialPort::GetNumberOfBytesAvailable
int GetNumberOfBytesAvailable()
Gets the number of bytes available in the read buffer.
Definition SerialPort.cpp:696
LibSerial::SerialPort::GetFileDescriptor
int GetFileDescriptor() const
Gets the serial port file descriptor.
Definition SerialPort.cpp:690
LibSerial::SerialPort::SetDTR
void SetDTR(const bool dtrState=true)
Sets the DTR line to the specified value.
Definition SerialPort.cpp:654
LibSerial::SerialPort::ReadLine
void ReadLine(std::string &dataString, char lineTerminator='\n', size_t msTimeout=0)
Reads a line of characters from the serial port. The method will timeout if no data is received in th...
Definition SerialPort.cpp:746
LibSerial::SerialPort::DrainWriteBuffer
void DrainWriteBuffer()
Waits until the write buffer is drained and then returns.
Definition SerialPort.cpp:528
LibSerial::SerialPort::IsOpen
bool IsOpen() const
Determines if the serial port is open for I/O.
Definition SerialPort.cpp:558
LibSerial::SerialPort::SetSerialPortBlockingStatus
void SetSerialPortBlockingStatus(bool blockingStatus)
Sets the current state of the serial port blocking status.
Definition SerialPort.cpp:780
LibSerial::SerialPort::SetStopBits
void SetStopBits(const StopBits &stopBits)
Sets the number of stop bits to be used with the serial port.
Definition SerialPort.cpp:618