#pragma once #include #include #include #include #include #define PROTO_BUFFER_SIZE 2048 // Increased for chunked file transfer responses template struct MessageTraits; #define DEFINE_MESSAGE_TRAITS(DataType, field) \ template <> \ struct MessageTraits { \ static constexpr pb_size_t tag = socket_message_Message_##field##_tag; \ static void assign(socket_message_Message& msg, const socket_message_##DataType& data) { \ msg.message.field = data; \ } \ static const socket_message_##DataType& access(const socket_message_Message& msg) { \ return msg.message.field; \ } \ }; DEFINE_MESSAGE_TRAITS(IMUData, imu) DEFINE_MESSAGE_TRAITS(ModeData, mode) DEFINE_MESSAGE_TRAITS(AnalyticsData, analytics) DEFINE_MESSAGE_TRAITS(AnglesData, angles) DEFINE_MESSAGE_TRAITS(RSSIData, rssi) DEFINE_MESSAGE_TRAITS(KinematicData, kinematic_data) DEFINE_MESSAGE_TRAITS(IMUCalibrateData, imu_calibrate) DEFINE_MESSAGE_TRAITS(I2CScanData, i2c_scan) DEFINE_MESSAGE_TRAITS(PeripheralSettingsData, peripheral_settings) DEFINE_MESSAGE_TRAITS(ControllerData, controller_data) DEFINE_MESSAGE_TRAITS(WalkGaitData, walk_gait) DEFINE_MESSAGE_TRAITS(IMUCalibrateExecute, imu_calibrate_execute) DEFINE_MESSAGE_TRAITS(I2CScanDataRequest, i2c_scan_data_request) DEFINE_MESSAGE_TRAITS(PeripheralSettingsDataRequest, peripheral_settings_data_request) DEFINE_MESSAGE_TRAITS(ServoPWMData, servo_pwm) DEFINE_MESSAGE_TRAITS(ServoStateData, servo_state) DEFINE_MESSAGE_TRAITS(CorrelationRequest, correlation_request) DEFINE_MESSAGE_TRAITS(CorrelationResponse, correlation_response) // DEFINE_MESSAGE_TRAITS(FSDeleteRequest, fs_delete_request) // DEFINE_MESSAGE_TRAITS(FSDeleteResponse, fs_delete_response) // DEFINE_MESSAGE_TRAITS(FSMkdirRequest, fs_mkdir_request) // DEFINE_MESSAGE_TRAITS(FSMkdirResponse, fs_mkdir_response) // DEFINE_MESSAGE_TRAITS(FSListRequest, fs_list_request) // DEFINE_MESSAGE_TRAITS(FSListResponse, fs_list_response) // DEFINE_MESSAGE_TRAITS(FSDownloadStartRequest, fs_download_start_request) // DEFINE_MESSAGE_TRAITS(FSDownloadStartResponse, fs_download_start_response) // DEFINE_MESSAGE_TRAITS(FSDownloadChunkRequest, fs_download_chunk_request) // DEFINE_MESSAGE_TRAITS(FSDownloadChunkResponse, fs_download_chunk_response) // DEFINE_MESSAGE_TRAITS(FSUploadStartRequest, fs_upload_start_request) // DEFINE_MESSAGE_TRAITS(FSUploadStartResponse, fs_upload_start_response) // DEFINE_MESSAGE_TRAITS(FSUploadChunkRequest, fs_upload_chunk_request) // DEFINE_MESSAGE_TRAITS(FSUploadChunkResponse, fs_upload_chunk_response) // DEFINE_MESSAGE_TRAITS(FSCancelTransferRequest, fs_cancel_transfer_request) // DEFINE_MESSAGE_TRAITS(FSCancelTransferResponse, fs_cancel_transfer_response) #undef DEFINE_MESSAGE_TRAITS class ProtoDecoder { public: using SubscribeHandler = std::function; using UnsubscribeHandler = std::function; using PingHandler = std::function; void onSubscribe(SubscribeHandler handler) { subscribeHandler_ = handler; } void onUnsubscribe(UnsubscribeHandler handler) { unsubscribeHandler_ = handler; } void onPing(PingHandler handler) { pingHandler_ = handler; } template void on(std::function handler) { handlers_[MessageTraits::tag] = [handler, this](int clientId) { handler(MessageTraits::access(msg_), clientId); }; } bool decode(const uint8_t* data, size_t len, int clientId) { pb_istream_t stream = pb_istream_from_buffer(data, len); if (!pb_decode(&stream, socket_message_Message_fields, &msg_)) { return false; } switch (msg_.which_message) { case socket_message_Message_sub_notif_tag: if (subscribeHandler_) subscribeHandler_(msg_.message.sub_notif.tag, clientId); return true; case socket_message_Message_unsub_notif_tag: if (unsubscribeHandler_) unsubscribeHandler_(msg_.message.unsub_notif.tag, clientId); return true; case socket_message_Message_pingmsg_tag: if (pingHandler_) pingHandler_(clientId); return true; default: { auto it = handlers_.find(msg_.which_message); if (it != handlers_.end()) { it->second(clientId); return true; } return false; } } } private: socket_message_Message msg_ = socket_message_Message_init_zero; SubscribeHandler subscribeHandler_; UnsubscribeHandler unsubscribeHandler_; PingHandler pingHandler_; std::map> handlers_; };