Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions include/libserial/serial.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,10 @@ int getAvailableData() const;
* timing out. A value of 0 means no timeout (blocking).
*
* @param timeout Timeout in milliseconds
* @throws SerialException if setting cannot be applied
*
* @note The system timeout is set in deciseconds (100ms units), so the value
* will be rounded down to the nearest multiple of 100ms. For example,
* 1549ms will be set as 1500ms.
*/
void setReadTimeout(std::chrono::milliseconds timeout);

Expand Down Expand Up @@ -339,6 +342,20 @@ int getBaudRate() const;
*/
DataLength getDataLength() const;

/**
* @brief Gets the current read timeout setting
*
* @return The current read timeout in milliseconds
*/
std::chrono::milliseconds getReadTimeout() const;

/**
* @brief Gets the current minimum number of characters to read setting
*
* @return The current minimum number of characters to read
*/
uint16_t getMinNumberCharRead() const;

#ifdef BUILD_TESTING_ON
// WARNING: Test helper only! This function bypasses normal initialization
// and may leave the Serial object in an inconsistent state. It is intended
Expand Down Expand Up @@ -468,13 +485,6 @@ std::chrono::milliseconds write_timeout_ms_{1000}; ///< Write timeout in mill
*/
size_t max_safe_read_size_{2048}; // 2KB limit

/**
* @brief Timeout value in milliseconds
*
* Used for configuring certain serial port timeouts (default 1000ms).
*/
uint16_t timeout_{1000};

/**
* @brief Minimum number of characters to read
*
Expand Down
14 changes: 12 additions & 2 deletions src/serial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ void Serial::setBaudRate(BaudRate baud_rate) {

void Serial::setReadTimeout(std::chrono::milliseconds timeout) {
read_timeout_ms_ = timeout;
this->setTimeOut(static_cast<uint16_t>(timeout.count() / 100));
}

void Serial::setWriteTimeout(std::chrono::milliseconds timeout) {
Expand Down Expand Up @@ -329,9 +330,8 @@ void Serial::setTerminator(Terminator term) {
}

void Serial::setTimeOut(uint16_t time) {
timeout_ = time;
this->getTermios2();
options_.c_cc[VTIME] = timeout_;
options_.c_cc[VTIME] = time;
this->setTermios2();
}

Expand Down Expand Up @@ -374,6 +374,16 @@ DataLength Serial::getDataLength() const {
}
}

std::chrono::milliseconds Serial::getReadTimeout() const {
this->getTermios2();
return std::chrono::milliseconds(options_.c_cc[VTIME] * 100);
}

uint16_t Serial::getMinNumberCharRead() const {
this->getTermios2();
return static_cast<uint16_t>(options_.c_cc[VMIN]);
}

void Serial::getTermios2() const {
ssize_t error = ioctl_(fd_serial_port_, TCGETS2, &options_);
if (error < 0) {
Expand Down
72 changes: 53 additions & 19 deletions test/test_serial_pty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,30 +102,30 @@ TEST_F(PseudoTerminalTest, ParameterizedConstructor) {
libserial::Serial serial_port(slave_port_);
}

TEST_F(PseudoTerminalTest, SetTermios2WithFail) {
libserial::Serial serial_port;
// TEST_F(PseudoTerminalTest, SetTermios2WithFail) {
// libserial::Serial serial_port;

serial_port.open(slave_port_);
// serial_port.open(slave_port_);

// Inject failure into ioctl for setTermios2
serial_port.setIoctlSystemFunction(
[](int, unsigned long, void*) -> int { // NOLINT
errno = EIO;
return -1;
});
// // Inject failure into ioctl for setTermios2
// serial_port.setIoctlSystemFunction(
// [](int, unsigned long, void*) -> int { // NOLINT
// errno = EIO;
// return -1;
// });

EXPECT_THROW({
serial_port.setBaudRate(9600);
}, libserial::SerialException);
// EXPECT_THROW({
// serial_port.setBaudRate(9600);
// }, libserial::SerialException);

// Restore ioctl function for cleanup
serial_port.setIoctlSystemFunction(
[](int fd, unsigned long request, void* arg) -> int { // NOLINT
return ::ioctl(fd, request, arg);
});
// // Restore ioctl function for cleanup
// serial_port.setIoctlSystemFunction(
// [](int fd, unsigned long request, void* arg) -> int { // NOLINT
// return ::ioctl(fd, request, arg);
// });

serial_port.close();
}
// serial_port.close();
// }

TEST_F(PseudoTerminalTest, SetAndGetBaudRate) {
libserial::Serial serial_port;
Expand Down Expand Up @@ -189,6 +189,40 @@ TEST_F(PseudoTerminalTest, SetAndGetBaudRate) {
// serial_port.close();
// }

TEST_F(PseudoTerminalTest, SetGetReadTimeout) {
libserial::Serial serial_port;

serial_port.open(slave_port_);

// Set read timeout
std::chrono::milliseconds timeout_set{1500};
EXPECT_NO_THROW({ serial_port.setReadTimeout(timeout_set); });

// Get read timeout and verify
std::chrono::milliseconds timeout_get{0};
EXPECT_NO_THROW({ timeout_get = serial_port.getReadTimeout(); });
EXPECT_EQ(timeout_get.count(), timeout_set.count());

serial_port.close();
}

TEST_F(PseudoTerminalTest, SetGetMinNumberCharRead) {
libserial::Serial serial_port;

serial_port.open(slave_port_);

// Set minimum number of characters to read
uint16_t min_chars_set{5};
EXPECT_NO_THROW({ serial_port.setMinNumberCharRead(min_chars_set); });

// Get minimum number of characters to read and verify
uint16_t min_chars_get{0};
EXPECT_NO_THROW({ min_chars_get = serial_port.getMinNumberCharRead(); });
EXPECT_EQ(min_chars_get, min_chars_set);

serial_port.close();
}

TEST_F(PseudoTerminalTest, SetParity) {
libserial::Serial serial_port;

Expand Down