From de812c2399a12bd14fe02b4dda3208f7cb6083fa Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 10:18:02 +0200 Subject: [PATCH 01/14] feat: enhance serial configuration with flow control and timeout settings --- README.md | 33 +++-- include/cpp_core/interface/get_version.h | 3 +- include/cpp_core/interface/serial_drain.h | 5 +- .../interface/serial_in_bytes_waiting.h | 5 +- include/cpp_core/interface/serial_open.h | 11 +- include/cpp_core/interface/serial_read.h | 13 +- include/cpp_core/interface/serial_read_line.h | 8 +- .../cpp_core/interface/serial_read_until.h | 10 +- .../interface/serial_read_until_sequence.h | 11 +- include/cpp_core/interface/serial_write.h | 12 +- include/cpp_core/reflection.test.cpp | 4 +- include/cpp_core/serial.h | 2 + include/cpp_core/serial_config.hpp | 133 ++++++++++++++++-- include/cpp_core/serial_config.test.cpp | 34 ++++- include/cpp_core/serial_interface.test.cpp | 39 +++++ include/cpp_core/validation.hpp | 54 ++++++- 16 files changed, 303 insertions(+), 74 deletions(-) create mode 100644 include/cpp_core/serial_interface.test.cpp diff --git a/README.md b/README.md index 8dc5574..86ab29c 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This repository does not provide a ready-to-load shared library by itself. It pr - `include/cpp_core/serial.h`: aggregated C ABI for serial operations - `include/cpp_core/status_code.h`: shared status-code model -- `include/cpp_core/interface/get_version.h`: version struct and `getVersion` +- `include/cpp_core/interface/get_version.h`: version struct and inline `getVersion` helper ## Quick Start @@ -54,10 +54,7 @@ Use the exported headers in your implementation: auto serialOpen( void *port, - int baudrate, - int data_bits, - int parity, - int stop_bits, + const cpp_core::SerialConfig *config, ErrorCallbackT error_callback ) -> intptr_t; ``` @@ -101,14 +98,28 @@ Example: ```cpp MODULE_API auto serialOpen( void *port, - int baudrate, - int data_bits, - int parity = 0, - int stop_bits = 0, + const cpp_core::SerialConfig *config, ErrorCallbackT error_callback = nullptr ) -> intptr_t; ``` +Line settings and per-operation timeout settings use explicit configuration +structures. `flow_mode` is applied as part of `serialOpen` together with the +other line settings: + +```cpp +constexpr auto serial_config = cpp_core::SerialConfig::make< + 115'200, + 8, + cpp_core::Parity::kNone, + cpp_core::StopBits::kOne, + cpp_core::FlowControl::kRtsCts>(); +constexpr auto timeout_config = cpp_core::SerialTimeoutConfig::make<50, 1>(); + +const auto handle = serialOpen(port, &serial_config); +const auto bytes_read = serialRead(handle, buffer, buffer_size, &timeout_config); +``` + This model keeps the ABI easy to consume from TypeScript hosts, Rust, Python, or other FFI hosts without requiring C++ runtime coupling. For C++ callers, the helper surface includes: @@ -116,7 +127,7 @@ For C++ callers, the helper surface includes: - `include/cpp_core/result.hpp`: `Result`, `Status`, `forwardUnexpected(...)`, plus the native `std::expected` monadic operations - `include/cpp_core/scope_guard.hpp`: `onScopeExit(...)`, `onScopeFail(...)`, `onScopeSuccess(...)`, `defer(...)` - `include/cpp_core/strong_types.hpp`: arithmetic-preserving strong integral wrappers and enum conversion helpers -- `include/cpp_core/serial_config.hpp`: typed config construction with `Result` validation helpers +- `include/cpp_core/serial_config.hpp`: typed line and timeout config construction with validation helpers - `include/cpp_core/reflection.hpp`: GCC 16 / C++26 reflection helpers such as enum/member counts and names, plus public field counts and names ## Versioning @@ -132,7 +143,7 @@ The version data is exposed through: - the `version` namespace in `include/cpp_core/version.hpp` - the `cpp_core::Version` struct -- the `getVersion(cpp_core::Version *out)` ABI function +- the inline `getVersion(cpp_core::Version *out)` helper ## Relationship to Platform Repositories diff --git a/include/cpp_core/interface/get_version.h b/include/cpp_core/interface/get_version.h index eee1893..b81433a 100644 --- a/include/cpp_core/interface/get_version.h +++ b/include/cpp_core/interface/get_version.h @@ -1,5 +1,4 @@ #pragma once -#include "../module_api.h" #include "../version.hpp" #ifdef __cplusplus @@ -31,7 +30,7 @@ extern "C" * @param[out] out Pointer to a `cpp_core::Version` structure that receives the version information. May be * `nullptr`. */ - inline MODULE_API void getVersion(cpp_core::Version *out) + inline void getVersion(cpp_core::Version *out) { if (out != nullptr) { diff --git a/include/cpp_core/interface/serial_drain.h b/include/cpp_core/interface/serial_drain.h index 16f3cf8..ca3dda6 100644 --- a/include/cpp_core/interface/serial_drain.h +++ b/include/cpp_core/interface/serial_drain.h @@ -19,9 +19,10 @@ extern "C" * Typical use-case: ensure a complete command frame has left the UART * before toggling RTS/DTR or powering down the device. * - * @code{.c} + * @code{.cpp} * // Send a frame and make sure it actually hits the line - * serialWrite(h, frame, frame_len, 50, 1); + * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 50, .multiplier = 1}; + * serialWrite(h, frame, frame_len, &timeout); * if (serialDrain(h) < 0) { * fprintf(stderr, "drain failed\n"); * } diff --git a/include/cpp_core/interface/serial_in_bytes_waiting.h b/include/cpp_core/interface/serial_in_bytes_waiting.h index 0db50e1..6049f2e 100644 --- a/include/cpp_core/interface/serial_in_bytes_waiting.h +++ b/include/cpp_core/interface/serial_in_bytes_waiting.h @@ -15,10 +15,11 @@ extern "C" * for data already consumed by the application. A value of `0` therefore * means a read call would have to wait for the next byte to arrive. * - * @code{.c} + * @code{.cpp} + * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 0, .multiplier = 1}; * int pending = serialInBytesWaiting(h); * if (pending > 0) { - * serialRead(h, buf, pending, 0, 1); // non-blocking read + * serialRead(h, buf, pending, &timeout); // non-blocking read * } * @endcode * diff --git a/include/cpp_core/interface/serial_open.h b/include/cpp_core/interface/serial_open.h index 46ec7ec..aba2b90 100644 --- a/include/cpp_core/interface/serial_open.h +++ b/include/cpp_core/interface/serial_open.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../serial_config.hpp" #include #ifdef __cplusplus @@ -12,19 +13,17 @@ extern "C" * @brief Open and configure a serial port. * * The function attempts to open the device referenced by @p port and applies - * the given line settings. The pointer is interpreted as + * the line settings in @p config. The @p port pointer is interpreted as * a UTF-8 encoded null-terminated string (`const char*`) on all platforms. * * @param port Null-terminated device identifier (e.g. "COM3", "/dev/ttyUSB0"). Passing `nullptr` results in * a failure. - * @param baudrate Desired baud rate in bit/s (>= 300). - * @param data_bits Number of data bits (5-8). - * @param parity 0 = none, 1 = even, 2 = odd. - * @param stop_bits 0 = 1 stop bit, 2 = 2 stop bits. + * @param config Serial line configuration. Includes baud rate, data bits, + * parity, stop bits, and flow-control mode. Passing `nullptr` results in a failure. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return A positive opaque handle on success or a negative value from ::cpp_core::StatusCode on failure. */ - MODULE_API auto serialOpen(void *port, int baudrate, int data_bits, int parity = 0, int stop_bits = 0, + MODULE_API auto serialOpen(void *port, const cpp_core::SerialConfig *config, ErrorCallbackT error_callback = nullptr) -> intptr_t; #ifdef __cplusplus diff --git a/include/cpp_core/interface/serial_read.h b/include/cpp_core/interface/serial_read.h index 4403316..9ff0451 100644 --- a/include/cpp_core/interface/serial_read.h +++ b/include/cpp_core/interface/serial_read.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../serial_config.hpp" #include #ifdef __cplusplus @@ -11,21 +12,19 @@ extern "C" /** * @brief Read raw bytes from the serial port. * - * The call blocks for at most @p timeout_ms milliseconds while waiting for + * The call blocks for at most `timeout_config->timeout_ms` milliseconds while waiting for * the FIRST byte. For every subsequent byte the individual timeout is - * calculated as `timeout_ms * multiplier`. + * calculated as `timeout_ms * multiplier` from @p timeout_config. * * @param handle Port handle. * @param buffer Destination buffer (must not be `nullptr`). * @param buffer_size Size of @p buffer in bytes (> 0). - * @param timeout_ms Base timeout per byte in milliseconds (applied to the first byte as-is; subsequent bytes use - * `timeout_ms * multiplier`). - * @param multiplier Factor applied to @p timeout_ms for every byte after the first. 0 -> return immediately after - * the first byte. + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialRead(int64_t handle, void *buffer, int buffer_size, int timeout_ms, int multiplier, + MODULE_API auto serialRead(int64_t handle, void *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus diff --git a/include/cpp_core/interface/serial_read_line.h b/include/cpp_core/interface/serial_read_line.h index 75a122c..efc2519 100644 --- a/include/cpp_core/interface/serial_read_line.h +++ b/include/cpp_core/interface/serial_read_line.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../serial_config.hpp" #include #ifdef __cplusplus @@ -17,13 +18,12 @@ extern "C" * @param handle Port handle. * @param buffer Destination buffer. * @param buffer_size Capacity of @p buffer in bytes. - * @param timeout_ms Base timeout per byte in milliseconds (applied to the first byte as-is; subsequent bytes use - * `timeout_ms * multiplier`). - * @param multiplier Factor applied to the timeout for subsequent bytes. + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialReadLine(int64_t handle, void *buffer, int buffer_size, int timeout_ms, int multiplier, + MODULE_API auto serialReadLine(int64_t handle, void *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus diff --git a/include/cpp_core/interface/serial_read_until.h b/include/cpp_core/interface/serial_read_until.h index 5876b2c..1f3069f 100644 --- a/include/cpp_core/interface/serial_read_until.h +++ b/include/cpp_core/interface/serial_read_until.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../serial_config.hpp" #include #ifdef __cplusplus @@ -18,16 +19,15 @@ extern "C" * @param handle Port handle. * @param buffer Destination buffer. * @param buffer_size Capacity of @p buffer in bytes. - * @param timeout_ms Base timeout per byte in milliseconds (applied to the first byte as-is; each additional byte - * uses `timeout_ms * multiplier`). - * @param multiplier Factor applied to the timeout for every additional byte. + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. * @param until_char Pointer to the terminator character (must not be `nullptr`). * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (including the terminator), 0 on timeout or a negative error code from ::cpp_core::StatusCode * on error. */ - MODULE_API auto serialReadUntil(int64_t handle, void *buffer, int buffer_size, int timeout_ms, int multiplier, - void *until_char, ErrorCallbackT error_callback = nullptr) -> int; + MODULE_API auto serialReadUntil(int64_t handle, void *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, void *until_char, + ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus } diff --git a/include/cpp_core/interface/serial_read_until_sequence.h b/include/cpp_core/interface/serial_read_until_sequence.h index f0ee7d7..bfbde0a 100644 --- a/include/cpp_core/interface/serial_read_until_sequence.h +++ b/include/cpp_core/interface/serial_read_until_sequence.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../serial_config.hpp" #include #ifdef __cplusplus @@ -17,16 +18,14 @@ extern "C" * @param handle Port handle. * @param buffer Destination buffer. * @param buffer_size Capacity of @p buffer in bytes. - * @param timeout_ms Base timeout per byte in milliseconds (first byte uses this value; each additional byte uses - * `timeout_ms * multiplier`). - * @param multiplier Factor applied to the timeout for subsequent bytes. + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. * @param sequence Pointer to the terminating byte sequence (must not be `nullptr`). * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (including the terminator) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialReadUntilSequence(int64_t handle, void *buffer, int buffer_size, int timeout_ms, - int multiplier, void *sequence, ErrorCallbackT error_callback = nullptr) - -> int; + MODULE_API auto serialReadUntilSequence(int64_t handle, void *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, void *sequence, + ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus } diff --git a/include/cpp_core/interface/serial_write.h b/include/cpp_core/interface/serial_write.h index be6734f..7cce89a 100644 --- a/include/cpp_core/interface/serial_write.h +++ b/include/cpp_core/interface/serial_write.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../serial_config.hpp" #include #ifdef __cplusplus @@ -11,19 +12,18 @@ extern "C" /** * @brief Write raw bytes to the serial port. * - * Timeout handling mirrors serialRead(): @p timeout_ms applies to the first - * byte, `timeout_ms * multiplier` to every subsequent one. + * Timeout handling mirrors serialRead(): `timeout_config->timeout_ms` applies + * to the first byte, `timeout_ms * multiplier` to every subsequent one. * * @param handle Port handle. * @param buffer Data to transmit (must not be `nullptr`). * @param buffer_size Number of bytes in @p buffer (> 0). - * @param timeout_ms Base timeout per byte in milliseconds (applied to the first byte as-is; subsequent bytes use - * `timeout_ms * multiplier`). - * @param multiplier Factor applied to the timeout for subsequent bytes. + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes written (may be 0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialWrite(int64_t handle, const void *buffer, int buffer_size, int timeout_ms, int multiplier, + MODULE_API auto serialWrite(int64_t handle, const void *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus diff --git a/include/cpp_core/reflection.test.cpp b/include/cpp_core/reflection.test.cpp index 1967f84..548f85c 100644 --- a/include/cpp_core/reflection.test.cpp +++ b/include/cpp_core/reflection.test.cpp @@ -19,8 +19,10 @@ static_assert(cpp_core::reflection::enumeratorName() == "kN static_assert(cpp_core::reflection::enumeratorName() == "kEven"); static_assert(cpp_core::reflection::enumerator_name_v == "kXonXoff"); static_assert(cpp_core::reflection::hasPubliclyReflectableFields()); -static_assert(cpp_core::reflection::publicFieldCount() == 4); +static_assert(cpp_core::reflection::publicFieldCount() == 5); static_assert(cpp_core::reflection::publicFieldName() == "parity"); +static_assert(cpp_core::reflection::publicFieldName() == "flow_mode"); +static_assert(cpp_core::reflection::publicFieldCount() == 2); static_assert(cpp_core::reflection::public_field_name_v == "message"); static_assert(cpp_core::reflection::public_field_count_v == 2); static_assert(!cpp_core::reflection::hasPubliclyReflectableFields()); diff --git a/include/cpp_core/serial.h b/include/cpp_core/serial.h index 6218a2e..11dc109 100644 --- a/include/cpp_core/serial.h +++ b/include/cpp_core/serial.h @@ -1,5 +1,7 @@ #pragma once +#include "serial_config.hpp" + // Aggregated interface headers #include "interface/get_version.h" #include "interface/serial_abort_read.h" diff --git a/include/cpp_core/serial_config.hpp b/include/cpp_core/serial_config.hpp index b695c9c..c5b4e8b 100644 --- a/include/cpp_core/serial_config.hpp +++ b/include/cpp_core/serial_config.hpp @@ -3,10 +3,11 @@ #include "result.hpp" #include "strong_types.hpp" -#include #include -#include +#include +#include #include +#include namespace cpp_core { @@ -36,42 +37,62 @@ constexpr auto validateStopBits(StopBits stop_bits) -> bool return stop_bits == StopBits::kOne || stop_bits == StopBits::kTwo; } +constexpr auto validateFlowControl(FlowControl flow_mode) -> bool +{ + return flow_mode == FlowControl::kNone || flow_mode == FlowControl::kRtsCts || flow_mode == FlowControl::kXonXoff; +} + +constexpr auto validateTimeout(int timeout_ms, int multiplier) -> bool +{ + return timeout_ms >= 0 && multiplier >= 0 && + (timeout_ms == 0 || multiplier <= std::numeric_limits::max() / timeout_ms); +} + } // namespace detail /** * Compile-time validated serial configuration. * Invalid configs are rejected at compile time - no runtime overhead. - * constexpr auto kCfg = SerialConfig::make<9600, 8, Parity::kNone, StopBits::kOne>(); + * constexpr auto kCfg = + * SerialConfig::make<9600, 8, Parity::kNone, StopBits::kOne, FlowControl::kNone>(); */ struct SerialConfig { - int baudrate; - int data_bits; - Parity parity; - StopBits stop_bits; + int baudrate; ///< Baud rate in bit/s (>= 300). + int data_bits; ///< Number of data bits (5-8). + Parity parity; ///< Parity mode. + StopBits stop_bits; ///< Stop-bit mode. + FlowControl flow_mode; ///< None, hardware RTS/CTS, or software XON/XOFF flow control. - template + template static consteval auto make() -> SerialConfig { static_assert(detail::validateBaudrate(Baud), "Baudrate must be >= 300"); static_assert(detail::validateDataBits(DataBitsVal), "DataBits must be 5-8"); + static_assert(detail::validateParity(P), "Parity must be none, even, or odd"); + static_assert(detail::validateStopBits(S), "StopBits must be one or two"); + static_assert(detail::validateFlowControl(F), "FlowControl must be none, RTS/CTS, or XON/XOFF"); return SerialConfig{ .baudrate = Baud, .data_bits = DataBitsVal, .parity = P, .stop_bits = S, + .flow_mode = F, }; } [[nodiscard]] static constexpr auto tryMake(Baudrate baud, DataBits data_bits, Parity parity = Parity::kNone, - StopBits stop_bits = StopBits::kOne) -> Result + StopBits stop_bits = StopBits::kOne, + FlowControl flow_mode = FlowControl::kNone) -> Result { - return tryMake(baud.get(), data_bits.get(), parity, stop_bits); + return tryMake(baud.get(), data_bits.get(), parity, stop_bits, flow_mode); } [[nodiscard]] static constexpr auto tryMake(int baud, int data_bits_val, Parity parity = Parity::kNone, - StopBits stop_bits = StopBits::kOne) -> Result + StopBits stop_bits = StopBits::kOne, + FlowControl flow_mode = FlowControl::kNone) -> Result { if (!detail::validateBaudrate(baud)) { @@ -89,18 +110,24 @@ struct SerialConfig { return fail(StatusCode::Configuration::kSetStopBitsError); } + if (!detail::validateFlowControl(flow_mode)) + { + return fail(StatusCode::Configuration::kSetFlowControlError); + } return ok(SerialConfig{ .baudrate = baud, .data_bits = data_bits_val, .parity = parity, .stop_bits = stop_bits, + .flow_mode = flow_mode, }); } [[nodiscard]] constexpr auto isValid() const noexcept -> bool { - return detail::validateBaudrate(baudrate) && detail::validateDataBits(data_bits) - && detail::validateParity(parity) && detail::validateStopBits(stop_bits); + return detail::validateBaudrate(baudrate) && detail::validateDataBits(data_bits) && + detail::validateParity(parity) && detail::validateStopBits(stop_bits) && + detail::validateFlowControl(flow_mode); } [[nodiscard]] constexpr auto baudrateValue() const noexcept -> Baudrate @@ -123,19 +150,95 @@ struct SerialConfig return toInt(stop_bits); } + [[nodiscard]] constexpr auto flowModeInt() const noexcept -> int + { + return toInt(flow_mode); + } + [[nodiscard]] constexpr auto withBaudrate(Baudrate baud) const -> Result { - return tryMake(baud, dataBitsValue(), parity, stop_bits); + return tryMake(baud, dataBitsValue(), parity, stop_bits, flow_mode); } [[nodiscard]] constexpr auto withDataBits(DataBits bits) const -> Result { - return tryMake(baudrateValue(), bits, parity, stop_bits); + return tryMake(baudrateValue(), bits, parity, stop_bits, flow_mode); + } + + [[nodiscard]] constexpr auto withParity(Parity new_parity) const -> Result + { + return tryMake(baudrateValue(), dataBitsValue(), new_parity, stop_bits, flow_mode); + } + + [[nodiscard]] constexpr auto withStopBits(StopBits new_stop_bits) const -> Result + { + return tryMake(baudrateValue(), dataBitsValue(), parity, new_stop_bits, flow_mode); + } + + [[nodiscard]] constexpr auto withFlowMode(FlowControl new_flow_mode) const -> Result + { + return tryMake(baudrateValue(), dataBitsValue(), parity, stop_bits, new_flow_mode); } [[nodiscard]] constexpr auto operator<=>(const SerialConfig &) const noexcept = default; }; +/** + * Timeout configuration shared by serial read and write operations. + * The base timeout applies to the first byte; subsequent bytes use + * `timeout_ms * multiplier`. + */ +struct SerialTimeoutConfig +{ + int timeout_ms; ///< Base timeout per byte in milliseconds. + int multiplier; ///< Factor applied to the timeout after the first byte. + + template static consteval auto make() -> SerialTimeoutConfig + { + static_assert(detail::validateTimeout(TimeoutMsVal, MultiplierVal), + "Timeout and multiplier must be non-negative and their product must fit into int"); + return SerialTimeoutConfig{ + .timeout_ms = TimeoutMsVal, + .multiplier = MultiplierVal, + }; + } + + [[nodiscard]] static constexpr auto tryMake(TimeoutMs timeout, Multiplier timeout_multiplier) + -> Result + { + return tryMake(timeout.get(), timeout_multiplier.get()); + } + + [[nodiscard]] static constexpr auto tryMake(int timeout, int timeout_multiplier) -> Result + { + if (!detail::validateTimeout(timeout, timeout_multiplier)) + { + return fail(StatusCode::Configuration::kSetTimeoutError); + } + return ok(SerialTimeoutConfig{ + .timeout_ms = timeout, + .multiplier = timeout_multiplier, + }); + } + + [[nodiscard]] constexpr auto isValid() const noexcept -> bool + { + return detail::validateTimeout(timeout_ms, multiplier); + } + + [[nodiscard]] constexpr auto timeoutValue() const noexcept -> TimeoutMs + { + return TimeoutMs{timeout_ms}; + } + + [[nodiscard]] constexpr auto multiplierValue() const noexcept -> Multiplier + { + return Multiplier{multiplier}; + } + + [[nodiscard]] constexpr auto operator<=>(const SerialTimeoutConfig &) const noexcept = default; +}; + // Concepts for serial port operations // clang-format off diff --git a/include/cpp_core/serial_config.test.cpp b/include/cpp_core/serial_config.test.cpp index fe86b4d..313ff20 100644 --- a/include/cpp_core/serial_config.test.cpp +++ b/include/cpp_core/serial_config.test.cpp @@ -1,20 +1,24 @@ -#include "cpp_core/reflection.hpp" #include "cpp_core/serial_config.hpp" +#include "cpp_core/reflection.hpp" namespace cpp_core::tests::serial_config { -constexpr auto kCompileTimeConfig = SerialConfig::make<115'200, 8, Parity::kEven, StopBits::kTwo>(); +constexpr auto kCompileTimeConfig = + SerialConfig::make<115'200, 8, Parity::kEven, StopBits::kTwo, FlowControl::kRtsCts>(); static_assert(kCompileTimeConfig.isValid()); static_assert(kCompileTimeConfig.baudrateValue() == Baudrate{115'200}); static_assert(kCompileTimeConfig.dataBitsValue() == DataBits{8}); static_assert(kCompileTimeConfig.parityInt() == 1); static_assert(kCompileTimeConfig.stopBitsInt() == 2); +static_assert(kCompileTimeConfig.flowModeInt() == 1); -constexpr auto kRuntimeLikeConfig = SerialConfig::tryMake(Baudrate{57'600}, DataBits{7}, Parity::kOdd, StopBits::kOne); +constexpr auto kRuntimeLikeConfig = + SerialConfig::tryMake(Baudrate{57'600}, DataBits{7}, Parity::kOdd, StopBits::kOne, FlowControl::kXonXoff); static_assert(kRuntimeLikeConfig.has_value()); static_assert(kRuntimeLikeConfig->baudrateValue() == Baudrate{57'600}); static_assert(kRuntimeLikeConfig->dataBitsValue() == DataBits{7}); +static_assert(kRuntimeLikeConfig->flow_mode == FlowControl::kXonXoff); consteval auto rejectsBadBaudrate() -> bool { @@ -31,15 +35,39 @@ consteval auto rejectsBadParity() -> bool return !SerialConfig::tryMake(9'600, 8, static_cast(77)).has_value(); } +consteval auto rejectsBadFlowMode() -> bool +{ + return !SerialConfig::tryMake(9'600, 8, Parity::kNone, StopBits::kOne, static_cast(77)).has_value(); +} + static_assert(rejectsBadBaudrate()); static_assert(rejectsBadDataBits()); static_assert(rejectsBadParity()); +static_assert(rejectsBadFlowMode()); constexpr auto kRetunedConfig = kCompileTimeConfig.withBaudrate(Baudrate{230'400}); static_assert(kRetunedConfig.has_value()); static_assert(kRetunedConfig->baudrateValue() == Baudrate{230'400}); +constexpr auto kFlowModeConfig = kCompileTimeConfig.withFlowMode(FlowControl::kXonXoff); +static_assert(kFlowModeConfig.has_value()); +static_assert(kFlowModeConfig->flow_mode == FlowControl::kXonXoff); + +constexpr auto kTimeoutConfig = SerialTimeoutConfig::make<50, 2>(); +static_assert(kTimeoutConfig.isValid()); +static_assert(kTimeoutConfig.timeoutValue() == TimeoutMs{50}); +static_assert(kTimeoutConfig.multiplierValue() == Multiplier{2}); + +constexpr auto kRuntimeTimeoutConfig = SerialTimeoutConfig::tryMake(TimeoutMs{100}, Multiplier{3}); +static_assert(kRuntimeTimeoutConfig.has_value()); +static_assert(kRuntimeTimeoutConfig->timeout_ms == 100); + +static_assert(!SerialTimeoutConfig::tryMake(-1, 1).has_value()); +static_assert(!SerialTimeoutConfig::tryMake(1'000'000'000, 3).has_value()); + static_assert(cpp_core::reflection::publicFieldName() == "baudrate"); static_assert(cpp_core::reflection::publicFieldName() == "data_bits"); +static_assert(cpp_core::reflection::publicFieldName() == "flow_mode"); +static_assert(cpp_core::reflection::publicFieldName() == "timeout_ms"); } // namespace cpp_core::tests::serial_config diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp new file mode 100644 index 0000000..f8f6732 --- /dev/null +++ b/include/cpp_core/serial_interface.test.cpp @@ -0,0 +1,39 @@ +#include "cpp_core/serial.h" +#include "cpp_core/serial_config.hpp" +#include "cpp_core/validation.hpp" + +#include +#include + +namespace cpp_core::tests::serial_interface +{ + +using OpenFn = intptr_t (*)(void *, const SerialConfig *, ErrorCallbackT); +using ReadFn = int (*)(int64_t, void *, int, const SerialTimeoutConfig *, ErrorCallbackT); +using ReadUntilFn = int (*)(int64_t, void *, int, const SerialTimeoutConfig *, void *, ErrorCallbackT); +using WriteFn = int (*)(int64_t, const void *, int, const SerialTimeoutConfig *, ErrorCallbackT); + +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); + +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); +static_assert(sizeof(SerialConfig) == 5 * sizeof(int)); +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); +static_assert(sizeof(SerialTimeoutConfig) == 2 * sizeof(int)); + +inline int portMarker; +constexpr auto kSerialConfig = SerialConfig::make<115'200, 8>(); +constexpr auto kTimeoutConfig = SerialTimeoutConfig::make<50, 1>(); + +static_assert(validateOpenParams(&portMarker, &kSerialConfig, nullptr) == StatusCode::kSuccess); +static_assert(validateOpenParams(&portMarker, nullptr, nullptr) == StatusCode::Control::kSetStateError); +static_assert(validateTimeoutConfig(&kTimeoutConfig, nullptr) == StatusCode::kSuccess); +static_assert(validateTimeoutConfig(nullptr, nullptr) == StatusCode::Configuration::kSetTimeoutError); + +} // namespace cpp_core::tests::serial_interface diff --git a/include/cpp_core/validation.hpp b/include/cpp_core/validation.hpp index 2ff5c80..6b10cd8 100644 --- a/include/cpp_core/validation.hpp +++ b/include/cpp_core/validation.hpp @@ -1,6 +1,7 @@ #pragma once #include "error_handling.hpp" +#include "serial_config.hpp" #include "status_code.h" #include @@ -31,7 +32,7 @@ constexpr auto validateHandle(int64_t handle, Callback &&error_callback) -> Ret * Returns kSuccess (0) if all params are valid, or the appropriate negative error code. */ template -constexpr auto validateOpenParams(void *port, int baudrate, int data_bits, Callback &&error_callback) -> Ret +constexpr auto validateOpenParams(void *port, const SerialConfig *config, Callback &&error_callback) -> Ret { if (port == nullptr) { @@ -39,18 +40,63 @@ constexpr auto validateOpenParams(void *port, int baudrate, int data_bits, Callb static_cast(StatusCode::Connection::kNotFoundError), "Port parameter is nullptr"); } - if (baudrate < 300) + if (config == nullptr) { return failMsg(std::forward(error_callback), static_cast(StatusCode::Control::kSetStateError), + "Config parameter is nullptr"); + } + if (!detail::validateBaudrate(config->baudrate)) + { + return failMsg(std::forward(error_callback), + static_cast(StatusCode::Configuration::kSetBaudrateError), "Invalid baudrate: must be >= 300"); } - if (data_bits < 5 || data_bits > 8) + if (!detail::validateDataBits(config->data_bits)) { return failMsg(std::forward(error_callback), - static_cast(StatusCode::Control::kSetStateError), + static_cast(StatusCode::Configuration::kSetDataBitsError), "Invalid data bits: must be 5-8"); } + if (!detail::validateParity(config->parity)) + { + return failMsg(std::forward(error_callback), + static_cast(StatusCode::Configuration::kSetParityError), + "Invalid parity mode"); + } + if (!detail::validateStopBits(config->stop_bits)) + { + return failMsg(std::forward(error_callback), + static_cast(StatusCode::Configuration::kSetStopBitsError), + "Invalid stop bits mode"); + } + if (!detail::validateFlowControl(config->flow_mode)) + { + return failMsg(std::forward(error_callback), + static_cast(StatusCode::Configuration::kSetFlowControlError), + "Invalid flow-control mode"); + } + return static_cast(StatusCode::kSuccess); +} + +/** + * Shared timeout validation for serial read and write operations. + */ +template +constexpr auto validateTimeoutConfig(const SerialTimeoutConfig *config, Callback &&error_callback) -> Ret +{ + if (config == nullptr) + { + return failMsg(std::forward(error_callback), + static_cast(StatusCode::Configuration::kSetTimeoutError), + "Timeout config parameter is nullptr"); + } + if (!config->isValid()) + { + return failMsg(std::forward(error_callback), + static_cast(StatusCode::Configuration::kSetTimeoutError), + "Timeout and multiplier must be non-negative and their product must fit into int"); + } return static_cast(StatusCode::kSuccess); } From b394de538610b19455dc80acc9d060c645585c1b Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 10:24:16 +0200 Subject: [PATCH 02/14] feat: update serial interface to use const char* and std::uint8_t for port and buffer types --- README.md | 4 +-- include/cpp_core/interface/serial_open.h | 6 ++--- include/cpp_core/interface/serial_read.h | 2 +- include/cpp_core/interface/serial_read_line.h | 2 +- .../cpp_core/interface/serial_read_until.h | 10 ++++---- .../interface/serial_read_until_sequence.h | 11 +++++--- include/cpp_core/interface/serial_write.h | 2 +- include/cpp_core/serial_config.hpp | 5 ++-- include/cpp_core/serial_interface.test.cpp | 25 +++++++++++++------ include/cpp_core/validation.hpp | 4 +-- 10 files changed, 42 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 86ab29c..9bbf302 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Use the exported headers in your implementation: #include auto serialOpen( - void *port, + const char *port, const cpp_core::SerialConfig *config, ErrorCallbackT error_callback ) -> intptr_t; @@ -97,7 +97,7 @@ Example: ```cpp MODULE_API auto serialOpen( - void *port, + const char *port, const cpp_core::SerialConfig *config, ErrorCallbackT error_callback = nullptr ) -> intptr_t; diff --git a/include/cpp_core/interface/serial_open.h b/include/cpp_core/interface/serial_open.h index aba2b90..1746c4b 100644 --- a/include/cpp_core/interface/serial_open.h +++ b/include/cpp_core/interface/serial_open.h @@ -13,8 +13,8 @@ extern "C" * @brief Open and configure a serial port. * * The function attempts to open the device referenced by @p port and applies - * the line settings in @p config. The @p port pointer is interpreted as - * a UTF-8 encoded null-terminated string (`const char*`) on all platforms. + * the line settings in @p config. @p port is interpreted as a UTF-8 encoded + * null-terminated string on all platforms. * * @param port Null-terminated device identifier (e.g. "COM3", "/dev/ttyUSB0"). Passing `nullptr` results in * a failure. @@ -23,7 +23,7 @@ extern "C" * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return A positive opaque handle on success or a negative value from ::cpp_core::StatusCode on failure. */ - MODULE_API auto serialOpen(void *port, const cpp_core::SerialConfig *config, + MODULE_API auto serialOpen(const char *port, const cpp_core::SerialConfig *config, ErrorCallbackT error_callback = nullptr) -> intptr_t; #ifdef __cplusplus diff --git a/include/cpp_core/interface/serial_read.h b/include/cpp_core/interface/serial_read.h index 9ff0451..1605eec 100644 --- a/include/cpp_core/interface/serial_read.h +++ b/include/cpp_core/interface/serial_read.h @@ -23,7 +23,7 @@ extern "C" * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialRead(int64_t handle, void *buffer, int buffer_size, + MODULE_API auto serialRead(int64_t handle, std::uint8_t *buffer, int buffer_size, const cpp_core::SerialTimeoutConfig *timeout_config, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_read_line.h b/include/cpp_core/interface/serial_read_line.h index efc2519..c83f80e 100644 --- a/include/cpp_core/interface/serial_read_line.h +++ b/include/cpp_core/interface/serial_read_line.h @@ -22,7 +22,7 @@ extern "C" * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialReadLine(int64_t handle, void *buffer, int buffer_size, + MODULE_API auto serialReadLine(int64_t handle, std::uint8_t *buffer, int buffer_size, const cpp_core::SerialTimeoutConfig *timeout_config, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_read_until.h b/include/cpp_core/interface/serial_read_until.h index 1f3069f..148a2ad 100644 --- a/include/cpp_core/interface/serial_read_until.h +++ b/include/cpp_core/interface/serial_read_until.h @@ -10,23 +10,23 @@ extern "C" #endif /** - * @brief Read bytes until a terminator character appears. + * @brief Read bytes until a terminator byte appears. * * Semantics are identical to serialRead() but reading stops as soon as the - * byte pointed to by @p until_char has been received. The terminator is part + * byte supplied as @p until_byte has been received. The terminator is part * of the returned data. * * @param handle Port handle. * @param buffer Destination buffer. * @param buffer_size Capacity of @p buffer in bytes. * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. - * @param until_char Pointer to the terminator character (must not be `nullptr`). + * @param until_byte Terminator byte. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (including the terminator), 0 on timeout or a negative error code from ::cpp_core::StatusCode * on error. */ - MODULE_API auto serialReadUntil(int64_t handle, void *buffer, int buffer_size, - const cpp_core::SerialTimeoutConfig *timeout_config, void *until_char, + MODULE_API auto serialReadUntil(int64_t handle, std::uint8_t *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, std::uint8_t until_byte, ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus diff --git a/include/cpp_core/interface/serial_read_until_sequence.h b/include/cpp_core/interface/serial_read_until_sequence.h index bfbde0a..218ef76 100644 --- a/include/cpp_core/interface/serial_read_until_sequence.h +++ b/include/cpp_core/interface/serial_read_until_sequence.h @@ -12,19 +12,22 @@ extern "C" /** * @brief Read until a specific byte sequence appears. * - * Works like serialReadUntil() but supports an arbitrary terminator string. + * Works like serialReadUntil() but supports an arbitrary byte sequence, + * including sequences containing zero bytes. * The terminator is included in the returned data. * * @param handle Port handle. * @param buffer Destination buffer. * @param buffer_size Capacity of @p buffer in bytes. * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. - * @param sequence Pointer to the terminating byte sequence (must not be `nullptr`). + * @param sequence Terminating byte sequence (must not be `nullptr`). + * @param sequence_size Size of @p sequence in bytes (> 0). * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes read (including the terminator) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialReadUntilSequence(int64_t handle, void *buffer, int buffer_size, - const cpp_core::SerialTimeoutConfig *timeout_config, void *sequence, + MODULE_API auto serialReadUntilSequence(int64_t handle, std::uint8_t *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, + const std::uint8_t *sequence, int sequence_size, ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus diff --git a/include/cpp_core/interface/serial_write.h b/include/cpp_core/interface/serial_write.h index 7cce89a..acca526 100644 --- a/include/cpp_core/interface/serial_write.h +++ b/include/cpp_core/interface/serial_write.h @@ -22,7 +22,7 @@ extern "C" * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return Bytes written (may be 0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialWrite(int64_t handle, const void *buffer, int buffer_size, + MODULE_API auto serialWrite(int64_t handle, const std::uint8_t *buffer, int buffer_size, const cpp_core::SerialTimeoutConfig *timeout_config, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/serial_config.hpp b/include/cpp_core/serial_config.hpp index c5b4e8b..d10ba9d 100644 --- a/include/cpp_core/serial_config.hpp +++ b/include/cpp_core/serial_config.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -251,14 +252,14 @@ concept NativeHandle = (std::is_integral_v || std::is_pointer_v) // A type that can serve as a mutable byte buffer for read operations. template concept ByteBuffer = requires(B buf) { - { buf.data() } -> std::convertible_to; + { buf.data() } -> std::convertible_to; { buf.size() } -> std::convertible_to; }; // Read-only byte source for write operations. template concept ConstByteBuffer = requires(const B buf) { - { buf.data() } -> std::convertible_to; + { buf.data() } -> std::convertible_to; { buf.size() } -> std::convertible_to; }; diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index f8f6732..e8bb5b3 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -2,22 +2,25 @@ #include "cpp_core/serial_config.hpp" #include "cpp_core/validation.hpp" +#include #include #include namespace cpp_core::tests::serial_interface { -using OpenFn = intptr_t (*)(void *, const SerialConfig *, ErrorCallbackT); -using ReadFn = int (*)(int64_t, void *, int, const SerialTimeoutConfig *, ErrorCallbackT); -using ReadUntilFn = int (*)(int64_t, void *, int, const SerialTimeoutConfig *, void *, ErrorCallbackT); -using WriteFn = int (*)(int64_t, const void *, int, const SerialTimeoutConfig *, ErrorCallbackT); +using OpenFn = intptr_t (*)(const char *, const SerialConfig *, ErrorCallbackT); +using ReadFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); +using ReadUntilFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, std::uint8_t, ErrorCallbackT); +using ReadUntilSequenceFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, const std::uint8_t *, + int, ErrorCallbackT); +using WriteFn = int (*)(int64_t, const std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); -static_assert(std::is_same_v); +static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_standard_layout_v); @@ -26,14 +29,20 @@ static_assert(sizeof(SerialConfig) == 5 * sizeof(int)); static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); static_assert(sizeof(SerialTimeoutConfig) == 2 * sizeof(int)); +static_assert(ByteBuffer>); +static_assert(ConstByteBuffer>); +static_assert(!ByteBuffer>); +static_assert(!ConstByteBuffer>); -inline int portMarker; +inline constexpr char kPort[] = "/dev/ttyUSB0"; constexpr auto kSerialConfig = SerialConfig::make<115'200, 8>(); constexpr auto kTimeoutConfig = SerialTimeoutConfig::make<50, 1>(); +inline constexpr std::uint8_t kByte{}; -static_assert(validateOpenParams(&portMarker, &kSerialConfig, nullptr) == StatusCode::kSuccess); -static_assert(validateOpenParams(&portMarker, nullptr, nullptr) == StatusCode::Control::kSetStateError); +static_assert(validateOpenParams(kPort, &kSerialConfig, nullptr) == StatusCode::kSuccess); +static_assert(validateOpenParams(kPort, nullptr, nullptr) == StatusCode::Control::kSetStateError); static_assert(validateTimeoutConfig(&kTimeoutConfig, nullptr) == StatusCode::kSuccess); static_assert(validateTimeoutConfig(nullptr, nullptr) == StatusCode::Configuration::kSetTimeoutError); +static_assert(validateBuffer(&kByte, 1, nullptr) == StatusCode::kSuccess); } // namespace cpp_core::tests::serial_interface diff --git a/include/cpp_core/validation.hpp b/include/cpp_core/validation.hpp index 6b10cd8..81f4aad 100644 --- a/include/cpp_core/validation.hpp +++ b/include/cpp_core/validation.hpp @@ -32,7 +32,7 @@ constexpr auto validateHandle(int64_t handle, Callback &&error_callback) -> Ret * Returns kSuccess (0) if all params are valid, or the appropriate negative error code. */ template -constexpr auto validateOpenParams(void *port, const SerialConfig *config, Callback &&error_callback) -> Ret +constexpr auto validateOpenParams(const char *port, const SerialConfig *config, Callback &&error_callback) -> Ret { if (port == nullptr) { @@ -102,7 +102,7 @@ constexpr auto validateTimeoutConfig(const SerialTimeoutConfig *config, Callback // Validate buffer + size for read/write calls. template -constexpr auto validateBuffer(const void *buffer, int buffer_size, Callback &&error_callback) -> Ret +constexpr auto validateBuffer(const std::uint8_t *buffer, int buffer_size, Callback &&error_callback) -> Ret { if (buffer == nullptr || buffer_size <= 0) { From 413041a4823c5ed997ae8c3cef634bfb6d0b4fee Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 10:27:26 +0200 Subject: [PATCH 03/14] feat: remove deprecated serial read functions and update tests --- include/cpp_core/interface/serial_read_line.h | 31 ----------------- .../cpp_core/interface/serial_read_until.h | 34 ------------------- .../interface/serial_read_until_sequence.h | 6 ++-- include/cpp_core/serial.h | 2 -- include/cpp_core/serial_interface.test.cpp | 3 -- 5 files changed, 3 insertions(+), 73 deletions(-) delete mode 100644 include/cpp_core/interface/serial_read_line.h delete mode 100644 include/cpp_core/interface/serial_read_until.h diff --git a/include/cpp_core/interface/serial_read_line.h b/include/cpp_core/interface/serial_read_line.h deleted file mode 100644 index c83f80e..0000000 --- a/include/cpp_core/interface/serial_read_line.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "../error_callback.h" -#include "../module_api.h" -#include "../serial_config.hpp" -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read a single line terminated by '\n'. - * - * Timeout handling is identical to serialRead(); the newline character is - * included in the returned data. - * - * @param handle Port handle. - * @param buffer Destination buffer. - * @param buffer_size Capacity of @p buffer in bytes. - * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Bytes read (0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialReadLine(int64_t handle, std::uint8_t *buffer, int buffer_size, - const cpp_core::SerialTimeoutConfig *timeout_config, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif diff --git a/include/cpp_core/interface/serial_read_until.h b/include/cpp_core/interface/serial_read_until.h deleted file mode 100644 index 148a2ad..0000000 --- a/include/cpp_core/interface/serial_read_until.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "../error_callback.h" -#include "../module_api.h" -#include "../serial_config.hpp" -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read bytes until a terminator byte appears. - * - * Semantics are identical to serialRead() but reading stops as soon as the - * byte supplied as @p until_byte has been received. The terminator is part - * of the returned data. - * - * @param handle Port handle. - * @param buffer Destination buffer. - * @param buffer_size Capacity of @p buffer in bytes. - * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. - * @param until_byte Terminator byte. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Bytes read (including the terminator), 0 on timeout or a negative error code from ::cpp_core::StatusCode - * on error. - */ - MODULE_API auto serialReadUntil(int64_t handle, std::uint8_t *buffer, int buffer_size, - const cpp_core::SerialTimeoutConfig *timeout_config, std::uint8_t until_byte, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif diff --git a/include/cpp_core/interface/serial_read_until_sequence.h b/include/cpp_core/interface/serial_read_until_sequence.h index 218ef76..4dd85c4 100644 --- a/include/cpp_core/interface/serial_read_until_sequence.h +++ b/include/cpp_core/interface/serial_read_until_sequence.h @@ -12,9 +12,9 @@ extern "C" /** * @brief Read until a specific byte sequence appears. * - * Works like serialReadUntil() but supports an arbitrary byte sequence, - * including sequences containing zero bytes. - * The terminator is included in the returned data. + * Reads bytes using the same timeout semantics as serialRead() and stops as + * soon as @p sequence has been received. Sequences may contain zero bytes, + * and the complete terminator is included in the returned data. * * @param handle Port handle. * @param buffer Destination buffer. diff --git a/include/cpp_core/serial.h b/include/cpp_core/serial.h index 11dc109..f01bde7 100644 --- a/include/cpp_core/serial.h +++ b/include/cpp_core/serial.h @@ -18,8 +18,6 @@ #include "interface/serial_out_bytes_total.h" #include "interface/serial_out_bytes_waiting.h" #include "interface/serial_read.h" -#include "interface/serial_read_line.h" -#include "interface/serial_read_until.h" #include "interface/serial_read_until_sequence.h" #include "interface/serial_set_error_callback.h" #include "interface/serial_set_read_callback.h" diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index e8bb5b3..ee67b84 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -11,15 +11,12 @@ namespace cpp_core::tests::serial_interface using OpenFn = intptr_t (*)(const char *, const SerialConfig *, ErrorCallbackT); using ReadFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); -using ReadUntilFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, std::uint8_t, ErrorCallbackT); using ReadUntilSequenceFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, const std::uint8_t *, int, ErrorCallbackT); using WriteFn = int (*)(int64_t, const std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); static_assert(std::is_same_v); static_assert(std::is_same_v); -static_assert(std::is_same_v); -static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); From 952a07dcdb7d2997c86f745551043394489f97f7 Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 10:32:04 +0200 Subject: [PATCH 04/14] feat: replace get_version interface with meta for library metadata retrieval --- README.md | 14 +++--- include/cpp_core/interface/get_version.h | 43 ------------------- include/cpp_core/interface/meta.h | 50 ++++++++++++++++++++++ include/cpp_core/reflection.test.cpp | 6 +++ include/cpp_core/serial.h | 2 +- include/cpp_core/serial_interface.test.cpp | 7 +++ 6 files changed, 71 insertions(+), 51 deletions(-) delete mode 100644 include/cpp_core/interface/get_version.h create mode 100644 include/cpp_core/interface/meta.h diff --git a/README.md b/README.md index 9bbf302..3ba06df 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This repository does not provide a ready-to-load shared library by itself. It pr - `include/cpp_core/serial.h`: aggregated C ABI for serial operations - `include/cpp_core/status_code.h`: shared status-code model -- `include/cpp_core/interface/get_version.h`: version struct and inline `getVersion` helper +- `include/cpp_core/interface/meta.h`: metadata struct and exported `meta` function ## Quick Start @@ -50,7 +50,7 @@ Use the exported headers in your implementation: ```cpp #include -#include +#include auto serialOpen( const char *port, @@ -62,10 +62,10 @@ auto serialOpen( Read the version data baked into the checkout: ```cpp -#include +#include -cpp_core::Version version{}; -getVersion(&version); +cpp_core::Meta metadata{}; +meta(&metadata); ``` ## Building This Repository @@ -142,8 +142,8 @@ Version information is generated from Git during CMake configure and written int The version data is exposed through: - the `version` namespace in `include/cpp_core/version.hpp` -- the `cpp_core::Version` struct -- the inline `getVersion(cpp_core::Version *out)` helper +- the `cpp_core::Meta` struct +- the exported `meta(cpp_core::Meta *out)` ABI function ## Relationship to Platform Repositories diff --git a/include/cpp_core/interface/get_version.h b/include/cpp_core/interface/get_version.h deleted file mode 100644 index b81433a..0000000 --- a/include/cpp_core/interface/get_version.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include "../version.hpp" - -#ifdef __cplusplus -extern "C" -{ -#endif - - namespace cpp_core - { - struct Version - { - int major = version::MAJOR; - int minor = version::MINOR; - int patch = version::PATCH; - const char *commit_hash_short = version::GIT_COMMIT_HASH_SHORT; - const char *commit_hash_full = version::GIT_COMMIT_HASH_FULL; - const char *commit_date = version::GIT_COMMIT_DATE; - const char *branch = version::GIT_BRANCH; - const char *version_string = version::VERSION; - }; - } // namespace cpp_core - - /** - * @brief Copy the compile-time version of the cpp_core library. - * - * Writes the version baked into the library at build-time to the structure - * pointed to by @p out. If @p out is `nullptr` the call is a no-op. - * - * @param[out] out Pointer to a `cpp_core::Version` structure that receives the version information. May be - * `nullptr`. - */ - inline void getVersion(cpp_core::Version *out) - { - if (out != nullptr) - { - *out = cpp_core::Version(); - } - } - -#ifdef __cplusplus -} -#endif diff --git a/include/cpp_core/interface/meta.h b/include/cpp_core/interface/meta.h new file mode 100644 index 0000000..d513d30 --- /dev/null +++ b/include/cpp_core/interface/meta.h @@ -0,0 +1,50 @@ +#pragma once +#include "../module_api.h" +#include "../version.hpp" + +#ifdef __cplusplus +extern "C" +{ +#endif + + namespace cpp_core + { + /** + * Build and source metadata for the loaded cpp_core-based library. + */ + struct Meta + { + int major = version::MAJOR; + int minor = version::MINOR; + int patch = version::PATCH; + int commits_since_tag = version::GIT_COMMIT_COUNT; + int is_dirty = version::GIT_IS_DIRTY ? 1 : 0; + + const char *library_name = "cpp-core"; + const char *version_string = version::VERSION; + const char *version_string_no_v = version::VERSION_NO_V; + const char *prerelease = version::PRERELEASE; + const char *prerelease_type = version::PRERELEASE_TYPE; + const char *prerelease_number = version::PRERELEASE_NUMBER; + + const char *git_tag = version::GIT_TAG; + const char *git_tag_no_v = version::GIT_TAG_NO_V; + const char *git_describe_hash = version::GIT_DESCRIBE_HASH; + const char *git_commit_hash_short = version::GIT_COMMIT_HASH_SHORT; + const char *git_commit_hash_full = version::GIT_COMMIT_HASH_FULL; + const char *git_commit_date = version::GIT_COMMIT_DATE; + const char *git_branch = version::GIT_BRANCH; + const char *git_dirty_suffix = version::GIT_DIRTY_SUFFIX; + }; + } // namespace cpp_core + + /** + * @brief Copy metadata for the loaded library. + * + * @param[out] out Structure receiving the metadata. Passing `nullptr` is a no-op. + */ + MODULE_API void meta(cpp_core::Meta *out); + +#ifdef __cplusplus +} +#endif diff --git a/include/cpp_core/reflection.test.cpp b/include/cpp_core/reflection.test.cpp index 548f85c..65fecc6 100644 --- a/include/cpp_core/reflection.test.cpp +++ b/include/cpp_core/reflection.test.cpp @@ -1,4 +1,5 @@ #include "cpp_core/reflection.hpp" +#include "cpp_core/interface/meta.h" #include "cpp_core/result.hpp" #include "cpp_core/serial_config.hpp" #include "cpp_core/strong_types.hpp" @@ -23,6 +24,11 @@ static_assert(cpp_core::reflection::publicFieldCount() = static_assert(cpp_core::reflection::publicFieldName() == "parity"); static_assert(cpp_core::reflection::publicFieldName() == "flow_mode"); static_assert(cpp_core::reflection::publicFieldCount() == 2); +static_assert(cpp_core::reflection::hasPubliclyReflectableFields()); +static_assert(cpp_core::reflection::publicFieldCount() == 19); +static_assert(cpp_core::reflection::publicFieldName() == "major"); +static_assert(cpp_core::reflection::publicFieldName() == "library_name"); +static_assert(cpp_core::reflection::publicFieldName() == "git_dirty_suffix"); static_assert(cpp_core::reflection::public_field_name_v == "message"); static_assert(cpp_core::reflection::public_field_count_v == 2); static_assert(!cpp_core::reflection::hasPubliclyReflectableFields()); diff --git a/include/cpp_core/serial.h b/include/cpp_core/serial.h index f01bde7..7862b1b 100644 --- a/include/cpp_core/serial.h +++ b/include/cpp_core/serial.h @@ -3,7 +3,7 @@ #include "serial_config.hpp" // Aggregated interface headers -#include "interface/get_version.h" +#include "interface/meta.h" #include "interface/serial_abort_read.h" #include "interface/serial_abort_write.h" #include "interface/serial_clear_buffer_in.h" diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index ee67b84..44d2635 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -9,17 +9,24 @@ namespace cpp_core::tests::serial_interface { +using MetaFn = void (*)(Meta *); using OpenFn = intptr_t (*)(const char *, const SerialConfig *, ErrorCallbackT); using ReadFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); using ReadUntilSequenceFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, const std::uint8_t *, int, ErrorCallbackT); using WriteFn = int (*)(int64_t, const std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); +static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); +constexpr Meta kMeta{}; +static_assert(kMeta.commits_since_tag >= 0); +static_assert(kMeta.is_dirty == 0 || kMeta.is_dirty == 1); static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); static_assert(sizeof(SerialConfig) == 5 * sizeof(int)); From 7fd1b1922a3b953e3a208f10509a7f29154588a2 Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 10:36:40 +0200 Subject: [PATCH 05/14] feat: remove unused library name and version string without 'v' from metadata --- include/cpp_core/interface/meta.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/cpp_core/interface/meta.h b/include/cpp_core/interface/meta.h index d513d30..e245435 100644 --- a/include/cpp_core/interface/meta.h +++ b/include/cpp_core/interface/meta.h @@ -20,15 +20,12 @@ extern "C" int commits_since_tag = version::GIT_COMMIT_COUNT; int is_dirty = version::GIT_IS_DIRTY ? 1 : 0; - const char *library_name = "cpp-core"; const char *version_string = version::VERSION; - const char *version_string_no_v = version::VERSION_NO_V; const char *prerelease = version::PRERELEASE; const char *prerelease_type = version::PRERELEASE_TYPE; const char *prerelease_number = version::PRERELEASE_NUMBER; const char *git_tag = version::GIT_TAG; - const char *git_tag_no_v = version::GIT_TAG_NO_V; const char *git_describe_hash = version::GIT_DESCRIBE_HASH; const char *git_commit_hash_short = version::GIT_COMMIT_HASH_SHORT; const char *git_commit_hash_full = version::GIT_COMMIT_HASH_FULL; From 40d2ec906cf855755dfc204c2ace0aa7ea4f6185 Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 10:44:01 +0200 Subject: [PATCH 06/14] feat: update reflection tests to correct public field count for Meta --- include/cpp_core/reflection.test.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/cpp_core/reflection.test.cpp b/include/cpp_core/reflection.test.cpp index 65fecc6..fec28fc 100644 --- a/include/cpp_core/reflection.test.cpp +++ b/include/cpp_core/reflection.test.cpp @@ -25,10 +25,8 @@ static_assert(cpp_core::reflection::publicFieldName() static_assert(cpp_core::reflection::publicFieldName() == "flow_mode"); static_assert(cpp_core::reflection::publicFieldCount() == 2); static_assert(cpp_core::reflection::hasPubliclyReflectableFields()); -static_assert(cpp_core::reflection::publicFieldCount() == 19); +static_assert(cpp_core::reflection::publicFieldCount() == 16); static_assert(cpp_core::reflection::publicFieldName() == "major"); -static_assert(cpp_core::reflection::publicFieldName() == "library_name"); -static_assert(cpp_core::reflection::publicFieldName() == "git_dirty_suffix"); static_assert(cpp_core::reflection::public_field_name_v == "message"); static_assert(cpp_core::reflection::public_field_count_v == 2); static_assert(!cpp_core::reflection::hasPubliclyReflectableFields()); From a9a01443225543e89c0167839db0613019f8b5b3 Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 10:49:48 +0200 Subject: [PATCH 07/14] feat: enhance metadata struct with detailed comments for clarity --- include/cpp_core/interface/meta.h | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/cpp_core/interface/meta.h b/include/cpp_core/interface/meta.h index e245435..f04ac92 100644 --- a/include/cpp_core/interface/meta.h +++ b/include/cpp_core/interface/meta.h @@ -14,24 +14,24 @@ extern "C" */ struct Meta { - int major = version::MAJOR; - int minor = version::MINOR; - int patch = version::PATCH; - int commits_since_tag = version::GIT_COMMIT_COUNT; - int is_dirty = version::GIT_IS_DIRTY ? 1 : 0; + int major = version::MAJOR; ///< Semantic-version major component. + int minor = version::MINOR; ///< Semantic-version minor component. + int patch = version::PATCH; ///< Semantic-version patch component. + int commits_since_tag = version::GIT_COMMIT_COUNT; ///< Commits since the closest Git tag. + int is_dirty = version::GIT_IS_DIRTY ? 1 : 0; ///< 1 for uncommitted changes, otherwise 0. - const char *version_string = version::VERSION; - const char *prerelease = version::PRERELEASE; - const char *prerelease_type = version::PRERELEASE_TYPE; - const char *prerelease_number = version::PRERELEASE_NUMBER; + const char *version_string = version::VERSION; ///< Complete generated version string. + const char *prerelease = version::PRERELEASE; ///< Prerelease identifier, or an empty string. + const char *prerelease_type = version::PRERELEASE_TYPE; ///< Prerelease kind such as `alpha` or `rc`. + const char *prerelease_number = version::PRERELEASE_NUMBER; ///< Prerelease number, or an empty string. - const char *git_tag = version::GIT_TAG; - const char *git_describe_hash = version::GIT_DESCRIBE_HASH; - const char *git_commit_hash_short = version::GIT_COMMIT_HASH_SHORT; - const char *git_commit_hash_full = version::GIT_COMMIT_HASH_FULL; - const char *git_commit_date = version::GIT_COMMIT_DATE; - const char *git_branch = version::GIT_BRANCH; - const char *git_dirty_suffix = version::GIT_DIRTY_SUFFIX; + const char *git_tag = version::GIT_TAG; ///< Closest Git tag. + const char *git_describe_hash = version::GIT_DESCRIBE_HASH; ///< Hash component reported by Git describe. + const char *git_commit_hash_short = version::GIT_COMMIT_HASH_SHORT; ///< Abbreviated commit hash. + const char *git_commit_hash_full = version::GIT_COMMIT_HASH_FULL; ///< Full commit hash. + const char *git_commit_date = version::GIT_COMMIT_DATE; ///< Commit timestamp including timezone. + const char *git_branch = version::GIT_BRANCH; ///< Branch name used for the build. + const char *git_dirty_suffix = version::GIT_DIRTY_SUFFIX; ///< `-dirty` or an empty string. }; } // namespace cpp_core From da23b566f29eb038bef720ad6efff5a25e9789df Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 11:49:34 +0200 Subject: [PATCH 08/14] feat: refactor serial configuration to use strong types for data bits, parity, stop bits, and flow control --- README.md | 2 +- .../cpp_core/interface/serial_set_data_bits.h | 5 ++- .../interface/serial_set_flow_control.h | 20 +++++----- .../cpp_core/interface/serial_set_parity.h | 6 ++- .../cpp_core/interface/serial_set_stop_bits.h | 5 ++- include/cpp_core/reflection.test.cpp | 2 + include/cpp_core/serial_config.hpp | 24 +++++------ include/cpp_core/serial_config.test.cpp | 17 ++++---- include/cpp_core/serial_interface.test.cpp | 10 ++++- include/cpp_core/strong_types.hpp | 40 +++++++++++++------ include/cpp_core/strong_types.test.cpp | 2 +- 11 files changed, 80 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 3ba06df..22158ed 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ other line settings: ```cpp constexpr auto serial_config = cpp_core::SerialConfig::make< 115'200, - 8, + cpp_core::DataBits::kEight, cpp_core::Parity::kNone, cpp_core::StopBits::kOne, cpp_core::FlowControl::kRtsCts>(); diff --git a/include/cpp_core/interface/serial_set_data_bits.h b/include/cpp_core/interface/serial_set_data_bits.h index 5887397..4aec53b 100644 --- a/include/cpp_core/interface/serial_set_data_bits.h +++ b/include/cpp_core/interface/serial_set_data_bits.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include #ifdef __cplusplus @@ -14,11 +15,11 @@ extern "C" * Takes effect immediately. All other line settings remain unchanged. * * @param handle Port handle obtained from serialOpen(). - * @param data_bits Number of data bits (5-8). + * @param data_bits Number of data bits. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialSetDataBits(int64_t handle, int data_bits, + MODULE_API auto serialSetDataBits(int64_t handle, cpp_core::DataBits data_bits, ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus diff --git a/include/cpp_core/interface/serial_set_flow_control.h b/include/cpp_core/interface/serial_set_flow_control.h index d5bf779..66f8bd9 100644 --- a/include/cpp_core/interface/serial_set_flow_control.h +++ b/include/cpp_core/interface/serial_set_flow_control.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include #ifdef __cplusplus @@ -14,24 +15,21 @@ extern "C" * Flow control prevents buffer overruns when one side is slower than the * other. Three modes are supported: * - * | @p mode | Meaning | - * |---------|-----------------------------------------------| - * | 0 | None - no flow control (default after open). | - * | 1 | Hardware (RTS/CTS) - the UART automatically | - * | | de-asserts RTS when the RX buffer is full and | - * | | pauses TX when CTS is de-asserted. | - * | 2 | Software (XON/XOFF) - in-band control chars | - * | | `0x11` (XON) and `0x13` (XOFF) are sent to | - * | | pause/resume the remote transmitter. | + * | @p flow_mode | Meaning | + * |------------------------------|----------------------------------------------| + * | `FlowControl::kNone` | No flow control. | + * | `FlowControl::kRtsCts` | Hardware RTS/CTS flow control. | + * | `FlowControl::kXonXoff` | Software XON/XOFF flow control. | * * Changing the mode on an already-open port takes effect immediately. * * @param handle Port handle obtained from serialOpen(). - * @param mode Flow-control mode: 0 = none, 1 = RTS/CTS, 2 = XON/XOFF. + * @param flow_mode Flow-control mode. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialSetFlowControl(int64_t handle, int mode, ErrorCallbackT error_callback = nullptr) -> int; + MODULE_API auto serialSetFlowControl(int64_t handle, cpp_core::FlowControl flow_mode, + ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus } diff --git a/include/cpp_core/interface/serial_set_parity.h b/include/cpp_core/interface/serial_set_parity.h index d67193f..049446c 100644 --- a/include/cpp_core/interface/serial_set_parity.h +++ b/include/cpp_core/interface/serial_set_parity.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include #ifdef __cplusplus @@ -14,11 +15,12 @@ extern "C" * Takes effect immediately. All other line settings remain unchanged. * * @param handle Port handle obtained from serialOpen(). - * @param parity 0 = none, 1 = even, 2 = odd. + * @param parity Parity mode. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialSetParity(int64_t handle, int parity, ErrorCallbackT error_callback = nullptr) -> int; + MODULE_API auto serialSetParity(int64_t handle, cpp_core::Parity parity, ErrorCallbackT error_callback = nullptr) + -> int; #ifdef __cplusplus } diff --git a/include/cpp_core/interface/serial_set_stop_bits.h b/include/cpp_core/interface/serial_set_stop_bits.h index fe9fe98..f199c59 100644 --- a/include/cpp_core/interface/serial_set_stop_bits.h +++ b/include/cpp_core/interface/serial_set_stop_bits.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include #ifdef __cplusplus @@ -14,11 +15,11 @@ extern "C" * Takes effect immediately. All other line settings remain unchanged. * * @param handle Port handle obtained from serialOpen(). - * @param stop_bits 0 = 1 stop bit, 2 = 2 stop bits. + * @param stop_bits Stop-bit mode. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. */ - MODULE_API auto serialSetStopBits(int64_t handle, int stop_bits, + MODULE_API auto serialSetStopBits(int64_t handle, cpp_core::StopBits stop_bits, ErrorCallbackT error_callback = nullptr) -> int; #ifdef __cplusplus diff --git a/include/cpp_core/reflection.test.cpp b/include/cpp_core/reflection.test.cpp index fec28fc..40b575b 100644 --- a/include/cpp_core/reflection.test.cpp +++ b/include/cpp_core/reflection.test.cpp @@ -13,9 +13,11 @@ struct PrivateMemberAggregate int value; }; +static_assert(cpp_core::reflection::enumeratorCount() == 4); static_assert(cpp_core::reflection::enumeratorCount() == 3); static_assert(cpp_core::reflection::enumeratorCount() == 2); static_assert(cpp_core::reflection::enumeratorCount() == 3); +static_assert(cpp_core::reflection::enumeratorName() == "kEight"); static_assert(cpp_core::reflection::enumeratorName() == "kNone"); static_assert(cpp_core::reflection::enumeratorName() == "kEven"); static_assert(cpp_core::reflection::enumerator_name_v == "kXonXoff"); diff --git a/include/cpp_core/serial_config.hpp b/include/cpp_core/serial_config.hpp index d10ba9d..16a83ac 100644 --- a/include/cpp_core/serial_config.hpp +++ b/include/cpp_core/serial_config.hpp @@ -23,9 +23,9 @@ constexpr auto validateBaudrate(int baud) -> bool return baud >= 300; } -constexpr auto validateDataBits(int bits) -> bool +constexpr auto validateDataBits(DataBits bits) -> bool { - return bits >= 5 && bits <= 8; + return bits == DataBits::kFive || bits == DataBits::kSix || bits == DataBits::kSeven || bits == DataBits::kEight; } constexpr auto validateParity(Parity parity) -> bool @@ -55,29 +55,29 @@ constexpr auto validateTimeout(int timeout_ms, int multiplier) -> bool * Compile-time validated serial configuration. * Invalid configs are rejected at compile time - no runtime overhead. * constexpr auto kCfg = - * SerialConfig::make<9600, 8, Parity::kNone, StopBits::kOne, FlowControl::kNone>(); + * SerialConfig::make<9600, DataBits::kEight, Parity::kNone, StopBits::kOne, FlowControl::kNone>(); */ struct SerialConfig { int baudrate; ///< Baud rate in bit/s (>= 300). - int data_bits; ///< Number of data bits (5-8). + DataBits data_bits; ///< Number of data bits. Parity parity; ///< Parity mode. StopBits stop_bits; ///< Stop-bit mode. FlowControl flow_mode; ///< None, hardware RTS/CTS, or software XON/XOFF flow control. - template static consteval auto make() -> SerialConfig { static_assert(detail::validateBaudrate(Baud), "Baudrate must be >= 300"); - static_assert(detail::validateDataBits(DataBitsVal), "DataBits must be 5-8"); + static_assert(detail::validateDataBits(D), "DataBits must be 5-8"); static_assert(detail::validateParity(P), "Parity must be none, even, or odd"); static_assert(detail::validateStopBits(S), "StopBits must be one or two"); static_assert(detail::validateFlowControl(F), "FlowControl must be none, RTS/CTS, or XON/XOFF"); return SerialConfig{ .baudrate = Baud, - .data_bits = DataBitsVal, + .data_bits = D, .parity = P, .stop_bits = S, .flow_mode = F, @@ -88,10 +88,10 @@ struct SerialConfig StopBits stop_bits = StopBits::kOne, FlowControl flow_mode = FlowControl::kNone) -> Result { - return tryMake(baud.get(), data_bits.get(), parity, stop_bits, flow_mode); + return tryMake(baud.get(), data_bits, parity, stop_bits, flow_mode); } - [[nodiscard]] static constexpr auto tryMake(int baud, int data_bits_val, Parity parity = Parity::kNone, + [[nodiscard]] static constexpr auto tryMake(int baud, DataBits data_bits, Parity parity = Parity::kNone, StopBits stop_bits = StopBits::kOne, FlowControl flow_mode = FlowControl::kNone) -> Result { @@ -99,7 +99,7 @@ struct SerialConfig { return fail(StatusCode::Configuration::kSetBaudrateError); } - if (!detail::validateDataBits(data_bits_val)) + if (!detail::validateDataBits(data_bits)) { return fail(StatusCode::Configuration::kSetDataBitsError); } @@ -117,7 +117,7 @@ struct SerialConfig } return ok(SerialConfig{ .baudrate = baud, - .data_bits = data_bits_val, + .data_bits = data_bits, .parity = parity, .stop_bits = stop_bits, .flow_mode = flow_mode, @@ -138,7 +138,7 @@ struct SerialConfig [[nodiscard]] constexpr auto dataBitsValue() const noexcept -> DataBits { - return DataBits{data_bits}; + return data_bits; } [[nodiscard]] constexpr auto parityInt() const noexcept -> int diff --git a/include/cpp_core/serial_config.test.cpp b/include/cpp_core/serial_config.test.cpp index 313ff20..d3eab65 100644 --- a/include/cpp_core/serial_config.test.cpp +++ b/include/cpp_core/serial_config.test.cpp @@ -5,39 +5,40 @@ namespace cpp_core::tests::serial_config { constexpr auto kCompileTimeConfig = - SerialConfig::make<115'200, 8, Parity::kEven, StopBits::kTwo, FlowControl::kRtsCts>(); + SerialConfig::make<115'200, DataBits::kEight, Parity::kEven, StopBits::kTwo, FlowControl::kRtsCts>(); static_assert(kCompileTimeConfig.isValid()); static_assert(kCompileTimeConfig.baudrateValue() == Baudrate{115'200}); -static_assert(kCompileTimeConfig.dataBitsValue() == DataBits{8}); +static_assert(kCompileTimeConfig.dataBitsValue() == DataBits::kEight); static_assert(kCompileTimeConfig.parityInt() == 1); static_assert(kCompileTimeConfig.stopBitsInt() == 2); static_assert(kCompileTimeConfig.flowModeInt() == 1); constexpr auto kRuntimeLikeConfig = - SerialConfig::tryMake(Baudrate{57'600}, DataBits{7}, Parity::kOdd, StopBits::kOne, FlowControl::kXonXoff); + SerialConfig::tryMake(Baudrate{57'600}, DataBits::kSeven, Parity::kOdd, StopBits::kOne, FlowControl::kXonXoff); static_assert(kRuntimeLikeConfig.has_value()); static_assert(kRuntimeLikeConfig->baudrateValue() == Baudrate{57'600}); -static_assert(kRuntimeLikeConfig->dataBitsValue() == DataBits{7}); +static_assert(kRuntimeLikeConfig->dataBitsValue() == DataBits::kSeven); static_assert(kRuntimeLikeConfig->flow_mode == FlowControl::kXonXoff); consteval auto rejectsBadBaudrate() -> bool { - return !SerialConfig::tryMake(Baudrate{299}, DataBits{8}).has_value(); + return !SerialConfig::tryMake(Baudrate{299}, DataBits::kEight).has_value(); } consteval auto rejectsBadDataBits() -> bool { - return !SerialConfig::tryMake(9'600, 4).has_value(); + return !SerialConfig::tryMake(9'600, static_cast(4)).has_value(); } consteval auto rejectsBadParity() -> bool { - return !SerialConfig::tryMake(9'600, 8, static_cast(77)).has_value(); + return !SerialConfig::tryMake(9'600, DataBits::kEight, static_cast(77)).has_value(); } consteval auto rejectsBadFlowMode() -> bool { - return !SerialConfig::tryMake(9'600, 8, Parity::kNone, StopBits::kOne, static_cast(77)).has_value(); + return !SerialConfig::tryMake(9'600, DataBits::kEight, Parity::kNone, StopBits::kOne, static_cast(77)) + .has_value(); } static_assert(rejectsBadBaudrate()); diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index 44d2635..617fcfa 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -15,12 +15,20 @@ using ReadFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig * using ReadUntilSequenceFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, const std::uint8_t *, int, ErrorCallbackT); using WriteFn = int (*)(int64_t, const std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); +using SetDataBitsFn = int (*)(int64_t, DataBits, ErrorCallbackT); +using SetParityFn = int (*)(int64_t, Parity, ErrorCallbackT); +using SetStopBitsFn = int (*)(int64_t, StopBits, ErrorCallbackT); +using SetFlowControlFn = int (*)(int64_t, FlowControl, ErrorCallbackT); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); @@ -39,7 +47,7 @@ static_assert(!ByteBuffer>); static_assert(!ConstByteBuffer>); inline constexpr char kPort[] = "/dev/ttyUSB0"; -constexpr auto kSerialConfig = SerialConfig::make<115'200, 8>(); +constexpr auto kSerialConfig = SerialConfig::make<115'200, DataBits::kEight>(); constexpr auto kTimeoutConfig = SerialTimeoutConfig::make<50, 1>(); inline constexpr std::uint8_t kByte{}; diff --git a/include/cpp_core/strong_types.hpp b/include/cpp_core/strong_types.hpp index f2f2b81..408c3d7 100644 --- a/include/cpp_core/strong_types.hpp +++ b/include/cpp_core/strong_types.hpp @@ -61,9 +61,6 @@ template struct StrongInt struct BaudrateTag { }; -struct DataBitsTag -{ -}; struct TimeoutMsTag { }; @@ -72,30 +69,47 @@ struct MultiplierTag }; using Baudrate = StrongInt; -using DataBits = StrongInt; using TimeoutMs = StrongInt; using Multiplier = StrongInt; -// Parity & StopBits enums +/** + * Number of data bits contained in each serial frame. + */ +enum class DataBits : int +{ + kFive = 5, ///< Use five data bits. + kSix = 6, ///< Use six data bits. + kSeven = 7, ///< Use seven data bits. + kEight = 8, ///< Use eight data bits. +}; +/** + * Parity mode used for serial communication. + */ enum class Parity : int { - kNone = 0, - kEven = 1, - kOdd = 2, + kNone = 0, ///< Disable parity checking and generation. + kEven = 1, ///< Use even parity. + kOdd = 2, ///< Use odd parity. }; +/** + * Number of stop bits appended to each serial frame. + */ enum class StopBits : int { - kOne = 0, - kTwo = 2, + kOne = 0, ///< Use one stop bit. + kTwo = 2, ///< Use two stop bits. }; +/** + * Flow-control mode used by the serial port. + */ enum class FlowControl : int { - kNone = 0, - kRtsCts = 1, - kXonXoff = 2, + kNone = 0, ///< Disable flow control. + kRtsCts = 1, ///< Use hardware RTS/CTS flow control. + kXonXoff = 2, ///< Use software XON/XOFF flow control. }; template diff --git a/include/cpp_core/strong_types.test.cpp b/include/cpp_core/strong_types.test.cpp index 0ca321d..fa171af 100644 --- a/include/cpp_core/strong_types.test.cpp +++ b/include/cpp_core/strong_types.test.cpp @@ -5,7 +5,7 @@ namespace cpp_core::tests::strong_types static_assert(Baudrate{}.get() == 0); static_assert((Baudrate{9'600} + Baudrate{115'200}).get() == 124'800); -static_assert((DataBits{8} - DataBits{3}).get() == 5); +static_assert(toInt(DataBits::kEight) == 8); static_assert(toInt(Parity::kOdd) == 2); static_assert(toInt(StopBits::kTwo) == 2); static_assert(toInt(FlowControl::kXonXoff) == 2); From 2de9609ff4799298053c5768540b81ff330f1c60 Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 14:40:33 +0200 Subject: [PATCH 09/14] Refactor serial interface headers to remove C linkage wrappers - Removed unnecessary extern "C" wrappers from function declarations in the serial interface headers. - Updated documentation comments for clarity and consistency across all serial functions. - Ensured that all function signatures remain unchanged while improving readability. --- README.md | 4 +- include/cpp_core/error_callback.h | 11 +-- include/cpp_core/interface/meta.h | 69 ++++++++----------- .../cpp_core/interface/serial_abort_read.h | 31 +++------ .../cpp_core/interface/serial_abort_write.h | 31 +++------ .../interface/serial_clear_buffer_in.h | 31 +++------ .../interface/serial_clear_buffer_out.h | 31 +++------ include/cpp_core/interface/serial_close.h | 31 +++------ include/cpp_core/interface/serial_drain.h | 59 +++++++--------- .../cpp_core/interface/serial_get_baudrate.h | 33 ++++----- include/cpp_core/interface/serial_get_cts.h | 33 ++++----- .../cpp_core/interface/serial_get_data_bits.h | 25 +++---- include/cpp_core/interface/serial_get_dcd.h | 33 ++++----- include/cpp_core/interface/serial_get_dsr.h | 31 +++------ .../interface/serial_get_flow_control.h | 25 +++---- .../cpp_core/interface/serial_get_parity.h | 25 +++---- include/cpp_core/interface/serial_get_ri.h | 31 +++------ .../cpp_core/interface/serial_get_stop_bits.h | 25 +++---- .../interface/serial_in_bytes_total.h | 25 +++---- .../interface/serial_in_bytes_waiting.h | 49 ++++++------- .../cpp_core/interface/serial_list_ports.h | 39 ++++------- .../cpp_core/interface/serial_monitor_ports.h | 35 ++++------ include/cpp_core/interface/serial_open.h | 41 +++++------ .../interface/serial_out_bytes_total.h | 25 +++---- .../interface/serial_out_bytes_waiting.h | 43 +++++------- include/cpp_core/interface/serial_read.h | 43 +++++------- .../interface/serial_read_until_sequence.h | 49 ++++++------- .../cpp_core/interface/serial_send_break.h | 47 +++++-------- .../cpp_core/interface/serial_set_baudrate.h | 42 +++++------ .../cpp_core/interface/serial_set_data_bits.h | 33 ++++----- include/cpp_core/interface/serial_set_dtr.h | 37 ++++------ .../interface/serial_set_error_callback.h | 27 +++----- .../interface/serial_set_flow_control.h | 51 ++++++-------- .../cpp_core/interface/serial_set_parity.h | 33 ++++----- .../interface/serial_set_read_callback.h | 25 +++---- include/cpp_core/interface/serial_set_rts.h | 37 ++++------ .../cpp_core/interface/serial_set_stop_bits.h | 33 ++++----- .../interface/serial_set_write_callback.h | 25 +++---- include/cpp_core/interface/serial_write.h | 41 +++++------ include/cpp_core/module_api.h | 10 ++- 40 files changed, 505 insertions(+), 844 deletions(-) diff --git a/README.md b/README.md index 22158ed..2937c7b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This repository does not provide a ready-to-load shared library by itself. It pr ## What It Provides -- Header-only C-compatible serial API definitions under `include/cpp_core` +- Header-only C++ API definitions with unmangled C linkage under `include/cpp_core` - Modern C++26 helper surface for `std::expected`-based error propagation, strong typed config values, and compile-time reflection helpers - A generated version surface used consistently across all platform bindings - An installable CMake package target: `cpp_core::cpp_core` @@ -91,7 +91,7 @@ The main aggregated interface lives in: #include ``` -The ABI is intentionally plain-C friendly: functions either return a status code, return a value-or-negative-status, or return an opaque handle-or-negative-status. +The API requires a C++ compiler, while exported functions use unmangled C linkage through `MODULE_API`. Functions either return a status code, return a value-or-negative-status, or return an opaque handle-or-negative-status. Example: diff --git a/include/cpp_core/error_callback.h b/include/cpp_core/error_callback.h index ffef1ab..dcd8bc0 100644 --- a/include/cpp_core/error_callback.h +++ b/include/cpp_core/error_callback.h @@ -1,12 +1,3 @@ #pragma once -#ifdef __cplusplus -extern "C" -{ -#endif - - using ErrorCallbackT = void (*)(int error_code, const char *message); - -#ifdef __cplusplus -} // extern "C" -#endif +using ErrorCallbackT = void (*)(int error_code, const char *message); diff --git a/include/cpp_core/interface/meta.h b/include/cpp_core/interface/meta.h index f04ac92..29cc492 100644 --- a/include/cpp_core/interface/meta.h +++ b/include/cpp_core/interface/meta.h @@ -2,46 +2,37 @@ #include "../module_api.h" #include "../version.hpp" -#ifdef __cplusplus -extern "C" +namespace cpp_core { -#endif - - namespace cpp_core - { - /** - * Build and source metadata for the loaded cpp_core-based library. - */ - struct Meta - { - int major = version::MAJOR; ///< Semantic-version major component. - int minor = version::MINOR; ///< Semantic-version minor component. - int patch = version::PATCH; ///< Semantic-version patch component. - int commits_since_tag = version::GIT_COMMIT_COUNT; ///< Commits since the closest Git tag. - int is_dirty = version::GIT_IS_DIRTY ? 1 : 0; ///< 1 for uncommitted changes, otherwise 0. - - const char *version_string = version::VERSION; ///< Complete generated version string. - const char *prerelease = version::PRERELEASE; ///< Prerelease identifier, or an empty string. - const char *prerelease_type = version::PRERELEASE_TYPE; ///< Prerelease kind such as `alpha` or `rc`. - const char *prerelease_number = version::PRERELEASE_NUMBER; ///< Prerelease number, or an empty string. +/** + * Build and source metadata for the loaded cpp_core-based library. + */ +struct Meta +{ + int major = version::MAJOR; ///< Semantic-version major component. + int minor = version::MINOR; ///< Semantic-version minor component. + int patch = version::PATCH; ///< Semantic-version patch component. + int commits_since_tag = version::GIT_COMMIT_COUNT; ///< Commits since the closest Git tag. + int is_dirty = version::GIT_IS_DIRTY ? 1 : 0; ///< 1 for uncommitted changes, otherwise 0. - const char *git_tag = version::GIT_TAG; ///< Closest Git tag. - const char *git_describe_hash = version::GIT_DESCRIBE_HASH; ///< Hash component reported by Git describe. - const char *git_commit_hash_short = version::GIT_COMMIT_HASH_SHORT; ///< Abbreviated commit hash. - const char *git_commit_hash_full = version::GIT_COMMIT_HASH_FULL; ///< Full commit hash. - const char *git_commit_date = version::GIT_COMMIT_DATE; ///< Commit timestamp including timezone. - const char *git_branch = version::GIT_BRANCH; ///< Branch name used for the build. - const char *git_dirty_suffix = version::GIT_DIRTY_SUFFIX; ///< `-dirty` or an empty string. - }; - } // namespace cpp_core + const char *version_string = version::VERSION; ///< Complete generated version string. + const char *prerelease = version::PRERELEASE; ///< Prerelease identifier, or an empty string. + const char *prerelease_type = version::PRERELEASE_TYPE; ///< Prerelease kind such as `alpha` or `rc`. + const char *prerelease_number = version::PRERELEASE_NUMBER; ///< Prerelease number, or an empty string. - /** - * @brief Copy metadata for the loaded library. - * - * @param[out] out Structure receiving the metadata. Passing `nullptr` is a no-op. - */ - MODULE_API void meta(cpp_core::Meta *out); + const char *git_tag = version::GIT_TAG; ///< Closest Git tag. + const char *git_describe_hash = version::GIT_DESCRIBE_HASH; ///< Hash component reported by Git describe. + const char *git_commit_hash_short = version::GIT_COMMIT_HASH_SHORT; ///< Abbreviated commit hash. + const char *git_commit_hash_full = version::GIT_COMMIT_HASH_FULL; ///< Full commit hash. + const char *git_commit_date = version::GIT_COMMIT_DATE; ///< Commit timestamp including timezone. + const char *git_branch = version::GIT_BRANCH; ///< Branch name used for the build. + const char *git_dirty_suffix = version::GIT_DIRTY_SUFFIX; ///< `-dirty` or an empty string. +}; +} // namespace cpp_core -#ifdef __cplusplus -} -#endif +/** + * @brief Copy metadata for the loaded library. + * + * @param[out] out Structure receiving the metadata. Passing `nullptr` is a no-op. + */ +MODULE_API void meta(cpp_core::Meta *out); diff --git a/include/cpp_core/interface/serial_abort_read.h b/include/cpp_core/interface/serial_abort_read.h index 6ac8008..43fd366 100644 --- a/include/cpp_core/interface/serial_abort_read.h +++ b/include/cpp_core/interface/serial_abort_read.h @@ -3,23 +3,14 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Abort a blocking read operation running in a different thread. - * - * The target read function returns immediately with - * ::cpp_core::StatusCode::Io::kAbortReadError. - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialAbortRead(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Abort a blocking read operation running in a different thread. + * + * The target read function returns immediately with + * ::cpp_core::StatusCode::Io::kAbortReadError. + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialAbortRead(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_abort_write.h b/include/cpp_core/interface/serial_abort_write.h index d579d94..42485ff 100644 --- a/include/cpp_core/interface/serial_abort_write.h +++ b/include/cpp_core/interface/serial_abort_write.h @@ -3,23 +3,14 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Abort a blocking write operation running in a different thread. - * - * The target write function returns immediately with - * ::cpp_core::StatusCode::Io::kAbortWriteError. - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialAbortWrite(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Abort a blocking write operation running in a different thread. + * + * The target write function returns immediately with + * ::cpp_core::StatusCode::Io::kAbortWriteError. + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialAbortWrite(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_clear_buffer_in.h b/include/cpp_core/interface/serial_clear_buffer_in.h index 9870293..869ce97 100644 --- a/include/cpp_core/interface/serial_clear_buffer_in.h +++ b/include/cpp_core/interface/serial_clear_buffer_in.h @@ -3,23 +3,14 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Clear (flush) the device's input buffer. - * - * Discards every byte the driver has already received but the application - * has not yet read. - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialClearBufferIn(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Clear (flush) the device's input buffer. + * + * Discards every byte the driver has already received but the application + * has not yet read. + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialClearBufferIn(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_clear_buffer_out.h b/include/cpp_core/interface/serial_clear_buffer_out.h index eea1966..341573e 100644 --- a/include/cpp_core/interface/serial_clear_buffer_out.h +++ b/include/cpp_core/interface/serial_clear_buffer_out.h @@ -3,23 +3,14 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Clear (flush) the device's output buffer. - * - * Blocks until all queued bytes have been transmitted and then discards any - * remaining data. - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialClearBufferOut(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Clear (flush) the device's output buffer. + * + * Blocks until all queued bytes have been transmitted and then discards any + * remaining data. + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialClearBufferOut(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_close.h b/include/cpp_core/interface/serial_close.h index 0d3a7a5..b0d48df 100644 --- a/include/cpp_core/interface/serial_close.h +++ b/include/cpp_core/interface/serial_close.h @@ -3,23 +3,14 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Close a previously opened serial port. - * - * The handle becomes invalid after the call. Passing an already invalid - * (<= 0) handle is a no-op. - * - * @param handle Handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialClose(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Close a previously opened serial port. + * + * The handle becomes invalid after the call. Passing an already invalid + * (<= 0) handle is a no-op. + * + * @param handle Handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialClose(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_drain.h b/include/cpp_core/interface/serial_drain.h index ca3dda6..99f68e8 100644 --- a/include/cpp_core/interface/serial_drain.h +++ b/include/cpp_core/interface/serial_drain.h @@ -3,37 +3,28 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Wait until the operating-system driver has physically sent every queued byte. - * - * The function blocks the *calling thread* until the device driver reports - * that the transmit FIFO is **empty** - i.e. all bytes handed to previous - * `serialWrite*` calls have been shifted out on the wire. It does *not* - * flush higher-level protocol buffers you may have implemented yourself. - * - * Typical use-case: ensure a complete command frame has left the UART - * before toggling RTS/DTR or powering down the device. - * - * @code{.cpp} - * // Send a frame and make sure it actually hits the line - * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 50, .multiplier = 1}; - * serialWrite(h, frame, frame_len, &timeout); - * if (serialDrain(h) < 0) { - * fprintf(stderr, "drain failed\n"); - * } - * @endcode - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialDrain(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Wait until the operating-system driver has physically sent every queued byte. + * + * The function blocks the *calling thread* until the device driver reports + * that the transmit FIFO is **empty** - i.e. all bytes handed to previous + * `serialWrite*` calls have been shifted out on the wire. It does *not* + * flush higher-level protocol buffers you may have implemented yourself. + * + * Typical use-case: ensure a complete command frame has left the UART + * before toggling RTS/DTR or powering down the device. + * + * @code{.cpp} + * // Send a frame and make sure it actually hits the line + * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 50, .multiplier = 1}; + * serialWrite(h, frame, frame_len, &timeout); + * if (serialDrain(h) < 0) { + * fprintf(stderr, "drain failed\n"); + * } + * @endcode + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialDrain(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_baudrate.h b/include/cpp_core/interface/serial_get_baudrate.h index 157cf75..b0de738 100644 --- a/include/cpp_core/interface/serial_get_baudrate.h +++ b/include/cpp_core/interface/serial_get_baudrate.h @@ -3,24 +3,15 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Query the current baud rate of an open serial port. - * - * Reads back the baud rate that the OS driver is currently using. Useful for - * verifying that serialOpen() or serialSetBaudrate() applied the requested - * value. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Current baud rate in bit/s (>= 300) or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetBaudrate(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Query the current baud rate of an open serial port. + * + * Reads back the baud rate that the OS driver is currently using. Useful for + * verifying that serialOpen() or serialSetBaudrate() applied the requested + * value. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Current baud rate in bit/s (>= 300) or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetBaudrate(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_cts.h b/include/cpp_core/interface/serial_get_cts.h index 8b2a695..04200c1 100644 --- a/include/cpp_core/interface/serial_get_cts.h +++ b/include/cpp_core/interface/serial_get_cts.h @@ -3,24 +3,15 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read the current state of the Clear To Send (CTS) input line. - * - * CTS is asserted by the remote device to indicate it is ready to receive - * data. Polling this line is useful when manual flow-control logic is - * required instead of (or in addition to) automatic RTS/CTS flow control. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetCts(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Read the current state of the Clear To Send (CTS) input line. + * + * CTS is asserted by the remote device to indicate it is ready to receive + * data. Polling this line is useful when manual flow-control logic is + * required instead of (or in addition to) automatic RTS/CTS flow control. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetCts(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_data_bits.h b/include/cpp_core/interface/serial_get_data_bits.h index ce537d5..5817c93 100644 --- a/include/cpp_core/interface/serial_get_data_bits.h +++ b/include/cpp_core/interface/serial_get_data_bits.h @@ -3,20 +3,11 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Query the current number of data bits of an open serial port. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Current data bits (5-8) or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetDataBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Query the current number of data bits of an open serial port. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Current data bits (5-8) or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetDataBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_dcd.h b/include/cpp_core/interface/serial_get_dcd.h index e34021c..49b48b0 100644 --- a/include/cpp_core/interface/serial_get_dcd.h +++ b/include/cpp_core/interface/serial_get_dcd.h @@ -3,24 +3,15 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read the current state of the Data Carrier Detect (DCD) input line. - * - * DCD is asserted by a modem when a carrier signal has been detected on the - * telephone line. For direct serial links it can serve as a general-purpose - * "connection alive" indicator. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetDcd(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Read the current state of the Data Carrier Detect (DCD) input line. + * + * DCD is asserted by a modem when a carrier signal has been detected on the + * telephone line. For direct serial links it can serve as a general-purpose + * "connection alive" indicator. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetDcd(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_dsr.h b/include/cpp_core/interface/serial_get_dsr.h index 8408782..34cf871 100644 --- a/include/cpp_core/interface/serial_get_dsr.h +++ b/include/cpp_core/interface/serial_get_dsr.h @@ -3,23 +3,14 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read the current state of the Data Set Ready (DSR) input line. - * - * DSR is asserted by the remote device to indicate it is powered on and - * ready to communicate. It is the counterpart to DTR. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetDsr(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Read the current state of the Data Set Ready (DSR) input line. + * + * DSR is asserted by the remote device to indicate it is powered on and + * ready to communicate. It is the counterpart to DTR. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetDsr(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_flow_control.h b/include/cpp_core/interface/serial_get_flow_control.h index 26f25ad..2db7e48 100644 --- a/include/cpp_core/interface/serial_get_flow_control.h +++ b/include/cpp_core/interface/serial_get_flow_control.h @@ -3,20 +3,11 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Query the current flow-control mode of an open serial port. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 = none, 1 = RTS/CTS, 2 = XON/XOFF, or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetFlowControl(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Query the current flow-control mode of an open serial port. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 = none, 1 = RTS/CTS, 2 = XON/XOFF, or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetFlowControl(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_parity.h b/include/cpp_core/interface/serial_get_parity.h index cf3106e..199bf27 100644 --- a/include/cpp_core/interface/serial_get_parity.h +++ b/include/cpp_core/interface/serial_get_parity.h @@ -3,20 +3,11 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Query the current parity setting of an open serial port. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 = none, 1 = even, 2 = odd, or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetParity(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Query the current parity setting of an open serial port. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 = none, 1 = even, 2 = odd, or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetParity(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_ri.h b/include/cpp_core/interface/serial_get_ri.h index 6cffea1..5eeddab 100644 --- a/include/cpp_core/interface/serial_get_ri.h +++ b/include/cpp_core/interface/serial_get_ri.h @@ -3,23 +3,14 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read the current state of the Ring Indicator (RI) input line. - * - * RI is asserted by a modem to signal an incoming call. On non-modem - * hardware it can be repurposed as a general-purpose input signal. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetRi(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Read the current state of the Ring Indicator (RI) input line. + * + * RI is asserted by a modem to signal an incoming call. On non-modem + * hardware it can be repurposed as a general-purpose input signal. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 1 if asserted (HIGH), 0 if de-asserted (LOW), or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetRi(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_get_stop_bits.h b/include/cpp_core/interface/serial_get_stop_bits.h index 90f39d8..5c4ab5d 100644 --- a/include/cpp_core/interface/serial_get_stop_bits.h +++ b/include/cpp_core/interface/serial_get_stop_bits.h @@ -3,20 +3,11 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Query the current stop-bit setting of an open serial port. - * - * @param handle Port handle obtained from serialOpen(). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 = 1 stop bit, 2 = 2 stop bits, or a negative error code from ::cpp_core::StatusCode. - */ - MODULE_API auto serialGetStopBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Query the current stop-bit setting of an open serial port. + * + * @param handle Port handle obtained from serialOpen(). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 = 1 stop bit, 2 = 2 stop bits, or a negative error code from ::cpp_core::StatusCode. + */ +MODULE_API auto serialGetStopBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_in_bytes_total.h b/include/cpp_core/interface/serial_in_bytes_total.h index 01511bf..4584311 100644 --- a/include/cpp_core/interface/serial_in_bytes_total.h +++ b/include/cpp_core/interface/serial_in_bytes_total.h @@ -3,20 +3,11 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Total number of bytes received since the port was opened. - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Total number of bytes read or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialInBytesTotal(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int64_t; - -#ifdef __cplusplus -} -#endif +/** + * @brief Total number of bytes received since the port was opened. + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Total number of bytes read or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialInBytesTotal(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int64_t; diff --git a/include/cpp_core/interface/serial_in_bytes_waiting.h b/include/cpp_core/interface/serial_in_bytes_waiting.h index 6049f2e..c66ac2f 100644 --- a/include/cpp_core/interface/serial_in_bytes_waiting.h +++ b/include/cpp_core/interface/serial_in_bytes_waiting.h @@ -3,32 +3,23 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Query how many bytes can be read *immediately* without blocking. - * - * The number reflects the size of the driver's RX FIFO **after** accounting - * for data already consumed by the application. A value of `0` therefore - * means a read call would have to wait for the next byte to arrive. - * - * @code{.cpp} - * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 0, .multiplier = 1}; - * int pending = serialInBytesWaiting(h); - * if (pending > 0) { - * serialRead(h, buf, pending, &timeout); // non-blocking read - * } - * @endcode - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Bytes available for instant reading or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialInBytesWaiting(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Query how many bytes can be read *immediately* without blocking. + * + * The number reflects the size of the driver's RX FIFO **after** accounting + * for data already consumed by the application. A value of `0` therefore + * means a read call would have to wait for the next byte to arrive. + * + * @code{.cpp} + * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 0, .multiplier = 1}; + * int pending = serialInBytesWaiting(h); + * if (pending > 0) { + * serialRead(h, buf, pending, &timeout); // non-blocking read + * } + * @endcode + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Bytes available for instant reading or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialInBytesWaiting(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_list_ports.h b/include/cpp_core/interface/serial_list_ports.h index 66b01e0..bcee02e 100644 --- a/include/cpp_core/interface/serial_list_ports.h +++ b/include/cpp_core/interface/serial_list_ports.h @@ -2,27 +2,18 @@ #include "../error_callback.h" #include "../module_api.h" -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Enumerate all available serial ports on the system. - * - * The supplied callback is invoked once for every discovered port. All string - * parameters may be `nullptr` if the information is unknown. - * - * @param callback_fn Callback receiving port information. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Number of ports found or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialListPorts(void (*callback_fn)(const char *port, const char *path, const char *manufacturer, - const char *serial_number, const char *pnp_id, - const char *location_id, const char *product_id, - const char *vendor_id), - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Enumerate all available serial ports on the system. + * + * The supplied callback is invoked once for every discovered port. All string + * parameters may be `nullptr` if the information is unknown. + * + * @param callback_fn Callback receiving port information. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Number of ports found or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialListPorts(void (*callback_fn)(const char *port, const char *path, const char *manufacturer, + const char *serial_number, const char *pnp_id, + const char *location_id, const char *product_id, + const char *vendor_id), + ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_monitor_ports.h b/include/cpp_core/interface/serial_monitor_ports.h index 01e3b8c..db5999b 100644 --- a/include/cpp_core/interface/serial_monitor_ports.h +++ b/include/cpp_core/interface/serial_monitor_ports.h @@ -2,25 +2,16 @@ #include "../error_callback.h" #include "../module_api.h" -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Start or stop port attach/detach notifications. - * - * Passing a non-null callback starts monitoring and invokes it with `event = 1` - * for attach and `event = 0` for detach notifications. Passing `nullptr` - * stops a previously running monitor. - * - * @param callback_fn Notification callback or `nullptr` to stop monitoring. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialMonitorPorts(void (*callback_fn)(int event, const char *port), - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Start or stop port attach/detach notifications. + * + * Passing a non-null callback starts monitoring and invokes it with `event = 1` + * for attach and `event = 0` for detach notifications. Passing `nullptr` + * stops a previously running monitor. + * + * @param callback_fn Notification callback or `nullptr` to stop monitoring. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialMonitorPorts(void (*callback_fn)(int event, const char *port), + ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_open.h b/include/cpp_core/interface/serial_open.h index 1746c4b..ddf30b4 100644 --- a/include/cpp_core/interface/serial_open.h +++ b/include/cpp_core/interface/serial_open.h @@ -4,28 +4,19 @@ #include "../serial_config.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Open and configure a serial port. - * - * The function attempts to open the device referenced by @p port and applies - * the line settings in @p config. @p port is interpreted as a UTF-8 encoded - * null-terminated string on all platforms. - * - * @param port Null-terminated device identifier (e.g. "COM3", "/dev/ttyUSB0"). Passing `nullptr` results in - * a failure. - * @param config Serial line configuration. Includes baud rate, data bits, - * parity, stop bits, and flow-control mode. Passing `nullptr` results in a failure. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return A positive opaque handle on success or a negative value from ::cpp_core::StatusCode on failure. - */ - MODULE_API auto serialOpen(const char *port, const cpp_core::SerialConfig *config, - ErrorCallbackT error_callback = nullptr) -> intptr_t; - -#ifdef __cplusplus -} -#endif +/** + * @brief Open and configure a serial port. + * + * The function attempts to open the device referenced by @p port and applies + * the line settings in @p config. @p port is interpreted as a UTF-8 encoded + * null-terminated string on all platforms. + * + * @param port Null-terminated device identifier (e.g. "COM3", "/dev/ttyUSB0"). Passing `nullptr` results in + * a failure. + * @param config Serial line configuration. Includes baud rate, data bits, + * parity, stop bits, and flow-control mode. Passing `nullptr` results in a failure. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return A positive opaque handle on success or a negative value from ::cpp_core::StatusCode on failure. + */ +MODULE_API auto serialOpen(const char *port, const cpp_core::SerialConfig *config, + ErrorCallbackT error_callback = nullptr) -> intptr_t; diff --git a/include/cpp_core/interface/serial_out_bytes_total.h b/include/cpp_core/interface/serial_out_bytes_total.h index d0c692f..4946ad2 100644 --- a/include/cpp_core/interface/serial_out_bytes_total.h +++ b/include/cpp_core/interface/serial_out_bytes_total.h @@ -3,20 +3,11 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Total number of bytes transmitted since the port was opened. - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Total number of bytes written or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialOutBytesTotal(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int64_t; - -#ifdef __cplusplus -} -#endif +/** + * @brief Total number of bytes transmitted since the port was opened. + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Total number of bytes written or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialOutBytesTotal(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int64_t; diff --git a/include/cpp_core/interface/serial_out_bytes_waiting.h b/include/cpp_core/interface/serial_out_bytes_waiting.h index 713946f..afe09fc 100644 --- a/include/cpp_core/interface/serial_out_bytes_waiting.h +++ b/include/cpp_core/interface/serial_out_bytes_waiting.h @@ -3,29 +3,20 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Return the number of bytes that have been accepted by the driver but not yet sent. - * - * Useful for gauging transmission progress in the background or for pacing - * further writes to avoid unbounded buffering. - * - * @code{.c} - * while (serialOutBytesWaiting(h) > 0) { - * usleep(1000); // wait 1 ms and poll again - * } - * @endcode - * - * @param handle Port handle. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Bytes still waiting in the TX FIFO or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialOutBytesWaiting(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Return the number of bytes that have been accepted by the driver but not yet sent. + * + * Useful for gauging transmission progress in the background or for pacing + * further writes to avoid unbounded buffering. + * + * @code{.c} + * while (serialOutBytesWaiting(h) > 0) { + * usleep(1000); // wait 1 ms and poll again + * } + * @endcode + * + * @param handle Port handle. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Bytes still waiting in the TX FIFO or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialOutBytesWaiting(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_read.h b/include/cpp_core/interface/serial_read.h index 1605eec..97dfb26 100644 --- a/include/cpp_core/interface/serial_read.h +++ b/include/cpp_core/interface/serial_read.h @@ -4,29 +4,20 @@ #include "../serial_config.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read raw bytes from the serial port. - * - * The call blocks for at most `timeout_config->timeout_ms` milliseconds while waiting for - * the FIRST byte. For every subsequent byte the individual timeout is - * calculated as `timeout_ms * multiplier` from @p timeout_config. - * - * @param handle Port handle. - * @param buffer Destination buffer (must not be `nullptr`). - * @param buffer_size Size of @p buffer in bytes (> 0). - * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Bytes read (0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialRead(int64_t handle, std::uint8_t *buffer, int buffer_size, - const cpp_core::SerialTimeoutConfig *timeout_config, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Read raw bytes from the serial port. + * + * The call blocks for at most `timeout_config->timeout_ms` milliseconds while waiting for + * the FIRST byte. For every subsequent byte the individual timeout is + * calculated as `timeout_ms * multiplier` from @p timeout_config. + * + * @param handle Port handle. + * @param buffer Destination buffer (must not be `nullptr`). + * @param buffer_size Size of @p buffer in bytes (> 0). + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Bytes read (0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialRead(int64_t handle, std::uint8_t *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, ErrorCallbackT error_callback = nullptr) + -> int; diff --git a/include/cpp_core/interface/serial_read_until_sequence.h b/include/cpp_core/interface/serial_read_until_sequence.h index 4dd85c4..b7d2d5d 100644 --- a/include/cpp_core/interface/serial_read_until_sequence.h +++ b/include/cpp_core/interface/serial_read_until_sequence.h @@ -4,32 +4,23 @@ #include "../serial_config.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Read until a specific byte sequence appears. - * - * Reads bytes using the same timeout semantics as serialRead() and stops as - * soon as @p sequence has been received. Sequences may contain zero bytes, - * and the complete terminator is included in the returned data. - * - * @param handle Port handle. - * @param buffer Destination buffer. - * @param buffer_size Capacity of @p buffer in bytes. - * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. - * @param sequence Terminating byte sequence (must not be `nullptr`). - * @param sequence_size Size of @p sequence in bytes (> 0). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Bytes read (including the terminator) or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialReadUntilSequence(int64_t handle, std::uint8_t *buffer, int buffer_size, - const cpp_core::SerialTimeoutConfig *timeout_config, - const std::uint8_t *sequence, int sequence_size, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Read until a specific byte sequence appears. + * + * Reads bytes using the same timeout semantics as serialRead() and stops as + * soon as @p sequence has been received. Sequences may contain zero bytes, + * and the complete terminator is included in the returned data. + * + * @param handle Port handle. + * @param buffer Destination buffer. + * @param buffer_size Capacity of @p buffer in bytes. + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. + * @param sequence Terminating byte sequence (must not be `nullptr`). + * @param sequence_size Size of @p sequence in bytes (> 0). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Bytes read (including the terminator) or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialReadUntilSequence(int64_t handle, std::uint8_t *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, + const std::uint8_t *sequence, int sequence_size, + ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_send_break.h b/include/cpp_core/interface/serial_send_break.h index d389f14..44a95af 100644 --- a/include/cpp_core/interface/serial_send_break.h +++ b/include/cpp_core/interface/serial_send_break.h @@ -3,31 +3,22 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Send a break condition on the serial line. - * - * A break is a sustained logic-LOW that lasts longer than a normal - * character frame. Many protocols rely on it: - * - * - **DMX512**: A break of >= 88 us marks the start of a new frame. - * - **LIN bus**: The master starts each frame with a 13-bit break. - * - **MODBUS RTU**: Some implementations use break for frame sync. - * - * The @p duration_ms parameter is a *minimum* - the actual break may be - * slightly longer due to OS scheduling. - * - * @param handle Port handle obtained from serialOpen(). - * @param duration_ms Break duration in milliseconds (> 0). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSendBreak(int64_t handle, int duration_ms, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Send a break condition on the serial line. + * + * A break is a sustained logic-LOW that lasts longer than a normal + * character frame. Many protocols rely on it: + * + * - **DMX512**: A break of >= 88 us marks the start of a new frame. + * - **LIN bus**: The master starts each frame with a 13-bit break. + * - **MODBUS RTU**: Some implementations use break for frame sync. + * + * The @p duration_ms parameter is a *minimum* - the actual break may be + * slightly longer due to OS scheduling. + * + * @param handle Port handle obtained from serialOpen(). + * @param duration_ms Break duration in milliseconds (> 0). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSendBreak(int64_t handle, int duration_ms, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_set_baudrate.h b/include/cpp_core/interface/serial_set_baudrate.h index fbd615b..52d8c2b 100644 --- a/include/cpp_core/interface/serial_set_baudrate.h +++ b/include/cpp_core/interface/serial_set_baudrate.h @@ -3,29 +3,19 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Change the baud rate of an already-open serial port. - * - * The new rate takes effect immediately without closing and re-opening the - * port. All other line settings (data bits, parity, stop bits, flow control) - * remain unchanged. - * - * Typical use-case: a bootloader handshake starts at a safe 9600 baud and - * then both sides switch to a higher speed for the actual data transfer. - * - * @param handle Port handle obtained from serialOpen(). - * @param baudrate New baud rate in bit/s (>= 300). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSetBaudrate(int64_t handle, int baudrate, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Change the baud rate of an already-open serial port. + * + * The new rate takes effect immediately without closing and re-opening the + * port. All other line settings (data bits, parity, stop bits, flow control) + * remain unchanged. + * + * Typical use-case: a bootloader handshake starts at a safe 9600 baud and + * then both sides switch to a higher speed for the actual data transfer. + * + * @param handle Port handle obtained from serialOpen(). + * @param baudrate New baud rate in bit/s (>= 300). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSetBaudrate(int64_t handle, int baudrate, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_set_data_bits.h b/include/cpp_core/interface/serial_set_data_bits.h index 4aec53b..62b4344 100644 --- a/include/cpp_core/interface/serial_set_data_bits.h +++ b/include/cpp_core/interface/serial_set_data_bits.h @@ -4,24 +4,15 @@ #include "../strong_types.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Change the number of data bits on an already-open serial port. - * - * Takes effect immediately. All other line settings remain unchanged. - * - * @param handle Port handle obtained from serialOpen(). - * @param data_bits Number of data bits. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSetDataBits(int64_t handle, cpp_core::DataBits data_bits, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Change the number of data bits on an already-open serial port. + * + * Takes effect immediately. All other line settings remain unchanged. + * + * @param handle Port handle obtained from serialOpen(). + * @param data_bits Number of data bits. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSetDataBits(int64_t handle, cpp_core::DataBits data_bits, ErrorCallbackT error_callback = nullptr) + -> int; diff --git a/include/cpp_core/interface/serial_set_dtr.h b/include/cpp_core/interface/serial_set_dtr.h index 97c4c5e..0c0d35d 100644 --- a/include/cpp_core/interface/serial_set_dtr.h +++ b/include/cpp_core/interface/serial_set_dtr.h @@ -3,26 +3,17 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Set or clear the Data Terminal Ready (DTR) modem control line. - * - * DTR is commonly used for: - * - Signalling readiness to the remote device. - * - Triggering a board reset on Arduino-compatible hardware. - * - Half-duplex direction control on RS-485 adapters. - * - * @param handle Port handle obtained from serialOpen(). - * @param state Non-zero to assert (HIGH), zero to de-assert (LOW). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSetDtr(int64_t handle, int state, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Set or clear the Data Terminal Ready (DTR) modem control line. + * + * DTR is commonly used for: + * - Signalling readiness to the remote device. + * - Triggering a board reset on Arduino-compatible hardware. + * - Half-duplex direction control on RS-485 adapters. + * + * @param handle Port handle obtained from serialOpen(). + * @param state Non-zero to assert (HIGH), zero to de-assert (LOW). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSetDtr(int64_t handle, int state, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_set_error_callback.h b/include/cpp_core/interface/serial_set_error_callback.h index 46e28a2..23fc278 100644 --- a/include/cpp_core/interface/serial_set_error_callback.h +++ b/include/cpp_core/interface/serial_set_error_callback.h @@ -2,21 +2,12 @@ #include "../error_callback.h" #include "../module_api.h" -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Register a callback that is invoked whenever an error occurs. - * - * Pass `nullptr` to disable the callback. - * - * @param error_callback Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. Gets - * invoked on any error. - */ - MODULE_API void serialSetErrorCallback(ErrorCallbackT error_callback); - -#ifdef __cplusplus -} -#endif +/** + * @brief Register a callback that is invoked whenever an error occurs. + * + * Pass `nullptr` to disable the callback. + * + * @param error_callback Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. Gets + * invoked on any error. + */ +MODULE_API void serialSetErrorCallback(ErrorCallbackT error_callback); diff --git a/include/cpp_core/interface/serial_set_flow_control.h b/include/cpp_core/interface/serial_set_flow_control.h index 66f8bd9..a9131ff 100644 --- a/include/cpp_core/interface/serial_set_flow_control.h +++ b/include/cpp_core/interface/serial_set_flow_control.h @@ -4,33 +4,24 @@ #include "../strong_types.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Configure the flow-control mode for an open serial port. - * - * Flow control prevents buffer overruns when one side is slower than the - * other. Three modes are supported: - * - * | @p flow_mode | Meaning | - * |------------------------------|----------------------------------------------| - * | `FlowControl::kNone` | No flow control. | - * | `FlowControl::kRtsCts` | Hardware RTS/CTS flow control. | - * | `FlowControl::kXonXoff` | Software XON/XOFF flow control. | - * - * Changing the mode on an already-open port takes effect immediately. - * - * @param handle Port handle obtained from serialOpen(). - * @param flow_mode Flow-control mode. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSetFlowControl(int64_t handle, cpp_core::FlowControl flow_mode, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Configure the flow-control mode for an open serial port. + * + * Flow control prevents buffer overruns when one side is slower than the + * other. Three modes are supported: + * + * | @p flow_mode | Meaning | + * |------------------------------|----------------------------------------------| + * | `FlowControl::kNone` | No flow control. | + * | `FlowControl::kRtsCts` | Hardware RTS/CTS flow control. | + * | `FlowControl::kXonXoff` | Software XON/XOFF flow control. | + * + * Changing the mode on an already-open port takes effect immediately. + * + * @param handle Port handle obtained from serialOpen(). + * @param flow_mode Flow-control mode. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSetFlowControl(int64_t handle, cpp_core::FlowControl flow_mode, + ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_set_parity.h b/include/cpp_core/interface/serial_set_parity.h index 049446c..cac2775 100644 --- a/include/cpp_core/interface/serial_set_parity.h +++ b/include/cpp_core/interface/serial_set_parity.h @@ -4,24 +4,15 @@ #include "../strong_types.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Change the parity setting on an already-open serial port. - * - * Takes effect immediately. All other line settings remain unchanged. - * - * @param handle Port handle obtained from serialOpen(). - * @param parity Parity mode. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSetParity(int64_t handle, cpp_core::Parity parity, ErrorCallbackT error_callback = nullptr) - -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Change the parity setting on an already-open serial port. + * + * Takes effect immediately. All other line settings remain unchanged. + * + * @param handle Port handle obtained from serialOpen(). + * @param parity Parity mode. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSetParity(int64_t handle, cpp_core::Parity parity, ErrorCallbackT error_callback = nullptr) + -> int; diff --git a/include/cpp_core/interface/serial_set_read_callback.h b/include/cpp_core/interface/serial_set_read_callback.h index 2b45ae0..4a191bd 100644 --- a/include/cpp_core/interface/serial_set_read_callback.h +++ b/include/cpp_core/interface/serial_set_read_callback.h @@ -1,20 +1,11 @@ #pragma once #include "../module_api.h" -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Register a callback that is invoked whenever bytes are read. - * - * Pass `nullptr` to disable the callback. - * - * @param callback Function receiving the number of bytes that have just been read. - */ - MODULE_API void serialSetReadCallback(void (*callback_fn)(int bytes_read)); - -#ifdef __cplusplus -} -#endif +/** + * @brief Register a callback that is invoked whenever bytes are read. + * + * Pass `nullptr` to disable the callback. + * + * @param callback Function receiving the number of bytes that have just been read. + */ +MODULE_API void serialSetReadCallback(void (*callback_fn)(int bytes_read)); diff --git a/include/cpp_core/interface/serial_set_rts.h b/include/cpp_core/interface/serial_set_rts.h index e6f2bf9..faa9ce0 100644 --- a/include/cpp_core/interface/serial_set_rts.h +++ b/include/cpp_core/interface/serial_set_rts.h @@ -3,26 +3,17 @@ #include "../module_api.h" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Set or clear the Request To Send (RTS) modem control line. - * - * RTS is typically used for hardware flow control (RTS/CTS) or - * as a transmit-enable signal in half-duplex RS-485 setups. When - * hardware flow control is **not** enabled via serialSetFlowControl(), - * this function gives manual control over the line. - * - * @param handle Port handle obtained from serialOpen(). - * @param state Non-zero to assert (HIGH), zero to de-assert (LOW). - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSetRts(int64_t handle, int state, ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Set or clear the Request To Send (RTS) modem control line. + * + * RTS is typically used for hardware flow control (RTS/CTS) or + * as a transmit-enable signal in half-duplex RS-485 setups. When + * hardware flow control is **not** enabled via serialSetFlowControl(), + * this function gives manual control over the line. + * + * @param handle Port handle obtained from serialOpen(). + * @param state Non-zero to assert (HIGH), zero to de-assert (LOW). + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSetRts(int64_t handle, int state, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/interface/serial_set_stop_bits.h b/include/cpp_core/interface/serial_set_stop_bits.h index f199c59..f64ba9a 100644 --- a/include/cpp_core/interface/serial_set_stop_bits.h +++ b/include/cpp_core/interface/serial_set_stop_bits.h @@ -4,24 +4,15 @@ #include "../strong_types.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Change the stop-bit setting on an already-open serial port. - * - * Takes effect immediately. All other line settings remain unchanged. - * - * @param handle Port handle obtained from serialOpen(). - * @param stop_bits Stop-bit mode. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialSetStopBits(int64_t handle, cpp_core::StopBits stop_bits, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Change the stop-bit setting on an already-open serial port. + * + * Takes effect immediately. All other line settings remain unchanged. + * + * @param handle Port handle obtained from serialOpen(). + * @param stop_bits Stop-bit mode. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialSetStopBits(int64_t handle, cpp_core::StopBits stop_bits, ErrorCallbackT error_callback = nullptr) + -> int; diff --git a/include/cpp_core/interface/serial_set_write_callback.h b/include/cpp_core/interface/serial_set_write_callback.h index a521e40..ff1fcfe 100644 --- a/include/cpp_core/interface/serial_set_write_callback.h +++ b/include/cpp_core/interface/serial_set_write_callback.h @@ -1,20 +1,11 @@ #pragma once #include "../module_api.h" -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Register a callback that is invoked whenever bytes are written. - * - * Pass `nullptr` to disable the callback. - * - * @param callback Function receiving the number of bytes that have just been written. - */ - MODULE_API void serialSetWriteCallback(void (*callback_fn)(int bytes_written)); - -#ifdef __cplusplus -} -#endif +/** + * @brief Register a callback that is invoked whenever bytes are written. + * + * Pass `nullptr` to disable the callback. + * + * @param callback Function receiving the number of bytes that have just been written. + */ +MODULE_API void serialSetWriteCallback(void (*callback_fn)(int bytes_written)); diff --git a/include/cpp_core/interface/serial_write.h b/include/cpp_core/interface/serial_write.h index acca526..2d2678d 100644 --- a/include/cpp_core/interface/serial_write.h +++ b/include/cpp_core/interface/serial_write.h @@ -4,28 +4,19 @@ #include "../serial_config.hpp" #include -#ifdef __cplusplus -extern "C" -{ -#endif - - /** - * @brief Write raw bytes to the serial port. - * - * Timeout handling mirrors serialRead(): `timeout_config->timeout_ms` applies - * to the first byte, `timeout_ms * multiplier` to every subsequent one. - * - * @param handle Port handle. - * @param buffer Data to transmit (must not be `nullptr`). - * @param buffer_size Number of bytes in @p buffer (> 0). - * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. - * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Bytes written (may be 0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. - */ - MODULE_API auto serialWrite(int64_t handle, const std::uint8_t *buffer, int buffer_size, - const cpp_core::SerialTimeoutConfig *timeout_config, - ErrorCallbackT error_callback = nullptr) -> int; - -#ifdef __cplusplus -} -#endif +/** + * @brief Write raw bytes to the serial port. + * + * Timeout handling mirrors serialRead(): `timeout_config->timeout_ms` applies + * to the first byte, `timeout_ms * multiplier` to every subsequent one. + * + * @param handle Port handle. + * @param buffer Data to transmit (must not be `nullptr`). + * @param buffer_size Number of bytes in @p buffer (> 0). + * @param timeout_config Timeout settings for this operation. Passing `nullptr` results in a failure. + * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. + * @return Bytes written (may be 0 on timeout) or a negative error code from ::cpp_core::StatusCode on error. + */ +MODULE_API auto serialWrite(int64_t handle, const std::uint8_t *buffer, int buffer_size, + const cpp_core::SerialTimeoutConfig *timeout_config, + ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/module_api.h b/include/cpp_core/module_api.h index e066a42..82478d4 100644 --- a/include/cpp_core/module_api.h +++ b/include/cpp_core/module_api.h @@ -1,11 +1,15 @@ #pragma once +/** + * Give an exported function C language linkage and platform-specific symbol visibility. + * This macro is intended for C++ declarations and definitions only. + */ #if defined(_WIN32) || defined(__CYGWIN__) #ifdef cpp_bindings_windows_EXPORTS -#define MODULE_API __declspec(dllexport) +#define MODULE_API extern "C" __declspec(dllexport) #else -#define MODULE_API __declspec(dllimport) +#define MODULE_API extern "C" __declspec(dllimport) #endif #else -#define MODULE_API __attribute__((visibility("default"))) +#define MODULE_API extern "C" __attribute__((visibility("default"))) #endif From ae8c86634b35a0c938c703a5172902d360be04a2 Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 15:09:17 +0200 Subject: [PATCH 10/14] feat: introduce PortEvent enum and update serialMonitorPorts callback signature --- include/cpp_core/interface/serial_monitor_ports.h | 9 +++++---- include/cpp_core/reflection.test.cpp | 2 ++ include/cpp_core/serial_interface.test.cpp | 3 +++ include/cpp_core/strong_types.hpp | 9 +++++++++ include/cpp_core/strong_types.test.cpp | 1 + 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/cpp_core/interface/serial_monitor_ports.h b/include/cpp_core/interface/serial_monitor_ports.h index db5999b..3806f3d 100644 --- a/include/cpp_core/interface/serial_monitor_ports.h +++ b/include/cpp_core/interface/serial_monitor_ports.h @@ -1,17 +1,18 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" /** * @brief Start or stop port attach/detach notifications. * - * Passing a non-null callback starts monitoring and invokes it with `event = 1` - * for attach and `event = 0` for detach notifications. Passing `nullptr` - * stops a previously running monitor. + * Passing a non-null callback starts monitoring and invokes it with + * ::cpp_core::PortEvent::kAttached or ::cpp_core::PortEvent::kDetached. + * Passing `nullptr` stops a previously running monitor. * * @param callback_fn Notification callback or `nullptr` to stop monitoring. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. */ -MODULE_API auto serialMonitorPorts(void (*callback_fn)(int event, const char *port), +MODULE_API auto serialMonitorPorts(void (*callback_fn)(cpp_core::PortEvent event, const char *port), ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/reflection.test.cpp b/include/cpp_core/reflection.test.cpp index 40b575b..3eee04f 100644 --- a/include/cpp_core/reflection.test.cpp +++ b/include/cpp_core/reflection.test.cpp @@ -17,10 +17,12 @@ static_assert(cpp_core::reflection::enumeratorCount() == 4); static_assert(cpp_core::reflection::enumeratorCount() == 3); static_assert(cpp_core::reflection::enumeratorCount() == 2); static_assert(cpp_core::reflection::enumeratorCount() == 3); +static_assert(cpp_core::reflection::enumeratorCount() == 2); static_assert(cpp_core::reflection::enumeratorName() == "kEight"); static_assert(cpp_core::reflection::enumeratorName() == "kNone"); static_assert(cpp_core::reflection::enumeratorName() == "kEven"); static_assert(cpp_core::reflection::enumerator_name_v == "kXonXoff"); +static_assert(cpp_core::reflection::enumerator_name_v == "kDetached"); static_assert(cpp_core::reflection::hasPubliclyReflectableFields()); static_assert(cpp_core::reflection::publicFieldCount() == 5); static_assert(cpp_core::reflection::publicFieldName() == "parity"); diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index 617fcfa..10debe9 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -19,6 +19,8 @@ using SetDataBitsFn = int (*)(int64_t, DataBits, ErrorCallbackT); using SetParityFn = int (*)(int64_t, Parity, ErrorCallbackT); using SetStopBitsFn = int (*)(int64_t, StopBits, ErrorCallbackT); using SetFlowControlFn = int (*)(int64_t, FlowControl, ErrorCallbackT); +using MonitorCallback = void (*)(PortEvent, const char *); +using MonitorPortsFn = int (*)(MonitorCallback, ErrorCallbackT); static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -29,6 +31,7 @@ static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); +static_assert(std::is_same_v); static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); diff --git a/include/cpp_core/strong_types.hpp b/include/cpp_core/strong_types.hpp index 408c3d7..fb8d1a5 100644 --- a/include/cpp_core/strong_types.hpp +++ b/include/cpp_core/strong_types.hpp @@ -112,6 +112,15 @@ enum class FlowControl : int kXonXoff = 2, ///< Use software XON/XOFF flow control. }; +/** + * Port lifecycle event reported by serialMonitorPorts(). + */ +enum class PortEvent : int +{ + kDetached = 0, ///< A serial port was removed from the system. + kAttached = 1, ///< A serial port became available. +}; + template requires std::is_enum_v [[nodiscard]] constexpr auto toInt(Enum value) noexcept -> int diff --git a/include/cpp_core/strong_types.test.cpp b/include/cpp_core/strong_types.test.cpp index fa171af..119e7e5 100644 --- a/include/cpp_core/strong_types.test.cpp +++ b/include/cpp_core/strong_types.test.cpp @@ -9,5 +9,6 @@ static_assert(toInt(DataBits::kEight) == 8); static_assert(toInt(Parity::kOdd) == 2); static_assert(toInt(StopBits::kTwo) == 2); static_assert(toInt(FlowControl::kXonXoff) == 2); +static_assert(toInt(PortEvent::kAttached) == 1); } // namespace cpp_core::tests::strong_types From fff829296c1e8a43512a9be13db56c16d75d55bb Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 16:44:54 +0200 Subject: [PATCH 11/14] feat: add serialSetEventCallback function and update related types for event handling --- ...l_monitor_ports.h => serial_set_event_callback.h} | 8 ++++---- include/cpp_core/serial.h | 12 ++++++------ include/cpp_core/serial_interface.test.cpp | 6 +++--- include/cpp_core/strong_types.hpp | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) rename include/cpp_core/interface/{serial_monitor_ports.h => serial_set_event_callback.h} (62%) diff --git a/include/cpp_core/interface/serial_monitor_ports.h b/include/cpp_core/interface/serial_set_event_callback.h similarity index 62% rename from include/cpp_core/interface/serial_monitor_ports.h rename to include/cpp_core/interface/serial_set_event_callback.h index 3806f3d..a9c1bf9 100644 --- a/include/cpp_core/interface/serial_monitor_ports.h +++ b/include/cpp_core/interface/serial_set_event_callback.h @@ -4,15 +4,15 @@ #include "../strong_types.hpp" /** - * @brief Start or stop port attach/detach notifications. + * @brief Register or clear the serial-port lifecycle event callback. * * Passing a non-null callback starts monitoring and invokes it with * ::cpp_core::PortEvent::kAttached or ::cpp_core::PortEvent::kDetached. - * Passing `nullptr` stops a previously running monitor. + * Passing `nullptr` clears the callback and stops monitoring. * * @param callback_fn Notification callback or `nullptr` to stop monitoring. * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. */ -MODULE_API auto serialMonitorPorts(void (*callback_fn)(cpp_core::PortEvent event, const char *port), - ErrorCallbackT error_callback = nullptr) -> int; +MODULE_API auto serialSetEventCallback(void (*callback_fn)(cpp_core::PortEvent event, const char *port), + ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/serial.h b/include/cpp_core/serial.h index 7862b1b..7a1d09c 100644 --- a/include/cpp_core/serial.h +++ b/include/cpp_core/serial.h @@ -13,38 +13,38 @@ #include "interface/serial_in_bytes_total.h" #include "interface/serial_in_bytes_waiting.h" #include "interface/serial_list_ports.h" -#include "interface/serial_monitor_ports.h" #include "interface/serial_open.h" #include "interface/serial_out_bytes_total.h" #include "interface/serial_out_bytes_waiting.h" #include "interface/serial_read.h" #include "interface/serial_read_until_sequence.h" #include "interface/serial_set_error_callback.h" +#include "interface/serial_set_event_callback.h" #include "interface/serial_set_read_callback.h" #include "interface/serial_set_write_callback.h" #include "interface/serial_write.h" // Modem line control -#include "interface/serial_set_dtr.h" -#include "interface/serial_set_rts.h" #include "interface/serial_get_cts.h" -#include "interface/serial_get_dsr.h" #include "interface/serial_get_dcd.h" +#include "interface/serial_get_dsr.h" #include "interface/serial_get_ri.h" +#include "interface/serial_set_dtr.h" +#include "interface/serial_set_rts.h" // Line-setting getters #include "interface/serial_get_baudrate.h" #include "interface/serial_get_data_bits.h" +#include "interface/serial_get_flow_control.h" #include "interface/serial_get_parity.h" #include "interface/serial_get_stop_bits.h" -#include "interface/serial_get_flow_control.h" // Line-setting setters #include "interface/serial_set_baudrate.h" #include "interface/serial_set_data_bits.h" +#include "interface/serial_set_flow_control.h" #include "interface/serial_set_parity.h" #include "interface/serial_set_stop_bits.h" -#include "interface/serial_set_flow_control.h" // Extended control #include "interface/serial_send_break.h" diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index 10debe9..eb4dbe6 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -19,8 +19,8 @@ using SetDataBitsFn = int (*)(int64_t, DataBits, ErrorCallbackT); using SetParityFn = int (*)(int64_t, Parity, ErrorCallbackT); using SetStopBitsFn = int (*)(int64_t, StopBits, ErrorCallbackT); using SetFlowControlFn = int (*)(int64_t, FlowControl, ErrorCallbackT); -using MonitorCallback = void (*)(PortEvent, const char *); -using MonitorPortsFn = int (*)(MonitorCallback, ErrorCallbackT); +using EventCallback = void (*)(PortEvent, const char *); +using SetEventCallbackFn = int (*)(EventCallback, ErrorCallbackT); static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -31,7 +31,7 @@ static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); -static_assert(std::is_same_v); +static_assert(std::is_same_v); static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); diff --git a/include/cpp_core/strong_types.hpp b/include/cpp_core/strong_types.hpp index fb8d1a5..768dc9a 100644 --- a/include/cpp_core/strong_types.hpp +++ b/include/cpp_core/strong_types.hpp @@ -113,7 +113,7 @@ enum class FlowControl : int }; /** - * Port lifecycle event reported by serialMonitorPorts(). + * Port lifecycle event reported by serialSetEventCallback(). */ enum class PortEvent : int { From b9aaeba5f627ce1ae70ab68322638fc020f763fd Mon Sep 17 00:00:00 2001 From: Katze719 Date: Wed, 2 Sep 2026 22:16:19 +0200 Subject: [PATCH 12/14] feat: add serialWaitForDrain function and update related tests and headers --- .../interface/{serial_drain.h => serial_wait_for_drain.h} | 4 ++-- include/cpp_core/serial.h | 2 +- include/cpp_core/serial_interface.test.cpp | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) rename include/cpp_core/interface/{serial_drain.h => serial_wait_for_drain.h} (89%) diff --git a/include/cpp_core/interface/serial_drain.h b/include/cpp_core/interface/serial_wait_for_drain.h similarity index 89% rename from include/cpp_core/interface/serial_drain.h rename to include/cpp_core/interface/serial_wait_for_drain.h index 99f68e8..d36463d 100644 --- a/include/cpp_core/interface/serial_drain.h +++ b/include/cpp_core/interface/serial_wait_for_drain.h @@ -18,7 +18,7 @@ * // Send a frame and make sure it actually hits the line * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 50, .multiplier = 1}; * serialWrite(h, frame, frame_len, &timeout); - * if (serialDrain(h) < 0) { + * if (serialWaitForDrain(h) < 0) { * fprintf(stderr, "drain failed\n"); * } * @endcode @@ -27,4 +27,4 @@ * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. * @return 0 on success or a negative error code from ::cpp_core::StatusCode on error. */ -MODULE_API auto serialDrain(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; +MODULE_API auto serialWaitForDrain(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; diff --git a/include/cpp_core/serial.h b/include/cpp_core/serial.h index 7a1d09c..b5949a2 100644 --- a/include/cpp_core/serial.h +++ b/include/cpp_core/serial.h @@ -9,7 +9,7 @@ #include "interface/serial_clear_buffer_in.h" #include "interface/serial_clear_buffer_out.h" #include "interface/serial_close.h" -#include "interface/serial_drain.h" +#include "interface/serial_wait_for_drain.h" #include "interface/serial_in_bytes_total.h" #include "interface/serial_in_bytes_waiting.h" #include "interface/serial_list_ports.h" diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index eb4dbe6..d0c9e38 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -10,6 +10,7 @@ namespace cpp_core::tests::serial_interface { using MetaFn = void (*)(Meta *); +using WaitForDrainFn = int (*)(int64_t, ErrorCallbackT); using OpenFn = intptr_t (*)(const char *, const SerialConfig *, ErrorCallbackT); using ReadFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); using ReadUntilSequenceFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, const std::uint8_t *, @@ -23,6 +24,7 @@ using EventCallback = void (*)(PortEvent, const char *); using SetEventCallbackFn = int (*)(EventCallback, ErrorCallbackT); static_assert(std::is_same_v); +static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); From c4f689771951c3267f73d706a13dcce62ad053fa Mon Sep 17 00:00:00 2001 From: Katze719 Date: Thu, 3 Sep 2026 09:03:55 +0200 Subject: [PATCH 13/14] feat: update serial getter functions to return strong types and enhance type safety --- include/cpp_core/interface/serial_get_data_bits.h | 6 ++++-- include/cpp_core/interface/serial_get_flow_control.h | 6 ++++-- include/cpp_core/interface/serial_get_parity.h | 6 ++++-- include/cpp_core/interface/serial_get_stop_bits.h | 6 ++++-- include/cpp_core/serial_interface.test.cpp | 8 ++++++++ 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/cpp_core/interface/serial_get_data_bits.h b/include/cpp_core/interface/serial_get_data_bits.h index 5817c93..8df7f8a 100644 --- a/include/cpp_core/interface/serial_get_data_bits.h +++ b/include/cpp_core/interface/serial_get_data_bits.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include /** @@ -8,6 +9,7 @@ * * @param handle Port handle obtained from serialOpen(). * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return Current data bits (5-8) or a negative error code from ::cpp_core::StatusCode. + * @return Current data-bit setting. On error, the underlying integer value is a negative error code from + * ::cpp_core::StatusCode. */ -MODULE_API auto serialGetDataBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; +MODULE_API auto serialGetDataBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> cpp_core::DataBits; diff --git a/include/cpp_core/interface/serial_get_flow_control.h b/include/cpp_core/interface/serial_get_flow_control.h index 2db7e48..1b970e0 100644 --- a/include/cpp_core/interface/serial_get_flow_control.h +++ b/include/cpp_core/interface/serial_get_flow_control.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include /** @@ -8,6 +9,7 @@ * * @param handle Port handle obtained from serialOpen(). * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 = none, 1 = RTS/CTS, 2 = XON/XOFF, or a negative error code from ::cpp_core::StatusCode. + * @return Current flow-control mode. On error, the underlying integer value is a negative error code from + * ::cpp_core::StatusCode. */ -MODULE_API auto serialGetFlowControl(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; +MODULE_API auto serialGetFlowControl(int64_t handle, ErrorCallbackT error_callback = nullptr) -> cpp_core::FlowControl; diff --git a/include/cpp_core/interface/serial_get_parity.h b/include/cpp_core/interface/serial_get_parity.h index 199bf27..3d1c601 100644 --- a/include/cpp_core/interface/serial_get_parity.h +++ b/include/cpp_core/interface/serial_get_parity.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include /** @@ -8,6 +9,7 @@ * * @param handle Port handle obtained from serialOpen(). * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 = none, 1 = even, 2 = odd, or a negative error code from ::cpp_core::StatusCode. + * @return Current parity mode. On error, the underlying integer value is a negative error code from + * ::cpp_core::StatusCode. */ -MODULE_API auto serialGetParity(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; +MODULE_API auto serialGetParity(int64_t handle, ErrorCallbackT error_callback = nullptr) -> cpp_core::Parity; diff --git a/include/cpp_core/interface/serial_get_stop_bits.h b/include/cpp_core/interface/serial_get_stop_bits.h index 5c4ab5d..8fb49f8 100644 --- a/include/cpp_core/interface/serial_get_stop_bits.h +++ b/include/cpp_core/interface/serial_get_stop_bits.h @@ -1,6 +1,7 @@ #pragma once #include "../error_callback.h" #include "../module_api.h" +#include "../strong_types.hpp" #include /** @@ -8,6 +9,7 @@ * * @param handle Port handle obtained from serialOpen(). * @param error_callback [optional] Callback to invoke on error. Defined in error_callback.h. Default is `nullptr`. - * @return 0 = 1 stop bit, 2 = 2 stop bits, or a negative error code from ::cpp_core::StatusCode. + * @return Current stop-bit setting. On error, the underlying integer value is a negative error code from + * ::cpp_core::StatusCode. */ -MODULE_API auto serialGetStopBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> int; +MODULE_API auto serialGetStopBits(int64_t handle, ErrorCallbackT error_callback = nullptr) -> cpp_core::StopBits; diff --git a/include/cpp_core/serial_interface.test.cpp b/include/cpp_core/serial_interface.test.cpp index d0c9e38..53d2e49 100644 --- a/include/cpp_core/serial_interface.test.cpp +++ b/include/cpp_core/serial_interface.test.cpp @@ -16,6 +16,10 @@ using ReadFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig * using ReadUntilSequenceFn = int (*)(int64_t, std::uint8_t *, int, const SerialTimeoutConfig *, const std::uint8_t *, int, ErrorCallbackT); using WriteFn = int (*)(int64_t, const std::uint8_t *, int, const SerialTimeoutConfig *, ErrorCallbackT); +using GetDataBitsFn = DataBits (*)(int64_t, ErrorCallbackT); +using GetParityFn = Parity (*)(int64_t, ErrorCallbackT); +using GetStopBitsFn = StopBits (*)(int64_t, ErrorCallbackT); +using GetFlowControlFn = FlowControl (*)(int64_t, ErrorCallbackT); using SetDataBitsFn = int (*)(int64_t, DataBits, ErrorCallbackT); using SetParityFn = int (*)(int64_t, Parity, ErrorCallbackT); using SetStopBitsFn = int (*)(int64_t, StopBits, ErrorCallbackT); @@ -29,6 +33,10 @@ static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(std::is_same_v); From 5d62e1c37290c81b5f7fd902a91c7131a6a8d8d5 Mon Sep 17 00:00:00 2001 From: Katze719 Date: Sun, 6 Sep 2026 17:43:48 +0200 Subject: [PATCH 14/14] feat: clarify documentation for serialInBytesWaiting function --- include/cpp_core/interface/serial_in_bytes_waiting.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cpp_core/interface/serial_in_bytes_waiting.h b/include/cpp_core/interface/serial_in_bytes_waiting.h index c66ac2f..6430539 100644 --- a/include/cpp_core/interface/serial_in_bytes_waiting.h +++ b/include/cpp_core/interface/serial_in_bytes_waiting.h @@ -4,7 +4,7 @@ #include /** - * @brief Query how many bytes can be read *immediately* without blocking. + * @brief Query how many bytes are immediately available to read. * * The number reflects the size of the driver's RX FIFO **after** accounting * for data already consumed by the application. A value of `0` therefore @@ -14,7 +14,7 @@ * constexpr cpp_core::SerialTimeoutConfig timeout{.timeout_ms = 0, .multiplier = 1}; * int pending = serialInBytesWaiting(h); * if (pending > 0) { - * serialRead(h, buf, pending, &timeout); // non-blocking read + * serialRead(h, buf, pending, &timeout); // returns immediately * } * @endcode *