diff --git a/Makefile.include b/Makefile.include index 4d667b89d..64dbeec27 100644 --- a/Makefile.include +++ b/Makefile.include @@ -22,6 +22,9 @@ FEATURES_REQUIRED += cpp # Required modules USEMODULE += cpp11-compat +# Required packages +USEPKG += etl + define remote-flash-recipe scp $(BINFILE) $(REMOTE_USER)@$(REMOTE_TARGET):/tmp/fw.bin $(GDB) -nx -batch -ex "target extended-remote $(REMOTE_TARGET):3333" -ex "monitor reset halt" -ex "monitor flash write_image erase /tmp/fw.bin 0x08000000" -ex "monitor reset run" @@ -77,6 +80,7 @@ tmp_cxxexflags := $(CXXEXFLAGS) CXXEXFLAGS = $(filter-out -std=%, $(tmp_cxxexflags)) CXXEXFLAGS += -std=c++17 CXXEXFLAGS += -Wno-pedantic +CXXEXFLAGS += -Wno-cast-align .PHONY: world world: all diff --git a/applications/app_test/PB_GameInputMessage.proto b/applications/app_test/PB_GameInputMessage.proto deleted file mode 100644 index cac4d02aa..000000000 --- a/applications/app_test/PB_GameInputMessage.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto3"; - -import "PB_Command.proto"; -import "PB_Wizard.proto"; -import "PB_Samples.proto"; - -message PB_GameInputMessage { - oneof type { - PB_Command command = 1; - bool copilot_connected = 2; - bool copilot_disconnected = 3; - PB_Wizard wizard = 4; - PB_Samples samples = 5; - } -} diff --git a/applications/app_test/PB_GameOutputMessage.proto b/applications/app_test/PB_GameOutputMessage.proto deleted file mode 100644 index 5b5f829b6..000000000 --- a/applications/app_test/PB_GameOutputMessage.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -import "PB_Menu.proto"; -import "PB_State.proto"; -import "PB_Wizard.proto"; - -message PB_GameOutputMessage { - oneof type { - bool reset = 1; - PB_Menu menu = 2; - PB_State state = 3; - PB_Wizard wizard = 4; - bool req_samples = 5; - uint32 score = 6; - } -} diff --git a/applications/app_test/PB_Score.proto b/applications/app_test/PB_Score.proto new file mode 100644 index 000000000..74a21cc60 --- /dev/null +++ b/applications/app_test/PB_Score.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message PB_Score { + int32 value = 1; +} diff --git a/applications/app_test/app_samples.cpp b/applications/app_test/app_samples.cpp index 024102173..9d82037cc 100644 --- a/applications/app_test/app_samples.cpp +++ b/applications/app_test/app_samples.cpp @@ -1,7 +1,6 @@ // Firmware includes #include "platform.hpp" #include "trigonometry.h" -#include "uartpb_config.hpp" #include "app_camp.hpp" #include "app_samples.hpp" @@ -16,9 +15,11 @@ namespace cogip { namespace app { -static PB_OutputMessage _output_message; static DetectedSamples _detected_samples; +constexpr cogip::uartpb::uuid_t sample_request_uuid = 3781855956; +constexpr cogip::uartpb::uuid_t sample_response_uuid = 1538397045; + static std::map _samples; typedef struct { @@ -57,6 +58,8 @@ void app_samples_init() return; } + pf_get_uartpb()->register_message_handler(sample_response_uuid, app_samples_process); + event_queue_init_detached(&_sample_queue); _sample_event.super.list_node.next = nullptr; @@ -170,9 +173,7 @@ const DetectedSamples & app_samples_detect(void) { event_queue_claim(&_sample_queue); cogip::uartpb::UartProtobuf *uartpb = pf_get_uartpb(); - _output_message.clear(); - _output_message.set_req_samples(true); - uartpb->send_message(_output_message); + uartpb->send_message(sample_request_uuid); sample_event_t *event = (sample_event_t *)event_wait(&_sample_queue); auto & samples = event->pb_message.get_samples(); @@ -203,9 +204,14 @@ const DetectedSamples & app_samples_detect(void) return _detected_samples; } -void app_samples_process(const PB_Samples &samples) +void app_samples_process(cogip::uartpb::ReadBuffer *buffer) { - _sample_event.pb_message = samples; + EmbeddedProto::Error error = _sample_event.pb_message.deserialize(*buffer); + if (error != EmbeddedProto::Error::NO_ERRORS) { + std::cout << "Samples: Protobuf deserialization error: " << static_cast(error) << std::endl; + return; + } + event_post(&_sample_queue, (event_t *)&_sample_event); } diff --git a/applications/app_test/app_uartpb.cpp b/applications/app_test/app_uartpb.cpp deleted file mode 100644 index 2a2897dc3..000000000 --- a/applications/app_test/app_uartpb.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "app.hpp" -#include "platform.hpp" -#include "shell_menu/shell_menu.hpp" - -#include "uartpb_config.hpp" - -#include - -namespace cogip { - -namespace app { - -// Read incoming Protobuf message and call the corresponding message handler -void app_uartpb_message_handler(cogip::uartpb::ReadBuffer &buffer) -{ - PB_InputMessage *message = new PB_InputMessage(); - EmbeddedProto::Error error = message->deserialize(buffer); - if (error != EmbeddedProto::Error::NO_ERRORS) { - COGIP_DEBUG_COUT("Protobuf deserialization error: " << static_cast(error)); - return; - } - if (message->has_command()) { - cogip::shell::handle_pb_command(message->command()); - } - else if (message->has_copilot_connected()) { - pf_set_copilot_connected(true); - COGIP_DEBUG_COUT("Copilot connected"); - if (cogip::shell::current_menu) { - cogip::shell::current_menu->send_pb_message(); - } - } - else if (message->has_copilot_disconnected()) { - pf_set_copilot_connected(false); - COGIP_DEBUG_COUT("Copilot disconnected"); - } - else if (message->has_wizard()) { - pf_get_wizard()->handle_response(message->wizard()); - } - else if (message->has_samples()) { - app_samples_process(message->samples()); - } - else { - COGIP_DEBUG_CERR("Unknown response type: " << static_cast(message->get_which_type())); - } - delete message; -} - -} // namespace app - -} // namespace cogip diff --git a/applications/app_test/include/app.hpp b/applications/app_test/include/app.hpp index 02cea9ad6..9cdde07f0 100644 --- a/applications/app_test/include/app.hpp +++ b/applications/app_test/include/app.hpp @@ -8,7 +8,6 @@ #include "app_obstacles.hpp" #include "app_samples.hpp" #include "app_shell.hpp" -#include "app_uartpb.hpp" /* * Machine parameters diff --git a/applications/app_test/include/app_samples.hpp b/applications/app_test/include/app_samples.hpp index be5fd96dc..abd7e0598 100644 --- a/applications/app_test/include/app_samples.hpp +++ b/applications/app_test/include/app_samples.hpp @@ -1,6 +1,7 @@ #pragma once #include "obstacles/Circle.hpp" +#include "uartpb/ReadBuffer.hpp" #include "PB_Samples.hpp" @@ -117,7 +118,7 @@ void app_samples_init(); const DetectedSamples & app_samples_detect(void); -void app_samples_process(const PB_Samples &samples); +void app_samples_process(cogip::uartpb::ReadBuffer *buffer); }; // namespace app diff --git a/applications/app_test/include/app_uartpb.hpp b/applications/app_test/include/app_uartpb.hpp deleted file mode 100644 index 383522dc0..000000000 --- a/applications/app_test/include/app_uartpb.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "uartpb/ReadBuffer.hpp" - -namespace cogip { - -namespace app { - -/// Message handler for incoming Protobuf messages. -void app_uartpb_message_handler(cogip::uartpb::ReadBuffer &buffer); - -} // namespace app - -} // namespace cogip diff --git a/applications/app_test/include/uartpb_config.hpp b/applications/app_test/include/uartpb_config.hpp deleted file mode 100644 index 6cde54f7b..000000000 --- a/applications/app_test/include/uartpb_config.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "shell_menu/Menu.hpp" -#include "obstacles/List.hpp" -#include "obstacles/Obstacle.hpp" -#include "avoidance.hpp" -#include "wizard/Wizard.hpp" -#include "app_samples.hpp" - -#include "PB_GameInputMessage.hpp" -#include "PB_GameOutputMessage.hpp" - -using PB_InputMessage = PB_GameInputMessage< - COMMAND_NAME_MAX_LENGTH, - COMMAND_DESC_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - APP_SAMPLES_MAX_DETECTED>; - -using PB_OutputMessage = PB_GameOutputMessage< - COMMAND_NAME_MAX_LENGTH, - NB_SHELL_COMMANDS, - COMMAND_NAME_MAX_LENGTH, - COMMAND_DESC_MAX_LENGTH, - AVOIDANCE_GRAPH_MAX_VERTICES, - OBSTACLES_MAX_NUMBER, - OBSTACLE_BOUNDING_BOX_VERTICES, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH>; diff --git a/applications/cup2022/PB_GameInputMessage.proto b/applications/cup2022/PB_GameInputMessage.proto deleted file mode 100644 index cac4d02aa..000000000 --- a/applications/cup2022/PB_GameInputMessage.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto3"; - -import "PB_Command.proto"; -import "PB_Wizard.proto"; -import "PB_Samples.proto"; - -message PB_GameInputMessage { - oneof type { - PB_Command command = 1; - bool copilot_connected = 2; - bool copilot_disconnected = 3; - PB_Wizard wizard = 4; - PB_Samples samples = 5; - } -} diff --git a/applications/cup2022/PB_GameOutputMessage.proto b/applications/cup2022/PB_GameOutputMessage.proto deleted file mode 100644 index 5b5f829b6..000000000 --- a/applications/cup2022/PB_GameOutputMessage.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -import "PB_Menu.proto"; -import "PB_State.proto"; -import "PB_Wizard.proto"; - -message PB_GameOutputMessage { - oneof type { - bool reset = 1; - PB_Menu menu = 2; - PB_State state = 3; - PB_Wizard wizard = 4; - bool req_samples = 5; - uint32 score = 6; - } -} diff --git a/applications/cup2022/app_samples.cpp b/applications/cup2022/app_samples.cpp index 024102173..9d82037cc 100644 --- a/applications/cup2022/app_samples.cpp +++ b/applications/cup2022/app_samples.cpp @@ -1,7 +1,6 @@ // Firmware includes #include "platform.hpp" #include "trigonometry.h" -#include "uartpb_config.hpp" #include "app_camp.hpp" #include "app_samples.hpp" @@ -16,9 +15,11 @@ namespace cogip { namespace app { -static PB_OutputMessage _output_message; static DetectedSamples _detected_samples; +constexpr cogip::uartpb::uuid_t sample_request_uuid = 3781855956; +constexpr cogip::uartpb::uuid_t sample_response_uuid = 1538397045; + static std::map _samples; typedef struct { @@ -57,6 +58,8 @@ void app_samples_init() return; } + pf_get_uartpb()->register_message_handler(sample_response_uuid, app_samples_process); + event_queue_init_detached(&_sample_queue); _sample_event.super.list_node.next = nullptr; @@ -170,9 +173,7 @@ const DetectedSamples & app_samples_detect(void) { event_queue_claim(&_sample_queue); cogip::uartpb::UartProtobuf *uartpb = pf_get_uartpb(); - _output_message.clear(); - _output_message.set_req_samples(true); - uartpb->send_message(_output_message); + uartpb->send_message(sample_request_uuid); sample_event_t *event = (sample_event_t *)event_wait(&_sample_queue); auto & samples = event->pb_message.get_samples(); @@ -203,9 +204,14 @@ const DetectedSamples & app_samples_detect(void) return _detected_samples; } -void app_samples_process(const PB_Samples &samples) +void app_samples_process(cogip::uartpb::ReadBuffer *buffer) { - _sample_event.pb_message = samples; + EmbeddedProto::Error error = _sample_event.pb_message.deserialize(*buffer); + if (error != EmbeddedProto::Error::NO_ERRORS) { + std::cout << "Samples: Protobuf deserialization error: " << static_cast(error) << std::endl; + return; + } + event_post(&_sample_queue, (event_t *)&_sample_event); } diff --git a/applications/cup2022/app_uartpb.cpp b/applications/cup2022/app_uartpb.cpp deleted file mode 100644 index 0fb1d39f9..000000000 --- a/applications/cup2022/app_uartpb.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "app.hpp" -#include "platform.hpp" -#include "shell_menu/shell_menu.hpp" - -#include "uartpb_config.hpp" - -#include - -namespace cogip { - -namespace app { - -// Read incoming Protobuf message and call the corresponding message handler -void app_uartpb_message_handler(cogip::uartpb::ReadBuffer &buffer) -{ - PB_InputMessage *message = new PB_InputMessage(); - EmbeddedProto::Error error = message->deserialize(buffer); - if (error != EmbeddedProto::Error::NO_ERRORS) { - COGIP_DEBUG_COUT("Protobuf deserialization error: " << static_cast(error)); - return; - } - if (message->has_command()) { - cogip::shell::handle_pb_command(message->command()); - } - else if (message->has_copilot_connected()) { - pf_set_copilot_connected(true); - COGIP_DEBUG_COUT("Copilot connected"); - if (cogip::shell::current_menu) { - cogip::shell::current_menu->send_pb_message(); - } - } - else if (message->has_copilot_disconnected()) { - pf_set_copilot_connected(false); - COGIP_DEBUG_COUT("Copilot disconnected"); - } - else if (message->has_wizard()) { - pf_get_wizard()->handle_response(message->wizard()); - } - else if (message->has_samples()) { - app_samples_process(message->samples()); - } - else { - COGIP_DEBUG_COUT("Unknown response type: " << static_cast(message->get_which_type())); - } - delete message; -} - -} // namespace app - -} // namespace cogip diff --git a/applications/cup2022/include/app.hpp b/applications/cup2022/include/app.hpp index 02cea9ad6..9cdde07f0 100644 --- a/applications/cup2022/include/app.hpp +++ b/applications/cup2022/include/app.hpp @@ -8,7 +8,6 @@ #include "app_obstacles.hpp" #include "app_samples.hpp" #include "app_shell.hpp" -#include "app_uartpb.hpp" /* * Machine parameters diff --git a/applications/cup2022/include/app_samples.hpp b/applications/cup2022/include/app_samples.hpp index be5fd96dc..abd7e0598 100644 --- a/applications/cup2022/include/app_samples.hpp +++ b/applications/cup2022/include/app_samples.hpp @@ -1,6 +1,7 @@ #pragma once #include "obstacles/Circle.hpp" +#include "uartpb/ReadBuffer.hpp" #include "PB_Samples.hpp" @@ -117,7 +118,7 @@ void app_samples_init(); const DetectedSamples & app_samples_detect(void); -void app_samples_process(const PB_Samples &samples); +void app_samples_process(cogip::uartpb::ReadBuffer *buffer); }; // namespace app diff --git a/applications/cup2022/include/app_uartpb.hpp b/applications/cup2022/include/app_uartpb.hpp deleted file mode 100644 index 383522dc0..000000000 --- a/applications/cup2022/include/app_uartpb.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "uartpb/ReadBuffer.hpp" - -namespace cogip { - -namespace app { - -/// Message handler for incoming Protobuf messages. -void app_uartpb_message_handler(cogip::uartpb::ReadBuffer &buffer); - -} // namespace app - -} // namespace cogip diff --git a/applications/cup2022/include/uartpb_config.hpp b/applications/cup2022/include/uartpb_config.hpp deleted file mode 100644 index 6cde54f7b..000000000 --- a/applications/cup2022/include/uartpb_config.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "shell_menu/Menu.hpp" -#include "obstacles/List.hpp" -#include "obstacles/Obstacle.hpp" -#include "avoidance.hpp" -#include "wizard/Wizard.hpp" -#include "app_samples.hpp" - -#include "PB_GameInputMessage.hpp" -#include "PB_GameOutputMessage.hpp" - -using PB_InputMessage = PB_GameInputMessage< - COMMAND_NAME_MAX_LENGTH, - COMMAND_DESC_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - APP_SAMPLES_MAX_DETECTED>; - -using PB_OutputMessage = PB_GameOutputMessage< - COMMAND_NAME_MAX_LENGTH, - NB_SHELL_COMMANDS, - COMMAND_NAME_MAX_LENGTH, - COMMAND_DESC_MAX_LENGTH, - AVOIDANCE_GRAPH_MAX_VERTICES, - OBSTACLES_MAX_NUMBER, - OBSTACLE_BOUNDING_BOX_VERTICES, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_REP_MAX, - WIZARD_NAME_MAX_LENGTH, - WIZARD_NAME_MAX_LENGTH>; diff --git a/examples/uartpb/PB_ExampleInputMessage.proto b/examples/uartpb/PB_ExampleInputMessage.proto deleted file mode 100644 index 75d7f8a95..000000000 --- a/examples/uartpb/PB_ExampleInputMessage.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; - -import "PB_RespHello.proto"; -import "PB_RespPing.proto"; -import "PB_RespPong.proto"; - -message PB_ExampleInputMessage { - oneof type { - PB_RespHello resp_hello = 1; - PB_RespPing resp_ping = 2; - PB_RespPong resp_pong = 3; - } -} diff --git a/examples/uartpb/PB_ExampleOutputMessage.proto b/examples/uartpb/PB_ExampleOutputMessage.proto deleted file mode 100644 index 9c3e411b3..000000000 --- a/examples/uartpb/PB_ExampleOutputMessage.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -import "PB_Menu.proto"; -import "PB_ReqHello.proto"; -import "PB_ReqPing.proto"; -import "PB_ReqPong.proto"; - -message PB_ExampleOutputMessage { - oneof type { - PB_Menu menu = 1; - bool reset = 2; - PB_ReqHello req_hello = 3; - PB_ReqPing req_ping = 4; - PB_ReqPong req_pong = 5; - } -} diff --git a/examples/uartpb/include/uartpb_config.hpp b/examples/uartpb/include/uartpb_config.hpp deleted file mode 100644 index 8248eb5f0..000000000 --- a/examples/uartpb/include/uartpb_config.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "shell_menu/Menu.hpp" -#include "PB_ExampleOutputMessage.hpp" - -using PB_OutputMessage = PB_ExampleOutputMessage< - COMMAND_NAME_MAX_LENGTH, - NB_SHELL_COMMANDS, - COMMAND_NAME_MAX_LENGTH, - COMMAND_DESC_MAX_LENGTH, - 64>; diff --git a/examples/uartpb/main.cpp b/examples/uartpb/main.cpp index 8f920ad1d..432bcbffc 100644 --- a/examples/uartpb/main.cpp +++ b/examples/uartpb/main.cpp @@ -6,8 +6,6 @@ #include "thread.h" #include "xtimer.h" -#include "uartpb_config.hpp" - // Projet includes #include "shell_menu/shell_menu.hpp" @@ -20,8 +18,6 @@ #include "PB_RespHello.hpp" #include "PB_RespPing.hpp" #include "PB_RespPong.hpp" -#include "PB_ExampleInputMessage.hpp" -#include "PB_ExampleOutputMessage.hpp" #include "uartpb/UartProtobuf.hpp" #include "uartpb/ReadBuffer.hpp" @@ -33,86 +29,78 @@ static char sender_stack[THREAD_STACKSIZE_MAIN]; bool suspend_sender = false; cogip::uartpb::UartProtobuf *uartpb = nullptr; -static PB_OutputMessage output_message; -static void handle_response_hello(const PB_RespHello &hello) -{ - printf("<<== Hello response with number=%" PRId32 "\n\n", (int32_t)hello.get_number()); -} +constexpr cogip::uartpb::uuid_t reset_uuid = 3351980141; +constexpr cogip::uartpb::uuid_t req_hello_uuid = 3938291130; +constexpr cogip::uartpb::uuid_t req_ping_uuid = 2537089183; +constexpr cogip::uartpb::uuid_t req_pong_uuid = 3650317449; +constexpr cogip::uartpb::uuid_t resp_hello_uuid = 4187249687; +constexpr cogip::uartpb::uuid_t resp_ping_uuid = 4288740491; +constexpr cogip::uartpb::uuid_t resp_pong_uuid = 2687718320; -static void handle_response_ping(const PB_RespPing &ping) +static PB_RespHello resp_hello; +static PB_RespPing resp_ping; +static PB_RespPong resp_pong; + +static PB_ReqHello<64> req_hello; +static PB_ReqPing req_ping; +static PB_ReqPong req_pong; + +static void handle_response_hello(cogip::uartpb::ReadBuffer *buffer) { - printf("<<== Ping response with color=%s\n\n", get_color_name((cogip::cogip_defs::Color)ping.get_color())); + resp_hello.deserialize(*buffer); + std::cout << "<<== Hello response with number=" << resp_hello.get_number() << std::endl; } -static void handle_response_pong(const PB_RespPong &pong) +static void handle_response_ping(cogip::uartpb::ReadBuffer *buffer) { - const cogip::cogip_defs::Pose &pose = pong.get_new_pose(); - printf( - "<<== Pong response with pose={x=%.2lf, y=%.2lf, angle=%.2lf}\n\n", - pose.x(), pose.y(), pose.O() - ); + resp_ping.deserialize(*buffer); + std::cout << "<<== Ping response with color="<< get_color_name((cogip::cogip_defs::Color)resp_ping.get_color()) << std::endl; } -void message_handler(cogip::uartpb::ReadBuffer &buffer) +static void handle_response_pong(cogip::uartpb::ReadBuffer *buffer) { - PB_ExampleInputMessage *message = new PB_ExampleInputMessage(); - message->deserialize(buffer); - - if (message->has_resp_hello()) { - handle_response_hello(message->resp_hello()); - } - else if (message->has_resp_ping()) { - handle_response_ping(message->resp_ping()); - } - else if (message->has_resp_pong()) { - handle_response_pong(message->resp_pong()); - } - else { - printf("Unknown response type: %" PRIu32 "\n", static_cast(message->get_which_type())); - } - - delete message; + resp_pong.deserialize(*buffer); + const cogip::cogip_defs::Pose &pose = resp_pong.get_new_pose(); + std::cout + << "<<== Pong response with pose={x=" << pose.x() + << ", y=" << pose.y() << ", angle=" << pose.O() << "}" + << std::endl; } static void send_hello() { - PB_ReqHello<64> hello; - hello.set_number(std::rand()); - hello.mutable_message() = "hellohello"; - printf( - "==>> Hello request with number=%" PRIi32 " and message='%s'\n", - (int32_t)hello.get_number(), (const char *)hello.get_message().get_const() - ); - - output_message.set_req_hello(hello); - uartpb->send_message(output_message); + req_hello.set_number(std::rand()); + req_hello.mutable_message() = "hellohello"; + std::cout + << "==>> Hello request with number=" << (int32_t)req_hello.get_number() + << " and message='" << req_hello.get_message().get_const() << "'" + << std::endl; + + uartpb->send_message(req_hello_uuid, &req_hello); } static void send_ping() { - PB_ReqPing ping; - ping.set_color((PB_Color)cogip::cogip_defs::Color::RED); + req_ping.set_color((PB_Color)cogip::cogip_defs::Color::RED); - printf("==>> Ping request with color=%s\n", get_color_name((cogip::cogip_defs::Color)ping.get_color())); + std::cout << "==>> Ping request with color=" << get_color_name((cogip::cogip_defs::Color)req_ping.get_color()) << std::endl; - output_message.set_req_ping(ping); - uartpb->send_message(output_message); + uartpb->send_message(req_ping_uuid, &req_ping); } static void send_pong() { - PB_ReqPong pong; cogip::cogip_defs::Pose pose = {15, 30, 90}; - pose.pb_copy(pong.mutable_pose()); + pose.pb_copy(req_pong.mutable_pose()); - printf( - "==>> Pong request with pose={x=%.2lf, y=%.2lf, angle=%.2lf}\n", - (double)pong.get_pose().get_x(), (double)pong.get_pose().get_y(), (double)pong.get_pose().get_O() - ); + std::cout + << "==>> Pong request with pose={x=" << req_pong.get_pose().get_x() + << ", y=" << req_pong.get_pose().get_y() + << ", angle=" << req_pong.get_pose().get_O() << "}" + << std::endl; - output_message.set_req_pong(pong); - uartpb->send_message(output_message); + uartpb->send_message(req_pong_uuid, &req_pong); } static void *message_sender(void *arg) @@ -176,14 +164,14 @@ static int cmd_sub(int argc, char **argv) (void)argc; (void)argv; - printf("Sub-menu command\n"); + std::cout << "Sub-menu command" << std::endl; return 0; } int main(void) { - printf("\n== UART/EmbeddedProto Example ==\n"); + std::cout << std::endl << "== UART/EmbeddedProto Example ==" << std::endl; cogip::shell::root_menu.push_back( new cogip::shell::Command("hello", "Send hello", cmd_hello)); @@ -197,14 +185,15 @@ int main(void) "Sub-menu", "sub", &cogip::shell::root_menu); menu->push_back(new cogip::shell::Command("cmd", "Sub-menu command", cmd_sub)); - uartpb = new cogip::uartpb::UartProtobuf( - message_handler, - UART_DEV(1) - ); + uartpb = new cogip::uartpb::UartProtobuf(UART_DEV(1)); + + uartpb->register_message_handler(resp_hello_uuid, handle_response_hello); + uartpb->register_message_handler(resp_ping_uuid, handle_response_ping); + uartpb->register_message_handler(resp_pong_uuid, handle_response_pong); bool res = uartpb->connect(); if (! res) { - printf("UART initialization status: %d\n", res); + std::cout << "UART initialization status: " << res << std::endl; exit(1); } @@ -214,8 +203,7 @@ int main(void) sender_stack, sizeof(sender_stack), SENDER_PRIO, THREAD_CREATE_SLEEPING, message_sender, NULL, "sender"); - output_message.set_reset(true); - uartpb->send_message(output_message); + uartpb->send_message(reset_uuid); // Start shell cogip::shell::register_uartpb(uartpb); diff --git a/examples/uartpb/uartpb-client.py b/examples/uartpb/uartpb-client.py index 7ea4c3630..947575ec3 100755 --- a/examples/uartpb/uartpb-client.py +++ b/examples/uartpb/uartpb-client.py @@ -2,6 +2,7 @@ import base64 import binascii from pathlib import Path +from typing import Union from google import protobuf from google.protobuf import json_format @@ -12,77 +13,107 @@ from PB_ReqHello_pb2 import PB_ReqHello from PB_ReqPing_pb2 import PB_ReqPing from PB_ReqPong_pb2 import PB_ReqPong +from PB_RespHello_pb2 import PB_RespHello +from PB_RespPing_pb2 import PB_RespPing +from PB_RespPong_pb2 import PB_RespPong from PB_Menu_pb2 import PB_Menu -from PB_ExampleInputMessage_pb2 import PB_ExampleInputMessage -from PB_ExampleOutputMessage_pb2 import PB_ExampleOutputMessage serial_port = Serial() - -def send_response(response: PB_ExampleInputMessage) -> None: - response_serialized = response.SerializeToString() - response_base64 = base64.encodebytes(response_serialized) - serial_port.write(response_base64) - serial_port.write(b"\n") +menu_uuid = 2168120333 +reset_uuid = 3351980141 +req_hello_uuid = 3938291130 +req_ping_uuid = 2537089183 +req_pong_uuid = 3650317449 +resp_hello_uuid = 4187249687 +resp_ping_uuid = 4288740491 +resp_pong_uuid = 2687718320 + + +def send_response( + uuid: int, + response: Union[None, PB_RespHello, PB_RespPing, PB_RespPong] = None) -> None: + serial_port.write(uuid.to_bytes(4, "little")) + if response: + response_serialized = response.SerializeToString() + response_base64 = base64.encodebytes(response_serialized) + serial_port.write(response_base64) + serial_port.write(b"\0") + + +def pb_exception_handler(func): + def inner_function(*args, **kwargs): + try: + func(*args, **kwargs) + except protobuf.message.DecodeError as exc: + print(exc) + return inner_function -def handle_message_reset(reset: bool) -> None: - print("Reset received:", reset) +def handle_message_reset() -> None: + print("Reset received") -def handle_message_menu(menu: PB_Menu) -> None: +@pb_exception_handler +def handle_message_menu(message: bytes) -> None: + menu = PB_Menu() + menu.ParseFromString(message) print("Received new menu:") print(json_format.MessageToDict(menu)) -def handle_message_hello(hello: PB_ReqHello) -> None: +@pb_exception_handler +def handle_message_hello(message: bytes) -> None: + hello = PB_ReqHello() + hello.ParseFromString(message) print(f"Received Hello request with number={hello.number} and message='{hello.message}'") - response = PB_ExampleInputMessage() - response.resp_hello.number = -hello.number - send_response(response) + response = PB_RespHello() + response.number = -hello.number + send_response(resp_hello_uuid, response) -def handle_message_ping(ping: PB_ReqPing) -> None: +@pb_exception_handler +def handle_message_ping(message: bytes) -> None: + ping = PB_ReqPing() + ping.ParseFromString(message) print(f"Received Ping request with color={PB_Color.Name(ping.color)}") - response = PB_ExampleInputMessage() - response.resp_ping.color = PB_Color.BLUE - send_response(response) + response = PB_RespPing() + response.color = PB_Color.BLUE + send_response(resp_ping_uuid, response) -def handle_message_pong(pong: PB_ReqPong) -> None: +@pb_exception_handler +def handle_message_pong(message: bytes) -> None: + pong = PB_ReqPong() + pong.ParseFromString(message) print(f"Received Pong request with pose={{x={pong.pose.x}, y={pong.pose.y}, angle={pong.pose.O}}}") - response = PB_ExampleInputMessage() - response.resp_pong.new_pose.x = -pong.pose.x - response.resp_pong.new_pose.y = -pong.pose.y - response.resp_pong.new_pose.O = -pong.pose.O - send_response(response) + response = PB_RespPong() + response.new_pose.x = -pong.pose.x + response.new_pose.y = -pong.pose.y + response.new_pose.O = -pong.pose.O + send_response(resp_pong_uuid, response) request_handlers = { - "reset": handle_message_reset, - "menu": handle_message_menu, - "req_hello": handle_message_hello, - "req_ping": handle_message_ping, - "req_pong": handle_message_pong + reset_uuid: handle_message_reset, + menu_uuid: handle_message_menu, + req_hello_uuid: handle_message_hello, + req_ping_uuid: handle_message_ping, + req_pong_uuid: handle_message_pong } -def decode_message(encoded_message: bytes) -> None: - try: - message = PB_ExampleOutputMessage() - message.ParseFromString(encoded_message) - except protobuf.message.DecodeError as exc: - print(exc) - return -1 - - message_type = message.WhichOneof("type") +def handle_message(uuid: int, pb_message: bytes = b"") -> None: + request_handler = request_handlers.get(uuid) + if not request_handler: + print(f"No handler found for message uuid '{uuid}'") + return - request_handler = request_handlers.get(message_type) - if request_handler: - request_handler(getattr(message, message_type)) + if not pb_message: + request_handler() else: - print(f"No handler found for message type '{message_type}'") + request_handler(pb_message) def main( @@ -97,17 +128,24 @@ def main( serial_port.open() while(True): - # Read next base64 message - base64_message = serial_port.readline() + # Read next message + message = serial_port.readline() + message = message.rstrip(b"\n") + + # Get message uuid on first bytes + uuid = int.from_bytes(message[:4], "little") + + if len(message) == 4: + handle_message(uuid) + continue - # Base64 decoding try: - pb_message = base64.decodebytes(base64_message) + pb_message = base64.decodebytes(message[4:]) except binascii.Error: - print("Failed to decode base64 message.") + print(f"Failed to decode base64 message (uuid={uuid}).") continue - decode_message(pb_message) + handle_message(uuid, pb_message) if __name__ == "__main__": diff --git a/lib/wizard/Wizard.cpp b/lib/wizard/Wizard.cpp index 6effc07a1..c259b7bcc 100644 --- a/lib/wizard/Wizard.cpp +++ b/lib/wizard/Wizard.cpp @@ -1,23 +1,28 @@ // Project includes #include "wizard/Wizard.hpp" -#include "uartpb_config.hpp" + +#include namespace cogip { namespace wizard { -static PB_OutputMessage output_message; -static bool queue_claimed = false; +constexpr cogip::uartpb::uuid_t wizard_uuid = 1525532810; Wizard::Wizard(cogip::uartpb::UartProtobuf *uartpb) : uartpb_(uartpb) { event_queue_init_detached(&queue_); event_.super.list_node.next = nullptr; + uartpb->register_message_handler(wizard_uuid, std::bind(&Wizard::handle_response, this, std::placeholders::_1)); } -void Wizard::handle_response(const PB_Message &pb_message) +void Wizard::handle_response(cogip::uartpb::ReadBuffer *buffer) { - event_.pb_message = pb_message; + EmbeddedProto::Error error = event_.pb_message.deserialize(*buffer); + if (error != EmbeddedProto::Error::NO_ERRORS) { + std::cout << "Wizard: Protobuf deserialization error: " << static_cast(error) << std::endl; + return; + } event_post(&queue_, (event_t *)&event_); } @@ -27,13 +32,12 @@ const Wizard::PB_Message &Wizard::request(const PB_Message &request) return request; } - if (! queue_claimed) { + if (! queue_claimed_) { event_queue_claim(&queue_); - queue_claimed = true; + queue_claimed_ = true; } - output_message.set_wizard(request); - uartpb_->send_message(output_message); + uartpb_->send_message(wizard_uuid, &request); wizard_event_t *event = (wizard_event_t *)event_wait(&queue_); return event->pb_message; diff --git a/lib/wizard/include/wizard/Wizard.hpp b/lib/wizard/include/wizard/Wizard.hpp index 799f066b9..6ef262d48 100644 --- a/lib/wizard/include/wizard/Wizard.hpp +++ b/lib/wizard/include/wizard/Wizard.hpp @@ -74,7 +74,7 @@ class Wizard { /// Message handler for responses. void handle_response( - const PB_Message &pb_message ///< [in] received message + cogip::uartpb::ReadBuffer *buffer ///< [in] buffer containing the received message ); /// Send a request and wait for the response. @@ -93,6 +93,7 @@ class Wizard { cogip::uartpb::UartProtobuf *uartpb_; ///< uartpb pointer used to send/receive messages wizard_event_t event_; ///< event containing the response event_queue_t queue_; ///< queue receiving response events + bool queue_claimed_ = false; ///< whether event queue has been claimed on the thread or not }; } // namespace wizard diff --git a/platforms/pegasus/platform.cpp b/platforms/pegasus/platform.cpp index bdbb144fe..c74a30ae4 100644 --- a/platforms/pegasus/platform.cpp +++ b/platforms/pegasus/platform.cpp @@ -22,7 +22,6 @@ #include "lidar_obstacles.hpp" #include "trace_utils.hpp" -#include "uartpb_config.hpp" #include "PB_Command.hpp" #include "PB_State.hpp" @@ -80,7 +79,12 @@ PB_Statesend_message(output_message); + uartpb->send_message(state_uuid, &pb_state); } void pf_init_quadpid_params(ctrl_quadpid_parameters_t ctrl_quadpid_params) @@ -257,11 +260,25 @@ cogip::wizard::Wizard *pf_get_wizard() return wizard; } +void handle_copilot_connected([[maybe_unused]] cogip::uartpb::ReadBuffer *buffer) +{ + pf_set_copilot_connected(true); + std::cout << "Copilot connected" << std::endl; + if (cogip::shell::current_menu) { + cogip::shell::current_menu->send_pb_message(); + } +} + +void handle_copilot_disconnected([[maybe_unused]] cogip::uartpb::ReadBuffer *buffer) +{ + pf_set_copilot_connected(false); + std::cout << "Copilot disconnected" << std::endl; +} + void pf_init(void) { /* Initialize UARTPB */ uartpb = new cogip::uartpb::UartProtobuf( - cogip::app::app_uartpb_message_handler, UART_DEV(1) ); @@ -272,9 +289,10 @@ void pf_init(void) } else { cogip::shell::register_uartpb(uartpb); + uartpb->register_message_handler(copilot_connected_uuid, handle_copilot_connected); + uartpb->register_message_handler(copilot_disconnected_uuid, handle_copilot_disconnected); uartpb->start_reader(); - output_message.set_reset(true); - uartpb->send_message(output_message); + uartpb->send_message(reset_uuid); } #ifdef MODULE_SHELL_PLATFORMS diff --git a/platforms/pf_test/platform.cpp b/platforms/pf_test/platform.cpp index 1103cc9c0..018eb370b 100644 --- a/platforms/pf_test/platform.cpp +++ b/platforms/pf_test/platform.cpp @@ -22,7 +22,6 @@ #include "lidar_obstacles.hpp" #include "trace_utils.hpp" -#include "uartpb_config.hpp" #include "PB_Command.hpp" #include "PB_State.hpp" @@ -80,7 +79,12 @@ PB_Statesend_message(output_message); + uartpb->send_message(state_uuid, &pb_state); } void pf_init_quadpid_params(ctrl_quadpid_parameters_t ctrl_quadpid_params) @@ -250,11 +253,25 @@ cogip::wizard::Wizard *pf_get_wizard() return wizard; } +void handle_copilot_connected([[maybe_unused]] cogip::uartpb::ReadBuffer *buffer) +{ + pf_set_copilot_connected(true); + std::cout << "Copilot connected" << std::endl; + if (cogip::shell::current_menu) { + cogip::shell::current_menu->send_pb_message(); + } +} + +void handle_copilot_disconnected([[maybe_unused]] cogip::uartpb::ReadBuffer *buffer) +{ + pf_set_copilot_connected(false); + std::cout << "Copilot disconnected" << std::endl; +} + void pf_init(void) { /* Initialize UARTPB */ uartpb = new cogip::uartpb::UartProtobuf( - cogip::app::app_uartpb_message_handler, UART_DEV(1) ); @@ -265,9 +282,10 @@ void pf_init(void) } else { cogip::shell::register_uartpb(uartpb); + uartpb->register_message_handler(copilot_connected_uuid, handle_copilot_connected); + uartpb->register_message_handler(copilot_disconnected_uuid, handle_copilot_disconnected); uartpb->start_reader(); - output_message.set_reset(true); - uartpb->send_message(output_message); + uartpb->send_message(reset_uuid); } #ifdef MODULE_SHELL_PLATFORMS diff --git a/sys/shell_menu/Menu.cpp b/sys/shell_menu/Menu.cpp index ef85c6662..3797bc7b1 100644 --- a/sys/shell_menu/Menu.cpp +++ b/sys/shell_menu/Menu.cpp @@ -4,10 +4,6 @@ // System includes #include -#ifdef MODULE_UARTPB -# include "uartpb_config.hpp" -#endif - #include "PB_Menu.hpp" namespace cogip { @@ -83,7 +79,7 @@ void Menu::enter(void) i++; } - COGIP_DEBUG_COUT("Enter shell menu: " << current_menu->name().c_str()); + COGIP_DEBUG_COUT("Enter shell menu: " << current_menu->name()); #ifdef MODULE_UARTPB send_pb_message(); @@ -111,14 +107,11 @@ void Menu::update_pb_message(void) } #ifdef MODULE_UARTPB -static PB_OutputMessage output_message; - void Menu::send_pb_message(void) { if (uart_protobuf) { update_pb_message(); - output_message.set_menu(pb_message_); - uart_protobuf->send_message(output_message); + uart_protobuf->send_message(menu_uuid, &pb_message_); } } #endif diff --git a/sys/shell_menu/include/shell_menu/shell_menu.hpp b/sys/shell_menu/include/shell_menu/shell_menu.hpp index ba0c7a9d2..67b8856f2 100644 --- a/sys/shell_menu/include/shell_menu/shell_menu.hpp +++ b/sys/shell_menu/include/shell_menu/shell_menu.hpp @@ -24,6 +24,11 @@ namespace cogip { namespace shell { +#ifdef MODULE_UARTPB +inline constexpr uartpb::uuid_t command_uuid = 2168120333; ///< uuid for uartpb +inline constexpr uartpb::uuid_t menu_uuid = 1485239280; ///< uuid for uartpb +#endif + extern Menu root_menu; ///< root menu extern Menu *current_menu; ///< pointer to the current menu extern std::list global_commands; ///< global commands, available in all menus @@ -50,7 +55,7 @@ void register_uartpb( ); /// Handle and execute a command coming from a Protobuf message -void handle_pb_command(const Command::PB_Message &pb_command); +void handle_pb_command(cogip::uartpb::ReadBuffer *buffer); #endif } // namespace shell diff --git a/sys/shell_menu/shell_menu.cpp b/sys/shell_menu/shell_menu.cpp index 2ba1c1460..d61a5755a 100644 --- a/sys/shell_menu/shell_menu.cpp +++ b/sys/shell_menu/shell_menu.cpp @@ -17,6 +17,7 @@ shell_command_t current_commands[NB_SHELL_COMMANDS]; #ifdef MODULE_UARTPB cogip::uartpb::UartProtobuf *uart_protobuf = nullptr; +static Command::PB_Message pb_command; #endif // Callbacks for default global commands @@ -97,9 +98,11 @@ void rename_command(const std::string &old_name, const std::string &new_name) } #ifdef MODULE_UARTPB + void register_uartpb(cogip::uartpb::UartProtobuf *uartpb_ptr) { uart_protobuf = uartpb_ptr; + uartpb_ptr->register_message_handler(command_uuid, handle_pb_command); } /// Execute a shell command callback using arguments from Protobuf message. @@ -142,10 +145,11 @@ static void run_pb_command_(Command *command, const Command::PB_Message &pb_comm command->handler()(argc, argv); } - // Handle a Protobuf command message -void handle_pb_command(const Command::PB_Message &pb_command) +void handle_pb_command(cogip::uartpb::ReadBuffer *buffer) { + pb_command.deserialize(*buffer); + if (cogip::shell::current_menu == nullptr) { COGIP_DEBUG_CERR( "Warning: received PB command before current_menu is initialized: " diff --git a/sys/uartpb/UartProtobuf.cpp b/sys/uartpb/UartProtobuf.cpp index 703d63c38..d22ca0bcb 100644 --- a/sys/uartpb/UartProtobuf.cpp +++ b/sys/uartpb/UartProtobuf.cpp @@ -1,5 +1,8 @@ #include "uartpb/UartProtobuf.hpp" +// System includes +#include + // RIOT includes #include "riot/chrono.hpp" #include "riot/thread.hpp" @@ -17,11 +20,9 @@ static ReadBuffer read_buffer_; ///< buffer used to decode static WriteBuffer write_buffer_; ///< buffer used to encode a message UartProtobuf::UartProtobuf( - message_handler_t message_handler, uart_t uart_dev, uint32_t uart_speed) : uart_dev_(uart_dev), uart_speed_(uart_speed) { - message_handler_ = message_handler; ringbuffer_init(&rx_buf_, rx_mem_, UART_BUFFER_SIZE); } @@ -53,42 +54,71 @@ void UartProtobuf::uart_rx_cb(uint8_t data) void UartProtobuf::message_reader() { + uuid_t uuid; msg_t msg; msg_t msg_queue[8]; msg_init_queue(msg_queue, 8); while (1) { + // Wait for a new message msg_receive(&msg); + + // Read and check message length uint32_t message_length = (uint32_t)msg.content.value; assert(message_length <= UARTPB_INPUT_MESSAGE_LENGTH_MAX); - read_buffer_.clear(); - ringbuffer_get(&rx_buf_, (char *)read_buffer_.get_base64_data(), message_length); - size_t res = read_buffer_.base64_decode(); - if (res > 0 && message_handler_) { - message_handler_(read_buffer_); + + // Read uuid + ringbuffer_get(&rx_buf_, (char *)&uuid, sizeof(uuid_t)); + message_length -= sizeof(uuid_t); + + // Check a handler corresponding to the uuid is registered + if (message_handlers_.count(uuid) != 1) { + std::cout << "Unknown message uuid: " << uuid << std::endl; + continue; } + + // Read Protobuf message if any + if (message_length > 0) { + read_buffer_.clear(); + ringbuffer_get(&rx_buf_, (char *)read_buffer_.get_base64_data(), message_length); + size_t res = read_buffer_.base64_decode(); + if (res <= 0) { + std::cout << "Failed to base64 decode Protobuf message (res = " << res << ")" << std::endl; + continue; + } + } + + message_handlers_[uuid](message_length > 0 ? &read_buffer_ : nullptr); } } - -bool UartProtobuf::send_message(const EmbeddedProto::MessageInterface &message) +bool UartProtobuf::send_message(uuid_t uuid, const EmbeddedProto::MessageInterface *message) { bool success = true; + size_t base64_size = 0; + char separator = '\n'; mutex_.lock(); - write_buffer_.clear(); - auto serialization_status = message.serialize(write_buffer_); - if(EmbeddedProto::Error::NO_ERRORS != serialization_status) { - puts("Failed to serialize Protobuf message."); - success = false; - } - else { - size_t base64_size = write_buffer_.base64_encode(); - if (base64_size == 0) { - puts("Failed to base64 encode Protobuf serialized message."); + + if (message) { + write_buffer_.clear(); + auto serialization_status = message->serialize(write_buffer_); + if(EmbeddedProto::Error::NO_ERRORS != serialization_status) { + puts("Failed to serialize Protobuf message."); success = false; } else { - uart_write(uart_dev_, write_buffer_.get_base64_data(), base64_size+1); + base64_size = write_buffer_.base64_encode(); + if (base64_size == 0) { + puts("Failed to base64 encode Protobuf serialized message."); + success = false; + } + } + } + if (success) { + uart_write(uart_dev_, (uint8_t *)&uuid, sizeof(uuid_t)); + if (message) { + uart_write(uart_dev_, write_buffer_.get_base64_data(), base64_size); } + uart_write(uart_dev_, (uint8_t *)&separator, 1); } mutex_.unlock(); @@ -96,6 +126,11 @@ bool UartProtobuf::send_message(const EmbeddedProto::MessageInterface &message) return success; } +void UartProtobuf::register_message_handler(uuid_t uuid, message_handler_t handler) +{ + message_handlers_[uuid] = handler; +} + } // namespace uartpb } // namespace cogip diff --git a/sys/uartpb/include/uartpb/UartProtobuf.hpp b/sys/uartpb/include/uartpb/UartProtobuf.hpp index 9fda20905..f98aa5f85 100644 --- a/sys/uartpb/include/uartpb/UartProtobuf.hpp +++ b/sys/uartpb/include/uartpb/UartProtobuf.hpp @@ -7,7 +7,9 @@ /// @brief Exchange Protobuf messages over UART module. /// @details This module provides a class that controls an UART to send and /// receive Protobuf messages using EmbbededProto. -/// A callback function must also be provided to handle decoded messages. +/// Each library/application using uartpb must define a unique id (32-bit integer +/// of type cogip::uartpb::uuid_t) and registrer a callback function to send +/// or receive their own messages. /// See `examples/uartb`. /// @{ /// @file @@ -20,6 +22,7 @@ #include "periph/uart.h" #include "ringbuffer.h" #include "thread.h" +#include "etl/map.h" #include "uartpb/uartpb.hpp" #include "uartpb/ReadBuffer.hpp" @@ -36,6 +39,12 @@ namespace cogip { namespace uartpb { +/// Custom type for uuids +using uuid_t = uint32_t; + +/// Prototype for incoming Protobuf message handlers +using message_handler_t = std::function; + /// Function called when data is received on serial port. /// This wrapper is used to call the uart_rx_cb() function from UartProtobuf class /// from a C context, passing the UartProtobuf instance pointer as first parameter. @@ -54,11 +63,9 @@ void *message_reader_wrapper( /// Generic UART Protobuf communication class. class UartProtobuf { public: - using message_handler_t = void (*)(cogip::uartpb::ReadBuffer &); /// Class constructor. UartProtobuf( - message_handler_t message_handler, ///< [in] callback to process the message after decoding uart_t uart_dev, ///< [in] UART device uint32_t uart_speed=230400U ///< [in] UART baud rate ); @@ -80,7 +87,17 @@ class UartProtobuf { /// Send message on serial port. /// @return true if message was encoded and sent, false otherwise - bool send_message(const EmbeddedProto::MessageInterface &message); + bool send_message( + uuid_t uuid, ///< [in] message uuid + const EmbeddedProto::MessageInterface *message = nullptr + ///< [in] message to send + ); + + /// Associate a message handle to a specific uuid + void register_message_handler( + uuid_t uuid, ///< [in] message uuid + message_handler_t handler ///< [in] message handler + ); private: uart_t uart_dev_; ///< UART device @@ -88,9 +105,9 @@ class UartProtobuf { kernel_pid_t reader_pid_; ///< reader thread PID ringbuffer_t rx_buf_; ///< ring buffer for UART incoming bytes uint32_t msg_length_ = 0; ///< message length - void (*message_handler_)(cogip::uartpb::ReadBuffer &); - ///< callback to process the message after decoding riot::mutex mutex_; ///< mutex protecting serial port access + etl::map message_handlers_; + ///< callbacks to process the message after decoding }; } // namespace uartpb diff --git a/sys/uartpb/include/uartpb/uartpb.hpp b/sys/uartpb/include/uartpb/uartpb.hpp index 5da0b59b3..8961c6d46 100644 --- a/sys/uartpb/include/uartpb/uartpb.hpp +++ b/sys/uartpb/include/uartpb/uartpb.hpp @@ -28,4 +28,8 @@ #define UARTPB_OUTPUT_MESSAGE_LENGTH_MAX (4*1024) ///< max outgoing message length #endif +#ifndef UARTPB_MAX_HANDLERS +#define UARTPB_MAX_HANDLERS 16 ///< max numbers of registered message handlers +#endif + /// @}