Skip to content

Commit 01594b6

Browse files
authored
🔀 Merge pull request #15 from NestorDP/feat-read-with-read-fails
Feat read with read fails
2 parents 26f01c4 + ef25be4 commit 01594b6

File tree

4 files changed

+285
-85
lines changed

4 files changed

+285
-85
lines changed

‎include/libserial/serial.hpp‎

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
#include <stdio.h>
99
#include <string.h>
1010
#include <unistd.h>
11+
#include <poll.h>
1112
#include <asm/ioctls.h>
1213
#include <asm/termbits.h>
1314
#include <sys/ioctl.h>
15+
#include <sys/types.h>
1416

1517
#include <chrono>
1618
#include <iostream>
1719
#include <memory>
20+
#include <functional>
1821
#include <string>
1922
#include <thread>
2023
#include <vector>
@@ -227,7 +230,7 @@ void setDataLength(DataLength nbits);
227230
* @param parity The desired parity setting (ENABLE or DISABLE)
228231
* @throws SerialException if parity cannot be set
229232
*/
230-
void setParity([[maybe_unused]] Parity parity);
233+
void setParity(Parity parity);
231234

232235
/**
233236
* @brief Sets the stop bits configuration
@@ -237,7 +240,7 @@ void setParity([[maybe_unused]] Parity parity);
237240
* @param stop_bits The desired stop bits setting (ONE, ONE_AND_HALF, or TWO)
238241
* @throws SerialException if stop bits cannot be set
239242
*/
240-
void setStopBits([[maybe_unused]] StopBits stop_bits);
243+
void setStopBits(StopBits stop_bits);
241244

242245
/**
243246
* @brief Sets the flow control configuration
@@ -315,9 +318,41 @@ int getBaudRate() const;
315318
void setFdForTest(int fd) {
316319
fd_serial_port_ = fd;
317320
}
321+
322+
// For testing - allow injection of mock functions
323+
void setSystemCallFunctions(
324+
std::function<int(struct pollfd*, nfds_t, int)> poll_func,
325+
std::function<ssize_t(int, void*, size_t)> read_func) {
326+
poll_ = [poll_func](struct pollfd* f, nfds_t n, int t) {
327+
return poll_func(f, n, t);
328+
};
329+
read_ = [read_func](int fd, void* buf, size_t sz) {
330+
return read_func(fd, buf, sz);
331+
};
332+
}
318333
#endif
319334

320335
private:
336+
/**
337+
* @brief Poll system call function wrapper
338+
*
339+
* Allows injection of custom poll function for testing.
340+
*/
341+
std::function<int(struct pollfd*, nfds_t, int)> poll_ =
342+
[](struct pollfd* f, nfds_t n, int t) {
343+
return ::poll(f, n, t);
344+
};
345+
346+
/**
347+
* @brief Read system call function wrapper
348+
*
349+
* Allows injection of custom read function for testing.
350+
*/
351+
std::function<ssize_t(int, void*, size_t)> read_ =
352+
[](int fd, void* buf, size_t sz) {
353+
return ::read(fd, buf, sz);
354+
};
355+
321356
/**
322357
* @brief Applies terminal settings to the port
323358
*

‎src/serial.cpp‎

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,17 @@ size_t Serial::read(std::shared_ptr<std::string> buffer) {
7373

7474
// 0 => no wait (immediate return), -1 => block forever, positive => wait specified milliseconds
7575
int timeout_ms = static_cast<int>(read_timeout_ms_.count());
76-
int pr = poll(&fd_poll, 1, timeout_ms);
76+
int pr = poll_(&fd_poll, 1, timeout_ms);
7777
if (pr < 0) {
78-
if (errno == EINTR) {
79-
throw IOException("Interrupted while polling");
80-
}
8178
throw IOException(std::string("Error in poll(): ") + strerror(errno));
8279
}
8380
if (pr == 0) {
84-
throw IOException("Read operation timed out after " + std::to_string(timeout_ms) + "ms");
81+
throw IOException("Read operation timed out after " + std::to_string(timeout_ms) +
82+
" milliseconds");
8583
}
8684

8785
// Data available: do the read
88-
ssize_t bytes_read = ::read(fd_serial_port_, const_cast<char*>(buffer->data()), kMaxSafeReadSize);
86+
ssize_t bytes_read = read_(fd_serial_port_, const_cast<char*>(buffer->data()), kMaxSafeReadSize);
8987
if (bytes_read < 0) {
9088
throw IOException(std::string("Error reading from serial port: ") + strerror(errno));
9189
}
@@ -104,7 +102,7 @@ size_t Serial::readBytes(std::shared_ptr<std::string> buffer, size_t num_bytes)
104102
}
105103

106104
if (num_bytes == 0) {
107-
throw IOException("Invalid number of bytes requested");
105+
throw IOException("Number of bytes requested must be greater than zero");
108106
}
109107

110108
buffer->clear();
@@ -157,7 +155,7 @@ size_t Serial::readUntil(std::shared_ptr<std::string> buffer, char terminator) {
157155
int64_t remaining_timeout = read_timeout_ms_.count() - elapsed;
158156
int timeout_ms = static_cast<int>(remaining_timeout);
159157

160-
int poll_result = poll(&pfd, 1, timeout_ms);
158+
int poll_result = poll_(&pfd, 1, timeout_ms);
161159
if (poll_result < 0) {
162160
throw IOException("Error in poll(): " + std::string(strerror(errno)));
163161
}
@@ -167,19 +165,19 @@ size_t Serial::readUntil(std::shared_ptr<std::string> buffer, char terminator) {
167165
}
168166

169167
// Data is available, perform the read
170-
ssize_t bytes_read = ::read(fd_serial_port_, &temp_char, 1);
168+
ssize_t bytes_read = read_(fd_serial_port_, &temp_char, 1);
171169

172170
if (bytes_read < 0) {
173171
if (errno == EAGAIN || errno == EWOULDBLOCK) {
174172
// Non-blocking read, no data available right now
175173
std::this_thread::sleep_for(std::chrono::milliseconds(1));
176174
continue;
177175
}
178-
throw SerialException("Error reading from serial port: " + std::string(strerror(errno)));
176+
throw IOException("Error reading from serial port: " + std::string(strerror(errno)));
179177
}
180178
else if (bytes_read == 0) {
181179
// End of file or connection closed
182-
throw SerialException("Connection closed while reading");
180+
throw IOException("Connection closed while reading: no terminator found");
183181
}
184182

185183
// Add the character to buffer (including terminator)
@@ -246,35 +244,30 @@ void Serial::setDataLength(DataLength nbits) {
246244
this->setTermios2();
247245
}
248246

249-
void Serial::setParity([[maybe_unused]] Parity parity) {
250-
// this->getTermios2();
251-
// switch (parity) {
252-
// case Parity::DISABLE:
253-
// options_.c_cflag &= ~PARENB;
254-
// break;
255-
// case Parity::ENABLE:
256-
// options_.c_cflag |= PARENB;
257-
// break;
258-
// default:
259-
// options_.c_cflag &= ~PARENB;
260-
// break;
261-
// }
262-
// this->setTermios2();
247+
void Serial::setParity(Parity parity) {
248+
this->getTermios2();
249+
switch (parity) {
250+
case Parity::DISABLE:
251+
options_.c_cflag &= ~PARENB;
252+
break;
253+
case Parity::ENABLE:
254+
options_.c_cflag |= PARENB;
255+
break;
256+
}
257+
this->setTermios2();
263258
}
264259

265-
void Serial::setStopBits([[maybe_unused]] StopBits stop_bits) {
266-
// this->getTermios2();
267-
// switch (stop_bits) {
268-
// case StopBits::DISABLE:
269-
// options_.c_cflag &= ~CSTOP;
270-
// break;
271-
// case StopBits::ENABLE:
272-
// options_.c_cflag |= CSTOP;
273-
// default:
274-
// options_.c_cflag &= ~CSTOP;
275-
// break;
276-
// }
277-
// this->setTermios2();
260+
void Serial::setStopBits(StopBits stop_bits) {
261+
this->getTermios2();
262+
switch (stop_bits) {
263+
case StopBits::ONE:
264+
options_.c_cflag &= ~CSTOP;
265+
break;
266+
case StopBits::TWO:
267+
options_.c_cflag |= CSTOP;
268+
break;
269+
}
270+
this->setTermios2();
278271
}
279272

280273
void Serial::setFlowControl([[maybe_unused]] FlowControl flow_control) {

‎test/test_ports.cpp‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ TEST_F(PortsTest, ScanPortsThrowsWhenPathMissing) {
5757
FAIL() << "Expected libserial::SerialException to be thrown";
5858
}
5959
catch (const libserial::SerialException& e) {
60-
GTEST_LOG_(INFO) << "Exception: " << e.what();
6160
// Optionally assert something about the message:
6261
EXPECT_NE(std::string(e.what()).find("Error while reading"), std::string::npos);
6362
}

0 commit comments

Comments
 (0)