From d24d5bc180ba4288c148b5dca051fb61101fbfa9 Mon Sep 17 00:00:00 2001 From: qzhhhi Date: Sun, 21 Jun 2026 11:20:22 +0000 Subject: [PATCH] fix(protocol): Fail invalid routes and simplify GPIO payloads - Propagate deserializer callback failures for CAN, UART, and GPIO so unexpected DataId values, channel indexes, and unsupported GPIO configurations abort the current transfer instead of being logged and ignored. - Collapse GPIO write and read-result packets into shared value payloads and rename GPIO config payload enums to reflect protocol semantics. Keep timestamped digital samples for uplink reads, but reject timestamped digital writes on host and firmware downlink paths. --- core/src/protocol/deserializer.cpp | 76 +++++--------- core/src/protocol/deserializer.hpp | 14 +-- core/src/protocol/protocol.hpp | 13 +-- core/src/protocol/serializer.hpp | 110 +++++---------------- firmware/c_board/app/src/gpio/gpio.hpp | 2 +- firmware/c_board/app/src/usb/vendor.hpp | 54 +++++----- firmware/rmcs_board/app/src/gpio/gpio.hpp | 2 +- firmware/rmcs_board/app/src/usb/vendor.hpp | 62 +++++++----- host/src/protocol/handler.cpp | 52 +++++++--- 9 files changed, 168 insertions(+), 217 deletions(-) diff --git a/core/src/protocol/deserializer.cpp b/core/src/protocol/deserializer.cpp index f746abb..f0b9ff2 100644 --- a/core/src/protocol/deserializer.cpp +++ b/core/src/protocol/deserializer.cpp @@ -108,9 +108,7 @@ coroutine::LifoTask Deserializer::process_can_field(FieldId field_id) { data_view.can_data = std::span{}; } - callback_.can_deserialized_callback(field_id, data_view); - - co_return true; + co_return callback_.can_deserialized_callback(field_id, data_view); } coroutine::LifoTask Deserializer::process_uart_field(FieldId field_id) { @@ -147,9 +145,7 @@ coroutine::LifoTask Deserializer::process_uart_field(FieldId field_id) { data_view.uart_data = std::span{}; } - callback_.uart_deserialized_callback(field_id, data_view); - - co_return true; + co_return callback_.uart_deserialized_callback(field_id, data_view); } coroutine::LifoTask Deserializer::process_gpio_field(FieldId) { @@ -169,16 +165,25 @@ coroutine::LifoTask Deserializer::process_gpio_field(FieldId) { } switch (payload_type) { - case GpioHeader::PayloadEnum::kDigitalWriteLow: - case GpioHeader::PayloadEnum::kDigitalWriteHigh: { - if (timestamped) [[unlikely]] - co_return false; + case GpioHeader::PayloadEnum::kDigitalLow: + case GpioHeader::PayloadEnum::kDigitalHigh: { data::GpioDigitalDataView data_view{}; - data_view.high = payload_type == GpioHeader::PayloadEnum::kDigitalWriteHigh; - callback_.gpio_digital_data_deserialized_callback(channel_index, data_view); + data_view.high = payload_type == GpioHeader::PayloadEnum::kDigitalHigh; + if (timestamped) { + const auto* payload_bytes = + co_await peek_bytes(sizeof(GpioDigitalReadTimestampPayload)); + if (!payload_bytes) [[unlikely]] + co_return false; + auto payload = GpioDigitalReadTimestampPayload::CRef{payload_bytes}; + data_view.timestamp_quarter_us = + payload.get(); + consume_peeked(); + } + if (!callback_.gpio_digital_data_deserialized_callback(channel_index, data_view)) + co_return false; break; } - case GpioHeader::PayloadEnum::kAnalogWrite: { + case GpioHeader::PayloadEnum::kAnalog: { if (timestamped) [[unlikely]] co_return false; const auto* payload_bytes = co_await peek_bytes(sizeof(GpioAnalogPayload)); @@ -190,11 +195,12 @@ coroutine::LifoTask Deserializer::process_gpio_field(FieldId) { data_view.value = payload.get(); consume_peeked(); - callback_.gpio_analog_data_deserialized_callback(channel_index, data_view); + if (!callback_.gpio_analog_data_deserialized_callback(channel_index, data_view)) + co_return false; break; } - case GpioHeader::PayloadEnum::kDigitalRead: - case GpioHeader::PayloadEnum::kAnalogRead: { + case GpioHeader::PayloadEnum::kDigitalReadConfig: + case GpioHeader::PayloadEnum::kAnalogReadConfig: { const auto* payload_bytes = co_await peek_bytes(sizeof(GpioReadConfigPayload)); if (!payload_bytes) [[unlikely]] co_return false; @@ -213,45 +219,15 @@ coroutine::LifoTask Deserializer::process_gpio_field(FieldId) { && data_view.pull != data::GpioPull::kDown) co_return false; - if (payload_type == GpioHeader::PayloadEnum::kDigitalRead) { - callback_.gpio_digital_read_config_deserialized_callback(channel_index, data_view); + if (payload_type == GpioHeader::PayloadEnum::kDigitalReadConfig) { + if (!callback_.gpio_digital_read_config_deserialized_callback(channel_index, data_view)) + co_return false; } else { if (data_view.capture_timestamp || data_view.rising_edge || data_view.falling_edge) co_return false; - callback_.gpio_analog_read_config_deserialized_callback(channel_index, data_view); - } - break; - } - case GpioHeader::PayloadEnum::kDigitalReadResultLow: - case GpioHeader::PayloadEnum::kDigitalReadResultHigh: { - data::GpioDigitalDataView data_view{}; - data_view.high = payload_type == GpioHeader::PayloadEnum::kDigitalReadResultHigh; - if (timestamped) { - const auto* payload_bytes = - co_await peek_bytes(sizeof(GpioDigitalReadTimestampPayload)); - if (!payload_bytes) [[unlikely]] + if (!callback_.gpio_analog_read_config_deserialized_callback(channel_index, data_view)) co_return false; - auto payload = GpioDigitalReadTimestampPayload::CRef{payload_bytes}; - data_view.timestamp_quarter_us = - payload.get(); - consume_peeked(); } - callback_.gpio_digital_data_deserialized_callback(channel_index, data_view); - break; - } - case GpioHeader::PayloadEnum::kAnalogReadResult: { - if (timestamped) [[unlikely]] - co_return false; - const auto* payload_bytes = co_await peek_bytes(sizeof(GpioAnalogPayload)); - if (!payload_bytes) [[unlikely]] - co_return false; - - auto payload = GpioAnalogPayload::CRef{payload_bytes}; - data::GpioAnalogDataView data_view{}; - data_view.value = payload.get(); - consume_peeked(); - - callback_.gpio_analog_data_deserialized_callback(channel_index, data_view); break; } default: co_return false; diff --git a/core/src/protocol/deserializer.hpp b/core/src/protocol/deserializer.hpp index 4e346a0..263a56f 100644 --- a/core/src/protocol/deserializer.hpp +++ b/core/src/protocol/deserializer.hpp @@ -24,20 +24,22 @@ class DeserializeCallback { DeserializeCallback& operator=(DeserializeCallback&&) = delete; virtual ~DeserializeCallback() = default; - virtual void can_deserialized_callback(FieldId id, const data::CanDataView& data) = 0; + [[nodiscard]] virtual bool + can_deserialized_callback(FieldId id, const data::CanDataView& data) = 0; - virtual void uart_deserialized_callback(FieldId id, const data::UartDataView& data) = 0; + [[nodiscard]] virtual bool + uart_deserialized_callback(FieldId id, const data::UartDataView& data) = 0; - virtual void gpio_digital_data_deserialized_callback( + [[nodiscard]] virtual bool gpio_digital_data_deserialized_callback( uint8_t channel_index, const data::GpioDigitalDataView& data) = 0; - virtual void gpio_analog_data_deserialized_callback( + [[nodiscard]] virtual bool gpio_analog_data_deserialized_callback( uint8_t channel_index, const data::GpioAnalogDataView& data) = 0; - virtual void gpio_digital_read_config_deserialized_callback( + [[nodiscard]] virtual bool gpio_digital_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) = 0; - virtual void gpio_analog_read_config_deserialized_callback( + [[nodiscard]] virtual bool gpio_analog_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) = 0; virtual void accelerometer_deserialized_callback(const data::AccelerometerDataView& data) = 0; diff --git a/core/src/protocol/protocol.hpp b/core/src/protocol/protocol.hpp index 2fb690d..fe7960c 100644 --- a/core/src/protocol/protocol.hpp +++ b/core/src/protocol/protocol.hpp @@ -93,14 +93,11 @@ struct SessionHeader struct GpioHeader : utility::Bitfield<2> { enum class PayloadEnum : uint8_t { - kDigitalWriteLow = 0b0000, - kDigitalWriteHigh = 0b0001, - kAnalogWrite = 0b0010, - kDigitalRead = 0b0100, - kAnalogRead = 0b0110, - kDigitalReadResultLow = 0b1000, - kDigitalReadResultHigh = 0b1001, - kAnalogReadResult = 0b1010, + kDigitalLow = 0b0000, + kDigitalHigh = 0b0001, + kAnalog = 0b0010, + kDigitalReadConfig = 0b0100, + kAnalogReadConfig = 0b0110, }; using PayloadType = utility::BitfieldMember<4, 4, PayloadEnum>; diff --git a/core/src/protocol/serializer.hpp b/core/src/protocol/serializer.hpp index db85988..b213f7b 100644 --- a/core/src/protocol/serializer.hpp +++ b/core/src/protocol/serializer.hpp @@ -120,14 +120,13 @@ class Serializer { return SerializeResult::kSuccess; } - SerializeResult write_gpio_digital_data( + SerializeResult write_gpio_digital_value( uint8_t channel_index, const data::GpioDigitalDataView& view) noexcept { utility::assert_debug(channel_index < (1U << GpioHeader::ChannelIndex::kBitWidth)); - LIBRMCS_VERIFY_LIKELY( - !view.timestamp_quarter_us.has_value(), SerializeResult::kInvalidArgument); - const auto payload_type = view.high ? GpioHeader::PayloadEnum::kDigitalWriteHigh - : GpioHeader::PayloadEnum::kDigitalWriteLow; - const std::size_t required = required_gpio_size(FieldId::kGpio, payload_type); + const auto payload_type = view.high ? GpioHeader::PayloadEnum::kDigitalHigh + : GpioHeader::PayloadEnum::kDigitalLow; + const std::size_t required = + required_gpio_size(FieldId::kGpio, payload_type, view.timestamp_quarter_us.has_value()); LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); auto dst = buffer_.allocate(required); @@ -141,7 +140,14 @@ class Serializer { cursor += sizeof(GpioHeader); header.set(payload_type); header.set(channel_index); - header.set(false); + header.set(view.timestamp_quarter_us.has_value()); + + if (view.timestamp_quarter_us) { + auto payload = GpioDigitalReadTimestampPayload::Ref(cursor); + cursor += sizeof(GpioDigitalReadTimestampPayload); + payload.set( + *view.timestamp_quarter_us); + } utility::assert_debug(cursor == dst.data() + dst.size()); return SerializeResult::kSuccess; @@ -151,7 +157,7 @@ class Serializer { uint8_t channel_index, const data::GpioReadConfigView& view) noexcept { utility::assert_debug(channel_index < (1U << GpioHeader::ChannelIndex::kBitWidth)); const std::size_t required = - required_gpio_size(FieldId::kGpio, GpioHeader::PayloadEnum::kDigitalRead); + required_gpio_size(FieldId::kGpio, GpioHeader::PayloadEnum::kDigitalReadConfig); LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); auto dst = buffer_.allocate(required); @@ -163,7 +169,7 @@ class Serializer { auto header = GpioHeader::Ref(cursor); cursor += sizeof(GpioHeader); - header.set(GpioHeader::PayloadEnum::kDigitalRead); + header.set(GpioHeader::PayloadEnum::kDigitalReadConfig); header.set(channel_index); header.set(view.capture_timestamp); @@ -179,11 +185,11 @@ class Serializer { return SerializeResult::kSuccess; } - SerializeResult write_gpio_analog_data( + SerializeResult write_gpio_analog_value( uint8_t channel_index, const data::GpioAnalogDataView& view) noexcept { utility::assert_debug(channel_index < (1U << GpioHeader::ChannelIndex::kBitWidth)); const std::size_t required = - required_gpio_size(FieldId::kGpio, GpioHeader::PayloadEnum::kAnalogWrite); + required_gpio_size(FieldId::kGpio, GpioHeader::PayloadEnum::kAnalog); LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); auto dst = buffer_.allocate(required); @@ -195,7 +201,7 @@ class Serializer { auto header = GpioHeader::Ref(cursor); cursor += sizeof(GpioHeader); - header.set(GpioHeader::PayloadEnum::kAnalogWrite); + header.set(GpioHeader::PayloadEnum::kAnalog); header.set(channel_index); header.set(false); @@ -215,7 +221,7 @@ class Serializer { LIBRMCS_VERIFY_LIKELY(!view.capture_timestamp, SerializeResult::kInvalidArgument); const std::size_t required = - required_gpio_size(FieldId::kGpio, GpioHeader::PayloadEnum::kAnalogRead); + required_gpio_size(FieldId::kGpio, GpioHeader::PayloadEnum::kAnalogReadConfig); LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); auto dst = buffer_.allocate(required); @@ -227,7 +233,7 @@ class Serializer { auto header = GpioHeader::Ref(cursor); cursor += sizeof(GpioHeader); - header.set(GpioHeader::PayloadEnum::kAnalogRead); + header.set(GpioHeader::PayloadEnum::kAnalogReadConfig); header.set(channel_index); header.set(false); @@ -243,67 +249,6 @@ class Serializer { return SerializeResult::kSuccess; } - SerializeResult write_gpio_digital_read_result( - uint8_t channel_index, const data::GpioDigitalDataView& view) noexcept { - utility::assert_debug(channel_index < (1U << GpioHeader::ChannelIndex::kBitWidth)); - const auto payload_type = view.high ? GpioHeader::PayloadEnum::kDigitalReadResultHigh - : GpioHeader::PayloadEnum::kDigitalReadResultLow; - const std::size_t required = - required_gpio_size(FieldId::kGpio, payload_type, view.timestamp_quarter_us.has_value()); - LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); - - auto dst = buffer_.allocate(required); - LIBRMCS_VERIFY_LIKELY(!dst.empty(), SerializeResult::kBadAlloc); - utility::assert_debug(dst.size() == required); - std::byte* cursor = dst.data(); - - write_field_header(cursor, FieldId::kGpio); - - auto header = GpioHeader::Ref(cursor); - cursor += sizeof(GpioHeader); - header.set(payload_type); - header.set(channel_index); - header.set(view.timestamp_quarter_us.has_value()); - - if (view.timestamp_quarter_us) { - auto payload = GpioDigitalReadTimestampPayload::Ref(cursor); - cursor += sizeof(GpioDigitalReadTimestampPayload); - payload.set( - *view.timestamp_quarter_us); - } - - utility::assert_debug(cursor == dst.data() + dst.size()); - return SerializeResult::kSuccess; - } - - SerializeResult write_gpio_analog_read_result( - uint8_t channel_index, const data::GpioAnalogDataView& view) noexcept { - utility::assert_debug(channel_index < (1U << GpioHeader::ChannelIndex::kBitWidth)); - const std::size_t required = - required_gpio_size(FieldId::kGpio, GpioHeader::PayloadEnum::kAnalogReadResult); - LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); - - auto dst = buffer_.allocate(required); - LIBRMCS_VERIFY_LIKELY(!dst.empty(), SerializeResult::kBadAlloc); - utility::assert_debug(dst.size() == required); - std::byte* cursor = dst.data(); - - write_field_header(cursor, FieldId::kGpio); - - auto header = GpioHeader::Ref(cursor); - cursor += sizeof(GpioHeader); - header.set(GpioHeader::PayloadEnum::kAnalogReadResult); - header.set(channel_index); - header.set(false); - - auto payload = GpioAnalogPayload::Ref(cursor); - cursor += sizeof(GpioAnalogPayload); - payload.set(view.value); - - utility::assert_debug(cursor == dst.data() + dst.size()); - return SerializeResult::kSuccess; - } - SerializeResult write_imu_accelerometer(const data::AccelerometerDataView& view) noexcept { const std::size_t required = required_imu_size(FieldId::kImu, ImuPayload::kAccelerometer); LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); @@ -466,20 +411,15 @@ class Serializer { const std::size_t gpio_header_bytes = sizeof(GpioHeader); std::size_t payload_bytes = 0; switch (payload) { - case GpioHeader::PayloadEnum::kDigitalWriteLow: - case GpioHeader::PayloadEnum::kDigitalWriteHigh: payload_bytes = 0; break; - case GpioHeader::PayloadEnum::kDigitalReadResultLow: - case GpioHeader::PayloadEnum::kDigitalReadResultHigh: + case GpioHeader::PayloadEnum::kDigitalLow: + case GpioHeader::PayloadEnum::kDigitalHigh: payload_bytes = timestamped ? sizeof(GpioDigitalReadTimestampPayload) : 0; break; - case GpioHeader::PayloadEnum::kDigitalRead: - case GpioHeader::PayloadEnum::kAnalogRead: + case GpioHeader::PayloadEnum::kDigitalReadConfig: + case GpioHeader::PayloadEnum::kAnalogReadConfig: payload_bytes = sizeof(GpioReadConfigPayload); break; - case GpioHeader::PayloadEnum::kAnalogWrite: - case GpioHeader::PayloadEnum::kAnalogReadResult: - payload_bytes = sizeof(GpioAnalogPayload); - break; + case GpioHeader::PayloadEnum::kAnalog: payload_bytes = sizeof(GpioAnalogPayload); break; default: return 0; } diff --git a/firmware/c_board/app/src/gpio/gpio.hpp b/firmware/c_board/app/src/gpio/gpio.hpp index 96cd189..a5540e8 100644 --- a/firmware/c_board/app/src/gpio/gpio.hpp +++ b/firmware/c_board/app/src/gpio/gpio.hpp @@ -211,7 +211,7 @@ class Gpio : private core::utility::Immovable { auto& serializer = usb::get_serializer(); core::utility::assert_debug( - serializer.write_gpio_digital_read_result( + serializer.write_gpio_digital_value( channel_index, {.high = high, .timestamp_quarter_us = timestamp_to_publish}) != core::protocol::Serializer::SerializeResult::kInvalidArgument); } diff --git a/firmware/c_board/app/src/usb/vendor.hpp b/firmware/c_board/app/src/usb/vendor.hpp index b8ac443..1e9051c 100644 --- a/firmware/c_board/app/src/usb/vendor.hpp +++ b/firmware/c_board/app/src/usb/vendor.hpp @@ -106,74 +106,82 @@ class Vendor session_established_ = true; } - void can_deserialized_callback( + bool can_deserialized_callback( core::protocol::FieldId id, const data::CanDataView& data) override { if (!session_established_) - return; + return true; switch (id) { - case data::DataId::kCan1: can::can1->handle_downlink(data); break; - case data::DataId::kCan2: can::can2->handle_downlink(data); break; - default: core::utility::assert_failed_always(); + case data::DataId::kCan1: can::can1->handle_downlink(data); return true; + case data::DataId::kCan2: can::can2->handle_downlink(data); return true; + default: return false; } } - void uart_deserialized_callback( + bool uart_deserialized_callback( core::protocol::FieldId id, const data::UartDataView& data) override { if (!session_established_) - return; + return true; switch (id) { - case data::DataId::kUart1: uart::uart1->handle_downlink(data); break; - case data::DataId::kUart2: uart::uart2->handle_downlink(data); break; - default: core::utility::assert_failed_always(); + case data::DataId::kUart1: uart::uart1->handle_downlink(data); return true; + case data::DataId::kUart2: uart::uart2->handle_downlink(data); return true; + default: return false; } } - void gpio_digital_data_deserialized_callback( + bool gpio_digital_data_deserialized_callback( uint8_t channel_index, const data::GpioDigitalDataView& data) override { if (!session_established_) - return; + return true; + if (data.timestamp_quarter_us.has_value()) + return false; if (channel_index >= kGpioChannelCount) - return; + return false; const auto& gpio = spec::c_board::kGpioDescriptors[channel_index]; if (!gpio.supports(spec::GpioCapability::kDigitalWrite)) - return; + return false; gpio::gpio->handle_digital_write(channel_index, data); + return true; } - void gpio_analog_data_deserialized_callback( + bool gpio_analog_data_deserialized_callback( uint8_t channel_index, const data::GpioAnalogDataView& data) override { if (!session_established_) - return; + return true; if (channel_index >= kGpioChannelCount) - return; + return false; const auto& gpio = spec::c_board::kGpioDescriptors[channel_index]; if (!gpio.supports(spec::GpioCapability::kAnalogWrite)) - return; + return false; gpio::gpio->handle_analog_write(channel_index, data); + return true; } - void gpio_digital_read_config_deserialized_callback( + bool gpio_digital_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) override { if (!session_established_) - return; + return true; if (channel_index >= kGpioChannelCount) - return; + return false; const auto& gpio = spec::c_board::kGpioDescriptors[channel_index]; if (!data.supported(gpio)) - return; + return false; gpio::gpio->handle_digital_read(channel_index, data); + return true; } - void gpio_analog_read_config_deserialized_callback( + bool gpio_analog_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) override { + if (!session_established_) + return true; (void)channel_index; (void)data; + return false; } void accelerometer_deserialized_callback(const data::AccelerometerDataView& data) override { diff --git a/firmware/rmcs_board/app/src/gpio/gpio.hpp b/firmware/rmcs_board/app/src/gpio/gpio.hpp index 3750ce5..0f9af26 100644 --- a/firmware/rmcs_board/app/src/gpio/gpio.hpp +++ b/firmware/rmcs_board/app/src/gpio/gpio.hpp @@ -309,7 +309,7 @@ class Gpio : private core::utility::Immovable { auto& serializer = usb::get_serializer(); core::utility::assert_debug( - serializer.write_gpio_digital_read_result( + serializer.write_gpio_digital_value( channel_index, {.high = high, .timestamp_quarter_us = timestamp_to_publish}) != core::protocol::Serializer::SerializeResult::kInvalidArgument); } diff --git a/firmware/rmcs_board/app/src/usb/vendor.hpp b/firmware/rmcs_board/app/src/usb/vendor.hpp index 9a11d4b..23db42d 100644 --- a/firmware/rmcs_board/app/src/usb/vendor.hpp +++ b/firmware/rmcs_board/app/src/usb/vendor.hpp @@ -111,82 +111,90 @@ class Vendor session_established_ = true; } - void can_deserialized_callback( + bool can_deserialized_callback( core::protocol::FieldId id, const data::CanDataView& data) override { if (!session_established_) - return; + return true; switch (id) { - case data::DataId::kCan0: can::can_array[0]->handle_downlink(data); break; - case data::DataId::kCan1: can::can_array[1]->handle_downlink(data); break; - case data::DataId::kCan2: can::can_array[2]->handle_downlink(data); break; - case data::DataId::kCan3: can::can_array[3]->handle_downlink(data); break; - default: core::utility::assert_failed_always(); + case data::DataId::kCan0: can::can_array[0]->handle_downlink(data); return true; + case data::DataId::kCan1: can::can_array[1]->handle_downlink(data); return true; + case data::DataId::kCan2: can::can_array[2]->handle_downlink(data); return true; + case data::DataId::kCan3: can::can_array[3]->handle_downlink(data); return true; + default: return false; } } - void uart_deserialized_callback( + bool uart_deserialized_callback( core::protocol::FieldId id, const data::UartDataView& data) override { if (!session_established_) - return; + return true; switch (id) { - case data::DataId::kUart0: uart::uart_array[0]->handle_downlink(data); break; - case data::DataId::kUart1: uart::uart_array[1]->handle_downlink(data); break; + case data::DataId::kUart0: uart::uart_array[0]->handle_downlink(data); return true; + case data::DataId::kUart1: uart::uart_array[1]->handle_downlink(data); return true; #ifdef BOARD_UART2 - case data::DataId::kUart2: uart::uart_array[2]->handle_downlink(data); break; + case data::DataId::kUart2: uart::uart_array[2]->handle_downlink(data); return true; #endif #ifdef BOARD_UART3 - case data::DataId::kUart3: uart::uart_array[3]->handle_downlink(data); break; + case data::DataId::kUart3: uart::uart_array[3]->handle_downlink(data); return true; #endif - default: core::utility::assert_failed_always(); + default: return false; } } - void gpio_digital_data_deserialized_callback( + bool gpio_digital_data_deserialized_callback( uint8_t channel_index, const data::GpioDigitalDataView& data) override { if (!session_established_) - return; + return true; + if (data.timestamp_quarter_us.has_value()) + return false; if (channel_index >= board::spec::kGpioDescriptors.size()) - return; + return false; const auto& gpio_descriptor = board::spec::kGpioDescriptors[channel_index]; if (!gpio_descriptor.supports(spec::GpioCapability::kDigitalWrite)) - return; + return false; gpio::gpio->handle_digital_write(channel_index, data); + return true; } - void gpio_analog_data_deserialized_callback( + bool gpio_analog_data_deserialized_callback( uint8_t channel_index, const data::GpioAnalogDataView& data) override { if (!session_established_) - return; + return true; if (channel_index >= board::spec::kGpioDescriptors.size()) - return; + return false; const auto& gpio_descriptor = board::spec::kGpioDescriptors[channel_index]; if (!gpio_descriptor.supports(spec::GpioCapability::kAnalogWrite)) - return; + return false; gpio::gpio->handle_analog_write(channel_index, data); + return true; } - void gpio_digital_read_config_deserialized_callback( + bool gpio_digital_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) override { if (!session_established_) - return; + return true; if (channel_index >= board::spec::kGpioDescriptors.size()) - return; + return false; const auto& gpio_descriptor = board::spec::kGpioDescriptors[channel_index]; if (!data.supported(gpio_descriptor)) - return; + return false; gpio::gpio->handle_digital_read(channel_index, data); + return true; } - void gpio_analog_read_config_deserialized_callback( + bool gpio_analog_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) override { + if (!session_established_) + return true; (void)channel_index; (void)data; + return false; } void accelerometer_deserialized_callback(const data::AccelerometerDataView& data) override { diff --git a/host/src/protocol/handler.cpp b/host/src/protocol/handler.cpp index 123f8a4..1ccf116 100644 --- a/host/src/protocol/handler.cpp +++ b/host/src/protocol/handler.cpp @@ -61,52 +61,70 @@ class Handler::Impl : public core::protocol::DeserializeCallback { PacketBuilder start_transmit() { return PacketBuilder{transport_.get()}; } - void can_deserialized_callback( + bool can_deserialized_callback( core::protocol::FieldId id, const data::CanDataView& data) override { if (!session_established()) - return; - if (!callback_.can_receive_callback(id, data)) + return true; + if (!callback_.can_receive_callback(id, data)) { logging::get_logger().error("Unexpected can field id: ", static_cast(id)); + return false; + } + return true; } - void uart_deserialized_callback( + bool uart_deserialized_callback( core::protocol::FieldId id, const data::UartDataView& data) override { if (!session_established()) - return; - if (!callback_.uart_receive_callback(id, data)) + return true; + if (!callback_.uart_receive_callback(id, data)) { logging::get_logger().error("Unexpected uart field id: ", static_cast(id)); + return false; + } + return true; } - void gpio_digital_data_deserialized_callback( + bool gpio_digital_data_deserialized_callback( uint8_t channel_index, const data::GpioDigitalDataView& data) override { if (!session_established()) - return; - if (!callback_.gpio_digital_read_result_callback(channel_index, data)) + return true; + if (!callback_.gpio_digital_read_result_callback(channel_index, data)) { logging::get_logger().error( "Unexpected gpio channel index: ", static_cast(channel_index)); + return false; + } + return true; } - void gpio_analog_data_deserialized_callback( + bool gpio_analog_data_deserialized_callback( uint8_t channel_index, const data::GpioAnalogDataView& data) override { if (!session_established()) - return; - if (!callback_.gpio_analog_read_result_callback(channel_index, data)) + return true; + if (!callback_.gpio_analog_read_result_callback(channel_index, data)) { logging::get_logger().error( "Unexpected gpio channel index: ", static_cast(channel_index)); + return false; + } + return true; } - void gpio_digital_read_config_deserialized_callback( + bool gpio_digital_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) override { + if (!session_established()) + return true; (void)channel_index; (void)data; logging::get_logger().error("Unexpected gpio digital read config field in uplink"); + return false; } - void gpio_analog_read_config_deserialized_callback( + bool gpio_analog_read_config_deserialized_callback( uint8_t channel_index, const data::GpioReadConfigView& data) override { + if (!session_established()) + return true; (void)channel_index; (void)data; logging::get_logger().error("Unexpected gpio analog read config field in uplink"); + return false; } void accelerometer_deserialized_callback(const data::AccelerometerDataView& data) override { @@ -295,7 +313,9 @@ struct PacketBuilderImpl { [[nodiscard]] bool write_gpio_digital_data( uint8_t channel_index, const data::GpioDigitalDataView& view) noexcept { - return process_result(serializer_.write_gpio_digital_data(channel_index, view)); + if (view.timestamp_quarter_us.has_value()) [[unlikely]] + return false; + return process_result(serializer_.write_gpio_digital_value(channel_index, view)); } [[nodiscard]] bool write_gpio_digital_read_config( @@ -305,7 +325,7 @@ struct PacketBuilderImpl { [[nodiscard]] bool write_gpio_analog_data( uint8_t channel_index, const data::GpioAnalogDataView& view) noexcept { - return process_result(serializer_.write_gpio_analog_data(channel_index, view)); + return process_result(serializer_.write_gpio_analog_value(channel_index, view)); } [[nodiscard]] bool write_imu_accelerometer(const data::AccelerometerDataView& view) noexcept {