From b3e0d4d0d6406ebb90facb12f820996fe542f79e Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Sat, 13 Jul 2024 18:28:15 +0200 Subject: [PATCH 01/20] use unsigned _BitInt instead of std::bitset in address --- include/utils/address.hpp | 49 +++++++++---------- src/borzoi/borzoi_converter.cpp | 4 +- src/l2/logical_link_control_formatter.cpp | 1 + .../circuit_mode_control_entity_formatter.cpp | 1 + src/l3/short_data_service_formatter.cpp | 1 + src/utils/address.cpp | 17 ++++--- 6 files changed, 38 insertions(+), 35 deletions(-) diff --git a/include/utils/address.hpp b/include/utils/address.hpp index 2bed57d..6348297 100644 --- a/include/utils/address.hpp +++ b/include/utils/address.hpp @@ -9,7 +9,6 @@ #pragma once #include "utils/bit_vector.hpp" -#include #include #include #include @@ -33,14 +32,14 @@ class Address { ussi_ == address_type.ussi_ && smi_ == address_type.smi_ && usage_marker_ == address_type.usage_marker_; } - void set_country_code(uint64_t country_code) { country_code_ = country_code; } - void set_network_code(uint64_t network_code) { network_code_ = network_code; } - void set_sna(uint64_t sna) { sna_ = sna; } - void set_ssi(uint64_t ssi) { ssi_ = ssi; } - void set_event_label(uint64_t event_label) { event_label_ = event_label; } - void set_ussi(uint64_t ussi) { ussi_ = ussi; } - void set_smi(uint64_t smi) { smi_ = smi; } - void set_usage_marker(uint64_t usage_marker) { usage_marker_ = usage_marker; } + void set_country_code(unsigned _BitInt(10) country_code) { country_code_ = country_code; } + void set_network_code(unsigned _BitInt(14) network_code) { network_code_ = network_code; } + void set_sna(unsigned _BitInt(8) sna) { sna_ = sna; } + void set_ssi(unsigned _BitInt(24) ssi) { ssi_ = ssi; } + void set_event_label(unsigned _BitInt(10) event_label) { event_label_ = event_label; } + void set_ussi(unsigned _BitInt(24) ussi) { ussi_ = ussi; } + void set_smi(unsigned _BitInt(24) smi) { smi_ = smi; } + void set_usage_marker(unsigned _BitInt(6) usage_marker) { usage_marker_ = usage_marker; } [[nodiscard]] auto country_code() const noexcept { return country_code_; } [[nodiscard]] auto network_code() const noexcept { return network_code_; } @@ -87,14 +86,14 @@ class Address { friend auto operator<<(std::ostream& stream, const Address& address_type) -> std::ostream&; private: - std::optional> country_code_; - std::optional> network_code_; - std::optional> sna_; - std::optional> ssi_; - std::optional> event_label_; - std::optional> ussi_; - std::optional> smi_; - std::optional> usage_marker_; + std::optional country_code_; + std::optional network_code_; + std::optional sna_; + std::optional ssi_; + std::optional event_label_; + std::optional ussi_; + std::optional smi_; + std::optional usage_marker_; }; namespace std { @@ -114,28 +113,28 @@ template <> struct adl_serializer
{ std::cout << address_type << std::endl << std::flush; if (address_type.country_code()) { - j["country_code"] = address_type.country_code().value().to_ulong(); + j["country_code"] = static_cast(address_type.country_code().value()); } if (address_type.network_code()) { - j["network_code"] = address_type.network_code().value().to_ulong(); + j["network_code"] = static_cast(address_type.network_code().value()); } if (address_type.sna()) { - j["sna"] = address_type.sna().value().to_ulong(); + j["sna"] = static_cast(address_type.sna().value()); } if (address_type.ssi()) { - j["ssi"] = address_type.ssi().value().to_ulong(); + j["ssi"] = static_cast(address_type.ssi().value()); } if (address_type.event_label()) { - j["event_label"] = address_type.event_label().value().to_ulong(); + j["event_label"] = static_cast(address_type.event_label().value()); } if (address_type.ussi()) { - j["ussi"] = address_type.ussi().value().to_ulong(); + j["ussi"] = static_cast(address_type.ussi().value()); } if (address_type.smi()) { - j["smi"] = address_type.smi().value().to_ulong(); + j["smi"] = static_cast(address_type.smi().value()); } if (address_type.usage_marker()) { - j["usage_marker"] = address_type.usage_marker().value().to_ulong(); + j["usage_marker"] = static_cast(address_type.usage_marker().value()); } } }; diff --git a/src/borzoi/borzoi_converter.cpp b/src/borzoi/borzoi_converter.cpp index 5f2f011..083bbe6 100644 --- a/src/borzoi/borzoi_converter.cpp +++ b/src/borzoi/borzoi_converter.cpp @@ -21,8 +21,8 @@ inline static auto get_time() -> std::string { auto BorzoiConverter::to_json(ShortDataServicePacket* packet) -> nlohmann::json { auto message = nlohmann::json::object(); /// TODO: this may throw - message["source_ssi"] = packet->sds_data_->address_.ssi()->to_ulong(); - message["destination_ssi"] = packet->address_.ssi()->to_ulong(); + message["source_ssi"] = static_cast(packet->sds_data_->address_.ssi().value()); + message["destination_ssi"] = static_cast(packet->address_.ssi().value()); message["protocol_identifier"] = static_cast(packet->protocol_identifier_); message["telegram_type"] = "SDS"; message["data"] = nlohmann::json::array(); diff --git a/src/l2/logical_link_control_formatter.cpp b/src/l2/logical_link_control_formatter.cpp index 52af58d..400ffd1 100644 --- a/src/l2/logical_link_control_formatter.cpp +++ b/src/l2/logical_link_control_formatter.cpp @@ -7,6 +7,7 @@ */ #include "l2/logical_link_control_packet.hpp" +#include auto operator<<(std::ostream& stream, const BasicLinkInformation& bli) -> std::ostream& { stream << " Basic Link Information: " << to_string(bli.basic_link_type_); diff --git a/src/l3/circuit_mode_control_entity_formatter.cpp b/src/l3/circuit_mode_control_entity_formatter.cpp index b7a2787..8c097c4 100644 --- a/src/l3/circuit_mode_control_entity_formatter.cpp +++ b/src/l3/circuit_mode_control_entity_formatter.cpp @@ -7,6 +7,7 @@ */ #include "l3/circuit_mode_control_entity_packet.hpp" +#include auto operator<<(std::ostream& stream, const SdsData& sds) -> std::ostream& { if (sds.area_selection_) { diff --git a/src/l3/short_data_service_formatter.cpp b/src/l3/short_data_service_formatter.cpp index 66ec319..7d9e1d5 100644 --- a/src/l3/short_data_service_formatter.cpp +++ b/src/l3/short_data_service_formatter.cpp @@ -7,6 +7,7 @@ */ #include "l3/short_data_service_packet.hpp" +#include auto operator<<(std::ostream& stream, const ShortLocationReport& slr) -> std::ostream& { stream << " Short Location Report" << std::endl; diff --git a/src/utils/address.cpp b/src/utils/address.cpp index b809ecf..a2bfea4 100644 --- a/src/utils/address.cpp +++ b/src/utils/address.cpp @@ -1,30 +1,31 @@ #include "utils/address.hpp" +#include #include auto operator<<(std::ostream& stream, const Address& address_type) -> std::ostream& { if (address_type.country_code_) { - stream << "Country Code: " << address_type.country_code_.value().to_ulong() << " "; + stream << "Country Code: " << std::bitset<10>(*address_type.country_code_) << " "; } if (address_type.network_code_) { - stream << "Network Code: " << address_type.network_code_.value().to_ulong() << " "; + stream << "Network Code: " << std::bitset<14>(*address_type.network_code_) << " "; } if (address_type.sna_) { - stream << "SNA: " << address_type.sna_.value().to_ulong() << " "; + stream << "SNA: " << std::bitset<8>(*address_type.sna_) << " "; } if (address_type.ssi_) { - stream << "SSI: " << address_type.ssi_.value().to_ulong() << " "; + stream << "SSI: " << std::bitset<24>(*address_type.ssi_) << " "; } if (address_type.ussi_) { - stream << "USSI: " << address_type.ussi_.value().to_ulong() << " "; + stream << "USSI: " << std::bitset<24>(*address_type.ussi_) << " "; } if (address_type.smi_) { - stream << "SMI: " << address_type.smi_.value().to_ulong() << " "; + stream << "SMI: " << std::bitset<24>(*address_type.smi_) << " "; } if (address_type.event_label_) { - stream << "Event Label: " << address_type.event_label_.value().to_ulong() << " "; + stream << "Event Label: " << std::bitset<10>(*address_type.event_label_) << " "; } if (address_type.usage_marker_) { - stream << "Usage Marker: " << address_type.usage_marker_.value().to_ulong() << " "; + stream << "Usage Marker: " << std::bitset<6>(*address_type.usage_marker_) << " "; } return stream; From 4d87c65933eb5c68b5e9dd09e7b06356a67194d9 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Tue, 23 Jul 2024 16:01:16 +0200 Subject: [PATCH 02/20] implementation of serialization/deserealization between packet types/data and json --- include/l2/logical_link_control_packet.hpp | 8 +- include/l2/upper_mac_packet.hpp | 78 ++++++++++++++++--- .../l3/circuit_mode_control_entity_packet.hpp | 10 ++- include/l3/mobile_link_entity_packet.hpp | 4 +- include/l3/mobile_management_packet.hpp | 18 ++++- include/l3/short_data_service_packet.hpp | 1 + include/nlohmann_std_optional.hpp | 32 ++++++++ include/nlohmann_std_variant.hpp | 53 +++++++++++++ include/nlohmann_unsigned_bitint.hpp | 19 +++++ include/utils/address.hpp | 39 ++-------- include/utils/bit_vector.hpp | 3 + include/utils/type234_parser.hpp | 15 ++-- src/l3/mobile_management_formatter.cpp | 1 + 13 files changed, 219 insertions(+), 62 deletions(-) create mode 100644 include/nlohmann_std_optional.hpp create mode 100644 include/nlohmann_std_variant.hpp create mode 100644 include/nlohmann_unsigned_bitint.hpp diff --git a/include/l2/logical_link_control_packet.hpp b/include/l2/logical_link_control_packet.hpp index d4e3dec..d37b487 100644 --- a/include/l2/logical_link_control_packet.hpp +++ b/include/l2/logical_link_control_packet.hpp @@ -51,10 +51,12 @@ struct BasicLinkInformation { std::optional n_s_; std::optional fcs_good_; - BasicLinkInformation() = delete; + BasicLinkInformation() = default; /// construct a BasicLinkInformation from a BitVector explicit BasicLinkInformation(BitVector& data); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(BasicLinkInformation, basic_link_type_, n_r_, n_s_, fcs_good_) }; auto operator<<(std::ostream& stream, const BasicLinkInformation& bli) -> std::ostream&; @@ -65,9 +67,11 @@ struct LogicalLinkControlPacket : public UpperMacCPlaneSignallingPacket { /// The data that is passed from the Logical Link Control layer to the Mobile Link Entity BitVector tl_sdu_; - LogicalLinkControlPacket() = delete; + LogicalLinkControlPacket() = default; explicit LogicalLinkControlPacket(const UpperMacCPlaneSignallingPacket& packet); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(LogicalLinkControlPacket, basic_link_information_, tl_sdu_) }; auto operator<<(std::ostream& stream, const LogicalLinkControlPacket& llc) -> std::ostream&; \ No newline at end of file diff --git a/include/l2/upper_mac_packet.hpp b/include/l2/upper_mac_packet.hpp index 3fd9a92..cb0ed44 100644 --- a/include/l2/upper_mac_packet.hpp +++ b/include/l2/upper_mac_packet.hpp @@ -76,11 +76,15 @@ struct AccessCodeDefinition { unsigned _BitInt(4) timeslot_pointer_; unsigned _BitInt(3) minimum_pdu_priority_; - AccessCodeDefinition() = delete; + AccessCodeDefinition() = default; /// construct a AccessCodeDefinition from a BitVector explicit AccessCodeDefinition(BitVector& data); friend auto operator<<(std::ostream& stream, const AccessCodeDefinition& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(AccessCodeDefinition, immediate_, waiting_time_, + number_of_random_access_transmissions_on_up_link_, frame_length_factor_, + timeslot_pointer_, minimum_pdu_priority_) }; auto operator<<(std::ostream& stream, const AccessCodeDefinition& element) -> std::ostream&; @@ -94,11 +98,15 @@ struct ExtendedServiceBroadcastSection1 { unsigned _BitInt(1) section3_sent_; unsigned _BitInt(1) section4_sent_; - ExtendedServiceBroadcastSection1() = delete; + ExtendedServiceBroadcastSection1() = default; /// construct a ExtendedServiceBroadcastSection1 from a BitVector explicit ExtendedServiceBroadcastSection1(BitVector& data); friend auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection1& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ExtendedServiceBroadcastSection1, data_priority_supported_, + extended_advanced_links_and_max_ublck_supported_, qos_negotiation_supported_, + d8psk_service_, section2_sent_, section3_sent_, section4_sent_) }; auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection1& element) -> std::ostream&; @@ -110,11 +118,14 @@ struct ExtendedServiceBroadcastSection2 { unsigned _BitInt(1) service_150Qam_; unsigned _BitInt(3) reserved_; - ExtendedServiceBroadcastSection2() = delete; + ExtendedServiceBroadcastSection2() = default; /// construct a ExtendedServiceBroadcastSection2 from a BitVector explicit ExtendedServiceBroadcastSection2(BitVector& data); friend auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection2& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ExtendedServiceBroadcastSection2, service_25Qam_, service_50Qam_, service_100Qam_, + service_150Qam_, reserved_) }; auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection2& element) -> std::ostream&; @@ -122,11 +133,13 @@ auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection2& el struct ExtendedServiceBroadcastSection3 { unsigned _BitInt(7) reserved_; - ExtendedServiceBroadcastSection3() = delete; + ExtendedServiceBroadcastSection3() = default; /// construct a ExtendedServiceBroadcastSection3 from a BitVector explicit ExtendedServiceBroadcastSection3(BitVector& data); friend auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection3& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ExtendedServiceBroadcastSection3, reserved_) }; auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection3& element) -> std::ostream&; @@ -134,11 +147,13 @@ auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection3& el struct ExtendedServiceBroadcastSection4 { unsigned _BitInt(7) reserved_; - ExtendedServiceBroadcastSection4() = delete; + ExtendedServiceBroadcastSection4() = default; /// construct a ExtendedServiceBroadcastSection4 from a BitVector explicit ExtendedServiceBroadcastSection4(BitVector& data); friend auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection4& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ExtendedServiceBroadcastSection4, reserved_) }; auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection4& element) -> std::ostream&; @@ -153,11 +168,14 @@ struct ExtendedServiceBroadcast { std::optional section3_; std::optional section4_; - ExtendedServiceBroadcast() = delete; + ExtendedServiceBroadcast() = default; /// construct a ExtendedServiceBroadcast from a BitVector explicit ExtendedServiceBroadcast(BitVector& data); friend auto operator<<(std::ostream& stream, const ExtendedServiceBroadcast& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ExtendedServiceBroadcast, security_information_, sdstl_addressing_method_, + gck_supported_, section1_, section2_, section3_, section4_) }; auto operator<<(std::ostream& stream, const ExtendedServiceBroadcast& element) -> std::ostream&; @@ -194,7 +212,7 @@ struct SystemInfo { unsigned _BitInt(1) air_interface_encryption_service_; unsigned _BitInt(1) advanced_link_supported_; - SystemInfo() = delete; + SystemInfo() = default; /// construct a SystemInfo from a BitVector explicit SystemInfo(BitVector& data); @@ -205,6 +223,15 @@ struct SystemInfo { [[nodiscard]] auto uplink_frequency() const noexcept -> int32_t; friend auto operator<<(std::ostream& stream, const SystemInfo& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE( + SystemInfo, main_carrier_, frequency_band_, offset_, duplex_spacing_field_, reverse_operation_, + number_secondary_control_channels_main_carrier_, ms_txpwr_max_cell_, rxlev_access_min_, access_parameter_, + radio_downlink_timeout_, hyper_frame_number_, common_cipher_key_identifier_or_static_cipher_key_version_number_, + even_multi_frame_definition_for_ts_mode_, odd_multi_frame_definition_for_ts_mode_, defaults_for_access_code_a_, + extended_service_broadcast_, location_area_, subscriber_class_, registration_, deregistration_, priority_cell_, + minimum_mode_service_, migration_, system_wide_service_, tetra_voice_service_, circuit_mode_data_service_, + sndcp_service_, air_interface_encryption_service_, advanced_link_supported_) }; auto operator<<(std::ostream& stream, const SystemInfo& element) -> std::ostream&; @@ -216,11 +243,14 @@ struct AccessDefine { std::optional subscriber_class_bitmap_; std::optional gssi_; - AccessDefine() = delete; + AccessDefine() = default; /// construct a AccessDefine from a BitVector explicit AccessDefine(BitVector& data); friend auto operator<<(std::ostream& stream, const AccessDefine& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(AccessDefine, common_or_assigned_control_channel_flag_, access_code_, + access_code_definition_, subscriber_class_bitmap_, gssi_) }; auto operator<<(std::ostream& stream, const AccessDefine& element) -> std::ostream&; @@ -235,6 +265,8 @@ struct UpperMacBroadcastPacket { std::optional access_define_; friend auto operator<<(std::ostream& stream, const UpperMacBroadcastPacket& packet) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(UpperMacBroadcastPacket, logical_channel_, type_, sysinfo_, access_define_) }; auto operator<<(std::ostream& stream, const UpperMacBroadcastPacket& packet) -> std::ostream&; @@ -297,11 +329,14 @@ struct ExtendedCarrierNumbering { unsigned _BitInt(3) duplex_spacing_; unsigned _BitInt(1) reverse_operation_; - ExtendedCarrierNumbering() = delete; + ExtendedCarrierNumbering() = default; /// construct a ExtendedCarrierNumbering from a BitVector explicit ExtendedCarrierNumbering(BitVector& data); friend auto operator<<(std::ostream& stream, const ExtendedCarrierNumbering& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ExtendedCarrierNumbering, frequency_band_, offset_, duplex_spacing_, + reverse_operation_) }; auto operator<<(std::ostream& stream, const ExtendedCarrierNumbering& element) -> std::ostream&; @@ -324,11 +359,16 @@ struct AugmentedChannelAllocation { std::optional conditional_element_b_; unsigned _BitInt(1) further_augmentation_flag_; - AugmentedChannelAllocation() = delete; + AugmentedChannelAllocation() = default; /// construct a AugmentedChannelAllocation from a BitVector explicit AugmentedChannelAllocation(BitVector& data); friend auto operator<<(std::ostream& stream, const AugmentedChannelAllocation& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(AugmentedChannelAllocation, up_downlink_assigned_, bandwidth_, modulation_mode_, + maximum_uplink_qam_modulation_level_, conforming_channel_status_, bs_link_imbalance_, + bs_transmit_power_relative_to_main_carrier_, napping_status_, napping_information_, + conditional_element_a_, conditional_element_b_, further_augmentation_flag_) }; auto operator<<(std::ostream& stream, const AugmentedChannelAllocation& element) -> std::ostream&; @@ -348,11 +388,16 @@ struct ChannelAllocationElement { std::optional augmented_channel_allocation_; - ChannelAllocationElement() = delete; + ChannelAllocationElement() = default; /// construct a ChannelAllocationElement from a BitVector explicit ChannelAllocationElement(BitVector& data); friend auto operator<<(std::ostream& stream, const ChannelAllocationElement& element) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ChannelAllocationElement, allocation_type_, timeslot_assigned_, + up_downlink_assigned_, clch_permission_, cell_change_flag_, carrier_number_, + extended_carrier_numbering_, monitoring_pattern_, frame18_monitoring_pattern_, + augmented_channel_allocation_) }; auto operator<<(std::ostream& stream, const ChannelAllocationElement& element) -> std::ostream&; @@ -418,6 +463,7 @@ struct UpperMacCPlaneSignallingPacket { /// check if this packet is sent on uplink [[nodiscard]] auto is_uplink() const -> bool { return is_uplink_burst(burst_type_); }; + UpperMacCPlaneSignallingPacket() = default; UpperMacCPlaneSignallingPacket(const UpperMacCPlaneSignallingPacket&) = default; UpperMacCPlaneSignallingPacket(BurstType burst_type, LogicalChannel logical_channel, MacPacketType type) : burst_type_(burst_type) @@ -427,6 +473,12 @@ struct UpperMacCPlaneSignallingPacket { virtual ~UpperMacCPlaneSignallingPacket() = default; friend auto operator<<(std::ostream& stream, const UpperMacCPlaneSignallingPacket& packet) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(UpperMacCPlaneSignallingPacket, burst_type_, logical_channel_, type_, encrypted_, + address_, fragmentation_, fragmentation_on_stealling_channel_, + reservation_requirement_, tm_sdu_, encryption_mode_, + immediate_napping_permission_flag_, basic_slot_granting_element_, position_of_grant_, + channel_allocation_element_, random_access_flag_, power_control_element_) }; auto operator<<(std::ostream& stream, const UpperMacCPlaneSignallingPacket& packet) -> std::ostream&; @@ -440,6 +492,8 @@ struct UpperMacUPlaneSignallingPacket { BitVector tm_sdu_; friend auto operator<<(std::ostream& stream, const UpperMacUPlaneSignallingPacket& packet) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(UpperMacUPlaneSignallingPacket, logical_channel_, type_, tm_sdu_) }; auto operator<<(std::ostream& stream, const UpperMacUPlaneSignallingPacket& packet) -> std::ostream&; @@ -451,6 +505,8 @@ struct UpperMacUPlaneTrafficPacket { BitVector data_; friend auto operator<<(std::ostream& stream, const UpperMacUPlaneTrafficPacket& packet) -> std::ostream&; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(UpperMacUPlaneTrafficPacket, logical_channel_, data_) }; auto operator<<(std::ostream& stream, const UpperMacUPlaneTrafficPacket& packet) -> std::ostream&; \ No newline at end of file diff --git a/include/l3/circuit_mode_control_entity_packet.hpp b/include/l3/circuit_mode_control_entity_packet.hpp index e312594..30e188e 100644 --- a/include/l3/circuit_mode_control_entity_packet.hpp +++ b/include/l3/circuit_mode_control_entity_packet.hpp @@ -9,9 +9,11 @@ #pragma once #include "l3/mobile_link_entity_packet.hpp" +#include "nlohmann_std_variant.hpp" // IWYU pragma: keep #include "utils/address.hpp" #include "utils/bit_vector.hpp" #include "utils/type234_parser.hpp" +#include #include #include @@ -296,13 +298,13 @@ struct SdsData { // This map may contain the "External subscriber number" and "DM-MS address" Type234Parser::Map optional_elements_; - private: SdsData() = default; - public: static auto from_d_sds_data(BitVector& data) -> SdsData; static auto from_u_sds_data(BitVector& data) -> SdsData; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(SdsData, area_selection_, address_, data_, optional_elements_) }; auto operator<<(std::ostream& stream, const SdsData& sds) -> std::ostream&; @@ -312,9 +314,11 @@ struct CircuitModeControlEntityPacket : public MobileLinkEntityPacket { std::optional sds_data_; - CircuitModeControlEntityPacket() = delete; + CircuitModeControlEntityPacket() = default; explicit CircuitModeControlEntityPacket(const MobileLinkEntityPacket& packet); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(CircuitModeControlEntityPacket, packet_type_, sds_data_) }; auto operator<<(std::ostream& stream, const CircuitModeControlEntityPacket& cmce) -> std::ostream&; \ No newline at end of file diff --git a/include/l3/mobile_link_entity_packet.hpp b/include/l3/mobile_link_entity_packet.hpp index e3dc3ba..2e541aa 100644 --- a/include/l3/mobile_link_entity_packet.hpp +++ b/include/l3/mobile_link_entity_packet.hpp @@ -48,9 +48,11 @@ struct MobileLinkEntityPacket : public LogicalLinkControlPacket { MobileLinkEntityProtocolDiscriminator mle_protocol_; BitVector sdu_; - MobileLinkEntityPacket() = delete; + MobileLinkEntityPacket() = default; explicit MobileLinkEntityPacket(const LogicalLinkControlPacket& packet); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileLinkEntityPacket, mle_protocol_, sdu_) }; auto operator<<(std::ostream& stream, const MobileLinkEntityPacket& mle) -> std::ostream&; \ No newline at end of file diff --git a/include/l3/mobile_management_packet.hpp b/include/l3/mobile_management_packet.hpp index d8b533f..de101d7 100644 --- a/include/l3/mobile_management_packet.hpp +++ b/include/l3/mobile_management_packet.hpp @@ -9,9 +9,9 @@ #pragma once #include "l3/mobile_link_entity_packet.hpp" +#include "nlohmann_std_variant.hpp" // IWYU pragma: keep #include "utils/bit_vector.hpp" #include "utils/type234_parser.hpp" -#include #include #include @@ -271,9 +271,12 @@ struct MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement { GroupIdentityAcceptReject group_identity_accept_reject_; Type234Parser::Map optional_elements_; - MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement() = delete; + MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement() = default; explicit MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement(BitVector&); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement, + group_identity_accept_reject_, group_identity_accept_reject_) }; auto operator<<(std::ostream& stream, const MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement& packet) @@ -289,9 +292,13 @@ struct MobileManagementDownlinkLocationUpdateAccept { Type234Parser::Map optional_elements_; - MobileManagementDownlinkLocationUpdateAccept() = delete; + MobileManagementDownlinkLocationUpdateAccept() = default; explicit MobileManagementDownlinkLocationUpdateAccept(BitVector&); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileManagementDownlinkLocationUpdateAccept, location_update_accept_type_, address_, + subscriber_class_, energy_saving_information_, scch_information_, + distribution_on_18th_frame_, optional_elements_) }; auto operator<<(std::ostream& stream, const MobileManagementDownlinkLocationUpdateAccept& packet) -> std::ostream&; @@ -302,9 +309,12 @@ struct MobileManagementPacket : public MobileLinkEntityPacket { std::optional downlink_attach_detach_group_identity_acknowledgement_; - MobileManagementPacket() = delete; + MobileManagementPacket() = default; explicit MobileManagementPacket(const MobileLinkEntityPacket& packet); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileManagementPacket, packet_type_, downlink_location_update_accept_, + downlink_attach_detach_group_identity_acknowledgement_) }; auto operator<<(std::ostream& stream, const MobileManagementPacket& packet) -> std::ostream&; \ No newline at end of file diff --git a/include/l3/short_data_service_packet.hpp b/include/l3/short_data_service_packet.hpp index e69cb72..10f96cf 100644 --- a/include/l3/short_data_service_packet.hpp +++ b/include/l3/short_data_service_packet.hpp @@ -39,6 +39,7 @@ struct LocationInformationProtocol { }; auto operator<<(std::ostream& stream, const LocationInformationProtocol& lip) -> std::ostream&; + struct ShortDataServicePacket : public CircuitModeControlEntityPacket { unsigned _BitInt(8) protocol_identifier_; std::optional location_information_protocol_; diff --git a/include/nlohmann_std_optional.hpp b/include/nlohmann_std_optional.hpp new file mode 100644 index 0000000..d40f108 --- /dev/null +++ b/include/nlohmann_std_optional.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include +#include + +namespace nlohmann { +template struct adl_serializer> { + static void to_json(json& j, const std::optional& opt) { + if (opt == std::nullopt) { + j = nullptr; + } else { + j = *opt; + } + } + + static void from_json(const json& j, std::optional& opt) { + if (j.is_null()) { + opt = std::nullopt; + } else { + opt = j.template get(); + } + } +}; +} // namespace nlohmann diff --git a/include/nlohmann_std_variant.hpp b/include/nlohmann_std_variant.hpp new file mode 100644 index 0000000..ff43a1d --- /dev/null +++ b/include/nlohmann_std_variant.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace nlohmann { +template struct adl_serializer> { + static void to_json(json& j, const std::variant& var) { + j = json::object(); + j["variant_id"] = var.index(); + std::visit([&j](auto&& arg) { j["variant"] = arg; }, var); + } + + static void from_json(const json& j, std::variant& var) { + std::size_t variant_id = j["variant_id"]; + std::size_t variant = j["variant"]; + + if constexpr (sizeof...(Ts) > 0) { + if (variant_id == 0) { + var = std::variant(typename std::tuple_element<0, std::tuple>::type(variant)); + } + } + if constexpr (sizeof...(Ts) > 1) { + if (variant_id == 1) { + var = std::variant(typename std::tuple_element<1, std::tuple>::type(variant)); + } + } + if constexpr (sizeof...(Ts) > 2) { + if (variant_id == 2) { + var = std::variant(typename std::tuple_element<2, std::tuple>::type(variant)); + } + } + if constexpr (sizeof...(Ts) > 3) { + if (variant_id == 3) { + var = std::variant(typename std::tuple_element<3, std::tuple>::type(variant)); + } + } + + throw std::runtime_error("Cannot deserialize a std::variant with more than four variants."); + } +}; +} // namespace nlohmann diff --git a/include/nlohmann_unsigned_bitint.hpp b/include/nlohmann_unsigned_bitint.hpp new file mode 100644 index 0000000..e9d0e2f --- /dev/null +++ b/include/nlohmann_unsigned_bitint.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include + +namespace nlohmann { +template struct adl_serializer { + static void to_json(json& j, const unsigned _BitInt(T) & bit_int) { j = static_cast(bit_int); } + + static void from_json(const json& j, unsigned _BitInt(T) & bit_int) { bit_int = j.template get(); } +}; +} // namespace nlohmann diff --git a/include/utils/address.hpp b/include/utils/address.hpp index 6348297..9a65e5c 100644 --- a/include/utils/address.hpp +++ b/include/utils/address.hpp @@ -8,6 +8,8 @@ #pragma once +#include "nlohmann_std_optional.hpp" // IWYU pragma: keep +#include "nlohmann_unsigned_bitint.hpp" // IWYU pragma: keep #include "utils/bit_vector.hpp" #include #include @@ -85,6 +87,9 @@ class Address { friend auto operator<<(std::ostream& stream, const Address& address_type) -> std::ostream&; + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Address, country_code_, network_code_, sna_, ssi_, event_label_, ussi_, smi_, + usage_marker_) + private: std::optional country_code_; std::optional network_code_; @@ -106,38 +111,4 @@ template <> struct hash
{ }; } // namespace std -namespace nlohmann { -template <> struct adl_serializer
{ - static void to_json(json& j, Address address_type) { - j = json::object(); - std::cout << address_type << std::endl << std::flush; - - if (address_type.country_code()) { - j["country_code"] = static_cast(address_type.country_code().value()); - } - if (address_type.network_code()) { - j["network_code"] = static_cast(address_type.network_code().value()); - } - if (address_type.sna()) { - j["sna"] = static_cast(address_type.sna().value()); - } - if (address_type.ssi()) { - j["ssi"] = static_cast(address_type.ssi().value()); - } - if (address_type.event_label()) { - j["event_label"] = static_cast(address_type.event_label().value()); - } - if (address_type.ussi()) { - j["ussi"] = static_cast(address_type.ussi().value()); - } - if (address_type.smi()) { - j["smi"] = static_cast(address_type.smi().value()); - } - if (address_type.usage_marker()) { - j["usage_marker"] = static_cast(address_type.usage_marker().value()); - } - } -}; -} // namespace nlohmann - auto operator<<(std::ostream& stream, const Address& address_type) -> std::ostream&; diff --git a/include/utils/bit_vector.hpp b/include/utils/bit_vector.hpp index d8a6b1b..65d082f 100644 --- a/include/utils/bit_vector.hpp +++ b/include/utils/bit_vector.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -114,6 +115,8 @@ class BitVector { friend auto operator<<(std::ostream& stream, const BitVector& vec) -> std::ostream&; + NLOHMANN_DEFINE_TYPE_INTRUSIVE(BitVector, data_, len_, read_offset_) + private: template [[nodiscard]] auto to_bit_int(const std::vector::const_iterator iterator) const -> unsigned _BitInt(N) { diff --git a/include/utils/type234_parser.hpp b/include/utils/type234_parser.hpp index 696b0e2..d9a425c 100644 --- a/include/utils/type234_parser.hpp +++ b/include/utils/type234_parser.hpp @@ -28,20 +28,21 @@ template struct BitVectorElement { unsigned _BitInt(N) x_; }; -template struct Type34Element { +struct Type34Element { BitVector unparsed_bits; unsigned repeated_elements = 1; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type34Element, unparsed_bits, repeated_elements) }; -template -inline auto operator<<(std::ostream& stream, const Type34Element& element) -> std::ostream& { +inline auto operator<<(std::ostream& stream, const Type34Element& element) -> std::ostream& { stream << "#" << element.repeated_elements << ": " << element.unparsed_bits; return stream; }; template class Type234Parser { public: - using Map = std::map>; + using Map = std::map; Type234Parser() = delete; @@ -85,7 +86,7 @@ template class Type234Parser { if (elements.count(element_identifier)) { throw std::runtime_error("This element identifier already occured."); } - elements[element_identifier] = Type34Element{.unparsed_bits = element_data}; + elements[element_identifier] = Type34Element{.unparsed_bits = element_data}; continue; } // Is this a type 4 element? @@ -97,8 +98,8 @@ template class Type234Parser { if (elements.count(element_identifier)) { throw std::runtime_error("This element identifier already occured."); } - elements[element_identifier] = Type34Element{.unparsed_bits = element_data, - .repeated_elements = repeated_elements}; + elements[element_identifier] = + Type34Element{.unparsed_bits = element_data, .repeated_elements = repeated_elements}; continue; } // Is this element invalid? diff --git a/src/l3/mobile_management_formatter.cpp b/src/l3/mobile_management_formatter.cpp index b5b73ac..c5b4f3f 100644 --- a/src/l3/mobile_management_formatter.cpp +++ b/src/l3/mobile_management_formatter.cpp @@ -7,6 +7,7 @@ */ #include "l3/mobile_management_packet.hpp" +#include auto operator<<(std::ostream& stream, const MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement& packet) -> std::ostream& { From d59d5418b6c07a3edbcc3bbcae4ddb51980b39c5 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Wed, 24 Jul 2024 17:13:00 +0200 Subject: [PATCH 03/20] implement json serde for sds type --- include/l3/short_data_service_packet.hpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/l3/short_data_service_packet.hpp b/include/l3/short_data_service_packet.hpp index 10f96cf..8c29330 100644 --- a/include/l3/short_data_service_packet.hpp +++ b/include/l3/short_data_service_packet.hpp @@ -23,8 +23,11 @@ struct ShortLocationReport { unsigned _BitInt(1) type_of_addition_data_; unsigned _BitInt(8) additional_data_; - ShortLocationReport() = delete; + ShortLocationReport() = default; explicit ShortLocationReport(BitVector& data); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ShortLocationReport, time_elapsed_, longitude_, latitude_, position_error_, + horizontal_velocity_, direction_of_travel_, type_of_addition_data_, additional_data_) }; auto operator<<(std::ostream& stream, const ShortLocationReport& slr) -> std::ostream&; @@ -33,9 +36,11 @@ struct LocationInformationProtocol { unsigned _BitInt(2) pdu_type_; std::optional short_location_report_; - LocationInformationProtocol() = delete; + LocationInformationProtocol() = default; explicit LocationInformationProtocol(BitVector& data); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(LocationInformationProtocol, pdu_type_, short_location_report_) }; auto operator<<(std::ostream& stream, const LocationInformationProtocol& lip) -> std::ostream&; @@ -46,9 +51,11 @@ struct ShortDataServicePacket : public CircuitModeControlEntityPacket { static constexpr const std::size_t kLocationInformationProtocolIdentifier = 0b00001010; - ShortDataServicePacket() = delete; + ShortDataServicePacket() = default; explicit ShortDataServicePacket(const CircuitModeControlEntityPacket& packet); + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ShortDataServicePacket, protocol_identifier_, location_information_protocol_) }; auto operator<<(std::ostream& stream, const ShortDataServicePacket& sds) -> std::ostream&; \ No newline at end of file From d9e7f70b5e2e29d26bb52e71f99c009720c917e2 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Thu, 25 Jul 2024 22:53:42 +0200 Subject: [PATCH 04/20] json serde: add objects from protocol layers below --- include/l2/logical_link_control_packet.hpp | 6 +++++- include/l3/circuit_mode_control_entity_packet.hpp | 7 ++++++- include/l3/mobile_link_entity_packet.hpp | 9 +++++++-- include/l3/mobile_management_packet.hpp | 9 +++++++-- include/l3/short_data_service_packet.hpp | 8 +++++++- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/include/l2/logical_link_control_packet.hpp b/include/l2/logical_link_control_packet.hpp index d37b487..dfe6806 100644 --- a/include/l2/logical_link_control_packet.hpp +++ b/include/l2/logical_link_control_packet.hpp @@ -71,7 +71,11 @@ struct LogicalLinkControlPacket : public UpperMacCPlaneSignallingPacket { explicit LogicalLinkControlPacket(const UpperMacCPlaneSignallingPacket& packet); - NLOHMANN_DEFINE_TYPE_INTRUSIVE(LogicalLinkControlPacket, basic_link_information_, tl_sdu_) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(LogicalLinkControlPacket, burst_type_, logical_channel_, type_, encrypted_, address_, + fragmentation_, fragmentation_on_stealling_channel_, reservation_requirement_, + tm_sdu_, encryption_mode_, immediate_napping_permission_flag_, + basic_slot_granting_element_, position_of_grant_, channel_allocation_element_, + random_access_flag_, power_control_element_, basic_link_information_, tl_sdu_) }; auto operator<<(std::ostream& stream, const LogicalLinkControlPacket& llc) -> std::ostream&; \ No newline at end of file diff --git a/include/l3/circuit_mode_control_entity_packet.hpp b/include/l3/circuit_mode_control_entity_packet.hpp index 30e188e..d4c4f8e 100644 --- a/include/l3/circuit_mode_control_entity_packet.hpp +++ b/include/l3/circuit_mode_control_entity_packet.hpp @@ -318,7 +318,12 @@ struct CircuitModeControlEntityPacket : public MobileLinkEntityPacket { explicit CircuitModeControlEntityPacket(const MobileLinkEntityPacket& packet); - NLOHMANN_DEFINE_TYPE_INTRUSIVE(CircuitModeControlEntityPacket, packet_type_, sds_data_) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(CircuitModeControlEntityPacket, burst_type_, logical_channel_, type_, encrypted_, + address_, fragmentation_, fragmentation_on_stealling_channel_, + reservation_requirement_, tm_sdu_, encryption_mode_, + immediate_napping_permission_flag_, basic_slot_granting_element_, position_of_grant_, + channel_allocation_element_, random_access_flag_, power_control_element_, + basic_link_information_, tl_sdu_, mle_protocol_, sdu_, packet_type_, sds_data_) }; auto operator<<(std::ostream& stream, const CircuitModeControlEntityPacket& cmce) -> std::ostream&; \ No newline at end of file diff --git a/include/l3/mobile_link_entity_packet.hpp b/include/l3/mobile_link_entity_packet.hpp index 2e541aa..8254445 100644 --- a/include/l3/mobile_link_entity_packet.hpp +++ b/include/l3/mobile_link_entity_packet.hpp @@ -45,14 +45,19 @@ constexpr auto to_string(MobileLinkEntityProtocolDiscriminator type) noexcept -> /// The packet that is parsed in the logical link control layer. Currently we only implement basic link. struct MobileLinkEntityPacket : public LogicalLinkControlPacket { - MobileLinkEntityProtocolDiscriminator mle_protocol_; + MobileLinkEntityProtocolDiscriminator mle_protocol_ = MobileLinkEntityProtocolDiscriminator(0); BitVector sdu_; MobileLinkEntityPacket() = default; explicit MobileLinkEntityPacket(const LogicalLinkControlPacket& packet); - NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileLinkEntityPacket, mle_protocol_, sdu_) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileLinkEntityPacket, burst_type_, logical_channel_, type_, encrypted_, address_, + fragmentation_, fragmentation_on_stealling_channel_, reservation_requirement_, + tm_sdu_, encryption_mode_, immediate_napping_permission_flag_, + basic_slot_granting_element_, position_of_grant_, channel_allocation_element_, + random_access_flag_, power_control_element_, basic_link_information_, tl_sdu_, + mle_protocol_, sdu_) }; auto operator<<(std::ostream& stream, const MobileLinkEntityPacket& mle) -> std::ostream&; \ No newline at end of file diff --git a/include/l3/mobile_management_packet.hpp b/include/l3/mobile_management_packet.hpp index de101d7..e7f6d1e 100644 --- a/include/l3/mobile_management_packet.hpp +++ b/include/l3/mobile_management_packet.hpp @@ -283,7 +283,7 @@ auto operator<<(std::ostream& stream, const MobileManagementDownlinkAttachDetach -> std::ostream&; struct MobileManagementDownlinkLocationUpdateAccept { - LocationUpdateAcceptType location_update_accept_type_; + LocationUpdateAcceptType location_update_accept_type_ = LocationUpdateAcceptType(0); Address address_; std::optional subscriber_class_; std::optional energy_saving_information_; @@ -313,7 +313,12 @@ struct MobileManagementPacket : public MobileLinkEntityPacket { explicit MobileManagementPacket(const MobileLinkEntityPacket& packet); - NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileManagementPacket, packet_type_, downlink_location_update_accept_, + NLOHMANN_DEFINE_TYPE_INTRUSIVE(MobileManagementPacket, burst_type_, logical_channel_, type_, encrypted_, address_, + fragmentation_, fragmentation_on_stealling_channel_, reservation_requirement_, + tm_sdu_, encryption_mode_, immediate_napping_permission_flag_, + basic_slot_granting_element_, position_of_grant_, channel_allocation_element_, + random_access_flag_, power_control_element_, basic_link_information_, tl_sdu_, + mle_protocol_, sdu_, packet_type_, downlink_location_update_accept_, downlink_attach_detach_group_identity_acknowledgement_) }; diff --git a/include/l3/short_data_service_packet.hpp b/include/l3/short_data_service_packet.hpp index 8c29330..9cff346 100644 --- a/include/l3/short_data_service_packet.hpp +++ b/include/l3/short_data_service_packet.hpp @@ -55,7 +55,13 @@ struct ShortDataServicePacket : public CircuitModeControlEntityPacket { explicit ShortDataServicePacket(const CircuitModeControlEntityPacket& packet); - NLOHMANN_DEFINE_TYPE_INTRUSIVE(ShortDataServicePacket, protocol_identifier_, location_information_protocol_) + NLOHMANN_DEFINE_TYPE_INTRUSIVE(ShortDataServicePacket, burst_type_, logical_channel_, type_, encrypted_, address_, + fragmentation_, fragmentation_on_stealling_channel_, reservation_requirement_, + tm_sdu_, encryption_mode_, immediate_napping_permission_flag_, + basic_slot_granting_element_, position_of_grant_, channel_allocation_element_, + random_access_flag_, power_control_element_, basic_link_information_, tl_sdu_, + mle_protocol_, sdu_, packet_type_, sds_data_, protocol_identifier_, + location_information_protocol_) }; auto operator<<(std::ostream& stream, const ShortDataServicePacket& sds) -> std::ostream&; \ No newline at end of file From 66d80499c6a510eb7ea2af913edeb18568d20fe0 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Thu, 25 Jul 2024 22:54:13 +0200 Subject: [PATCH 05/20] adapt borzoi to_json converter --- include/borzoi/borzoi_converter.hpp | 8 +++- src/borzoi/borzoi_converter.cpp | 72 +++++++++++++---------------- src/borzoi/borzoi_sender.cpp | 22 +++------ 3 files changed, 45 insertions(+), 57 deletions(-) diff --git a/include/borzoi/borzoi_converter.hpp b/include/borzoi/borzoi_converter.hpp index d124102..10f8918 100644 --- a/include/borzoi/borzoi_converter.hpp +++ b/include/borzoi/borzoi_converter.hpp @@ -8,10 +8,14 @@ #pragma once +#include "l2/logical_link_control_packet.hpp" #include "l2/slot.hpp" -#include "l3/short_data_service_packet.hpp" +#include struct BorzoiConverter { - static auto to_json(ShortDataServicePacket* packet) -> nlohmann::json; + static constexpr const int kPacketApiVersion = 0; + static auto to_json(const Slots& slots) -> nlohmann::json; + + static auto to_json(const std::unique_ptr& packet) -> nlohmann::json; }; diff --git a/src/borzoi/borzoi_converter.cpp b/src/borzoi/borzoi_converter.cpp index 083bbe6..28e0c94 100644 --- a/src/borzoi/borzoi_converter.cpp +++ b/src/borzoi/borzoi_converter.cpp @@ -7,8 +7,10 @@ */ #include "borzoi/borzoi_converter.hpp" -#include "utils/bit_vector.hpp" -#include +#include "l3/circuit_mode_control_entity_packet.hpp" +#include "l3/mobile_link_entity_packet.hpp" +#include "l3/mobile_management_packet.hpp" +#include "l3/short_data_service_packet.hpp" inline static auto get_time() -> std::string { auto t = std::time(nullptr); @@ -18,47 +20,39 @@ inline static auto get_time() -> std::string { return ss.str(); } -auto BorzoiConverter::to_json(ShortDataServicePacket* packet) -> nlohmann::json { - auto message = nlohmann::json::object(); - /// TODO: this may throw - message["source_ssi"] = static_cast(packet->sds_data_->address_.ssi().value()); - message["destination_ssi"] = static_cast(packet->address_.ssi().value()); - message["protocol_identifier"] = static_cast(packet->protocol_identifier_); - message["telegram_type"] = "SDS"; - message["data"] = nlohmann::json::array(); - auto data = BitVector(packet->sds_data_->data_); - while (data.bits_left() >= 8) { - unsigned bits = data.take<8>(); - message["data"].push_back(bits); - } - message["arbitrary"] = nlohmann::json::object(); - if (data.bits_left() > 0) { - message["arbitrary"]["bits_in_last_byte"] = data.bits_left(); - message["data"].push_back(data.take_all()); - } else { - message["arbitrary"]["bits_in_last_byte"] = 8; - } - message["arbitrary"]["optional_fields"] = nlohmann::json::object(); - for (const auto& [key, value] : packet->sds_data_->optional_elements_) { - auto& vec = message["arbitrary"]["optional_fields"][to_string(key)]; - vec = nlohmann::json::object(); - vec["repeated_elements"] = value.repeated_elements; - vec["unparsed_bits"] = nlohmann::json::array(); - auto data = BitVector(value.unparsed_bits); - while (data.bits_left() >= 8) { - unsigned bits = data.take<8>(); - vec["unparsed_bits"].push_back(bits); - } - if (data.bits_left() > 0) { - vec["bits_in_last_byte"] = data.bits_left(); - vec["unparsed_bits"].push_back(data.take_all()); +auto BorzoiConverter::to_json(const std::unique_ptr& packet) -> nlohmann::json { + nlohmann::json data = nlohmann::json::object(); + + data["protocol_version"] = BorzoiConverter::kPacketApiVersion; + data["time"] = get_time(); + + if (auto* mle = dynamic_cast(packet.get())) { + if (auto* cmce = dynamic_cast(mle)) { + if (auto* sds = dynamic_cast(mle)) { + // Emit ShortDataServicePacket packet to json + data["key"] = "ShortDataServicePacket"; + data["value"] = *sds; + } else { + // Emit CircuitModeControlEntityPacket packet to json + data["key"] = "CircuitModeControlEntityPacket"; + data["value"] = *cmce; + } + } else if (auto* mm = dynamic_cast(mle)) { + // Emit MobileManagementPacket packet to json + data["key"] = "MobileManagementPacket"; + data["value"] = *mm; } else { - vec["bits_in_last_byte"] = 8; + // Emit MobileLinkEntityPacket packet to json + data["key"] = "MobileLinkEntityPacket"; + data["value"] = *mle; } + } else { + // Emit LogicalLinkControlPacket packet to json + data["key"] = "LogicalLinkControlPacket"; + data["value"] = *packet; } - message["time"] = get_time(); - return message; + return data; } auto BorzoiConverter::to_json(const Slots& slots) -> nlohmann::json { diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index a3be613..d6a354c 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -41,23 +41,13 @@ BorzoiSender::BorzoiSender(ThreadSafeFifo& packet) { - if (auto* sds = dynamic_cast(packet.get())) { - nlohmann::json json; - try { - json = BorzoiConverter::to_json(sds); - json["station"] = borzoi_uuid_; - /// TODO: add json to post request - } catch (std::exception& e) { - std::cout << "Failed to convert packet to json. Error: " << e.what() << std::endl; - return; - } - cpr::Response resp = - cpr::Post(borzoi_url_sds_, cpr::Body{json.dump()}, cpr::Header{{"Content-Type", "application/json"}}); + nlohmann::json json = BorzoiConverter::to_json(packet); + cpr::Response resp = + cpr::Post(borzoi_url_sds_, cpr::Body{json.dump()}, cpr::Header{{"Content-Type", "application/json"}}); - if (resp.status_code != 200) { - std::cout << "Failed to send packet to Borzoi: " << json.dump() << " Error: " << resp.status_code << " " - << resp.error.message << std::endl; - } + if (resp.status_code != 200) { + std::cout << "Failed to send packet to Borzoi: " << json.dump() << " Error: " << resp.status_code << " " + << resp.error.message << std::endl; } } From 2042a529bc6cf597e7a327751e25a95d6156c5ec Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Sat, 27 Jul 2024 01:11:13 +0200 Subject: [PATCH 06/20] refactor borzoi converter into nlohmann json function --- include/borzoi/borzoi_converter.hpp | 5 -- ...unique_ptr_logical_link_control_packet.hpp | 85 +++++++++++++++++++ src/borzoi/borzoi_converter.cpp | 35 -------- src/borzoi/borzoi_sender.cpp | 3 +- 4 files changed, 87 insertions(+), 41 deletions(-) create mode 100644 include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp diff --git a/include/borzoi/borzoi_converter.hpp b/include/borzoi/borzoi_converter.hpp index 10f8918..7036000 100644 --- a/include/borzoi/borzoi_converter.hpp +++ b/include/borzoi/borzoi_converter.hpp @@ -8,14 +8,9 @@ #pragma once -#include "l2/logical_link_control_packet.hpp" #include "l2/slot.hpp" #include struct BorzoiConverter { - static constexpr const int kPacketApiVersion = 0; - static auto to_json(const Slots& slots) -> nlohmann::json; - - static auto to_json(const std::unique_ptr& packet) -> nlohmann::json; }; diff --git a/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp b/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp new file mode 100644 index 0000000..a173b44 --- /dev/null +++ b/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "l2/logical_link_control_packet.hpp" +#include "l3/circuit_mode_control_entity_packet.hpp" +#include "l3/mobile_link_entity_packet.hpp" +#include "l3/mobile_management_packet.hpp" +#include "l3/short_data_service_packet.hpp" +#include + +static constexpr const int kPacketApiVersion = 0; + +inline static auto get_time() -> std::string { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + std::stringstream ss; + ss << std::put_time(&tm, "%FT%T%z"); + return ss.str(); +} + +namespace nlohmann { +template <> struct adl_serializer> { + static void to_json(json& j, const std::unique_ptr& packet) { + j["protocol_version"] = kPacketApiVersion; + j["time"] = get_time(); + + if (auto* mle = dynamic_cast(packet.get())) { + if (auto* cmce = dynamic_cast(mle)) { + if (auto* sds = dynamic_cast(mle)) { + // Emit ShortDataServicePacket packet to json + j["key"] = "ShortDataServicePacket"; + j["value"] = *sds; + } else { + // Emit CircuitModeControlEntityPacket packet to json + j["key"] = "CircuitModeControlEntityPacket"; + j["value"] = *cmce; + } + } else if (auto* mm = dynamic_cast(mle)) { + // Emit MobileManagementPacket packet to json + j["key"] = "MobileManagementPacket"; + j["value"] = *mm; + } else { + // Emit MobileLinkEntityPacket packet to json + j["key"] = "MobileLinkEntityPacket"; + j["value"] = *mle; + } + } else { + // Emit LogicalLinkControlPacket packet to json + j["key"] = "LogicalLinkControlPacket"; + j["value"] = *packet; + } + } + + static void from_json(const json& j, std::unique_ptr& packet) { + auto protocol_version = j["protocol_version"].template get(); + if (protocol_version != kPacketApiVersion) { + throw std::runtime_error("Cannot process packets different API version."); + } + + auto key = j["key"].template get(); + + if (key == "LogicalLinkControlPacket") { + packet = std::make_unique(j["value"].template get()); + } else if (key == "MobileLinkEntityPacket") { + packet = std::make_unique(j["value"].template get()); + } else if (key == "MobileManagementPacket") { + packet = std::make_unique(j["value"].template get()); + } else if (key == "CircuitModeControlEntityPacket") { + packet = + std::make_unique(j["value"].template get()); + } else if (key == "ShortDataServicePacket") { + packet = std::make_unique(j["value"].template get()); + } else { + throw std::runtime_error("Unknown packet type: " + key); + } + } +}; +} // namespace nlohmann diff --git a/src/borzoi/borzoi_converter.cpp b/src/borzoi/borzoi_converter.cpp index 28e0c94..95ffc89 100644 --- a/src/borzoi/borzoi_converter.cpp +++ b/src/borzoi/borzoi_converter.cpp @@ -20,41 +20,6 @@ inline static auto get_time() -> std::string { return ss.str(); } -auto BorzoiConverter::to_json(const std::unique_ptr& packet) -> nlohmann::json { - nlohmann::json data = nlohmann::json::object(); - - data["protocol_version"] = BorzoiConverter::kPacketApiVersion; - data["time"] = get_time(); - - if (auto* mle = dynamic_cast(packet.get())) { - if (auto* cmce = dynamic_cast(mle)) { - if (auto* sds = dynamic_cast(mle)) { - // Emit ShortDataServicePacket packet to json - data["key"] = "ShortDataServicePacket"; - data["value"] = *sds; - } else { - // Emit CircuitModeControlEntityPacket packet to json - data["key"] = "CircuitModeControlEntityPacket"; - data["value"] = *cmce; - } - } else if (auto* mm = dynamic_cast(mle)) { - // Emit MobileManagementPacket packet to json - data["key"] = "MobileManagementPacket"; - data["value"] = *mm; - } else { - // Emit MobileLinkEntityPacket packet to json - data["key"] = "MobileLinkEntityPacket"; - data["value"] = *mle; - } - } else { - // Emit LogicalLinkControlPacket packet to json - data["key"] = "LogicalLinkControlPacket"; - data["value"] = *packet; - } - - return data; -} - auto BorzoiConverter::to_json(const Slots& slots) -> nlohmann::json { auto message = nlohmann::json::object(); diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index d6a354c..8e562df 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -13,6 +13,7 @@ #include "l3/mobile_link_entity_packet.hpp" #include "l3/mobile_management_packet.hpp" #include "l3/short_data_service_packet.hpp" +#include "nlohmann_std_unique_ptr_logical_link_control_packet.hpp" // IWYU pragma: keep #include #include #include @@ -41,7 +42,7 @@ BorzoiSender::BorzoiSender(ThreadSafeFifo& packet) { - nlohmann::json json = BorzoiConverter::to_json(packet); + nlohmann::json json = packet; cpr::Response resp = cpr::Post(borzoi_url_sds_, cpr::Body{json.dump()}, cpr::Header{{"Content-Type", "application/json"}}); From df2338acd50f411a30c5c4c24967c5cd40558cfb Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Sat, 27 Jul 2024 20:51:10 +0200 Subject: [PATCH 07/20] add json serde for slots. refactor borzoi sender --- CMakeLists.txt | 1 - include/borzoi/borzoi_converter.hpp | 16 ------ include/l2/slot.hpp | 21 ++++---- ...unique_ptr_logical_link_control_packet.hpp | 9 ---- src/borzoi/borzoi_converter.cpp | 50 ------------------- src/borzoi/borzoi_sender.cpp | 35 +++++++------ src/l2/lower_mac.cpp | 16 +++--- src/l2/slot.cpp | 10 ++-- 8 files changed, 45 insertions(+), 113 deletions(-) delete mode 100644 include/borzoi/borzoi_converter.hpp delete mode 100644 src/borzoi/borzoi_converter.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 32b0134..5dda6f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ add_executable(tetra-decoder src/bit_stream_decoder.cpp src/iq_stream_decoder.cpp src/prometheus.cpp - src/borzoi/borzoi_converter.cpp src/borzoi/borzoi_sender.cpp src/l2/access_assignment_channel.cpp src/l2/broadcast_synchronization_channel.cpp diff --git a/include/borzoi/borzoi_converter.hpp b/include/borzoi/borzoi_converter.hpp deleted file mode 100644 index 7036000..0000000 --- a/include/borzoi/borzoi_converter.hpp +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2024 Transit Live Mapping Solutions - * All rights reserved. - * - * Authors: - * Marenz Schmidl - */ - -#pragma once - -#include "l2/slot.hpp" -#include - -struct BorzoiConverter { - static auto to_json(const Slots& slots) -> nlohmann::json; -}; diff --git a/include/l2/slot.hpp b/include/l2/slot.hpp index a3c6ef7..238bd88 100644 --- a/include/l2/slot.hpp +++ b/include/l2/slot.hpp @@ -82,15 +82,15 @@ class Slot { auto operator<<(std::ostream& stream, const Slot& slot) -> std::ostream&; /// defines the number and types of slots in a packet -enum class SlotsType { kOneSubslot, kTwoSubslots, kFullSlot }; +enum class SlotType { kOneSubslot, kTwoSubslots, kFullSlot }; -constexpr auto to_string(SlotsType type) noexcept -> const char* { +constexpr auto to_string(SlotType type) noexcept -> const char* { switch (type) { - case SlotsType::kOneSubslot: + case SlotType::kOneSubslot: return "OneSubslot"; - case SlotsType::kTwoSubslots: + case SlotType::kTwoSubslots: return "TwoSubslots"; - case SlotsType::kFullSlot: + case SlotType::kFullSlot: return "FullSlot"; } }; @@ -115,22 +115,22 @@ class Slots { /// which burst type ths slots originated from BurstType burst_type_; /// the number and types of slots - SlotsType slot_type_; + SlotType slot_type_; /// The slots, either one half or full slot or two half slots. /// We are doing accesses that would normally not be const but are in this case, because we make assumption about /// the content of this vector based on the constructor used to initialize this class. mutable std::vector slots_; public: - Slots() = delete; + Slots() = default; Slots(const Slots& other) = default; /// constructor for one subslot or a full slot - Slots(BurstType burst_type, SlotsType slot_type, Slot&& slot); + Slots(BurstType burst_type, SlotType slot_type, Slot&& slot); /// construct for two half slot - Slots(BurstType burst_type, SlotsType slot_type, Slot&& first_slot, Slot&& second_slot); + Slots(BurstType burst_type, SlotType slot_type, Slot&& first_slot, Slot&& second_slot); /// get a reference to the concreate slots [[nodiscard]] auto get_concreate_slots() const -> std::vector { @@ -169,6 +169,9 @@ class Slots { /// get the type of the underlying burst [[nodiscard]] auto get_burst_type() const noexcept -> BurstType { return burst_type_; } + /// get the type of the underlying slot + [[nodiscard]] auto get_slot_type() const noexcept -> SlotType { return slot_type_; } + friend auto operator<<(std::ostream& stream, const Slots& slots) -> std::ostream&; }; diff --git a/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp b/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp index a173b44..f340d03 100644 --- a/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp +++ b/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp @@ -17,19 +17,10 @@ static constexpr const int kPacketApiVersion = 0; -inline static auto get_time() -> std::string { - auto t = std::time(nullptr); - auto tm = *std::localtime(&t); - std::stringstream ss; - ss << std::put_time(&tm, "%FT%T%z"); - return ss.str(); -} - namespace nlohmann { template <> struct adl_serializer> { static void to_json(json& j, const std::unique_ptr& packet) { j["protocol_version"] = kPacketApiVersion; - j["time"] = get_time(); if (auto* mle = dynamic_cast(packet.get())) { if (auto* cmce = dynamic_cast(mle)) { diff --git a/src/borzoi/borzoi_converter.cpp b/src/borzoi/borzoi_converter.cpp deleted file mode 100644 index 95ffc89..0000000 --- a/src/borzoi/borzoi_converter.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2024 Transit Live Mapping Solutions - * All rights reserved. - * - * Authors: - * Marenz Schmidl - */ - -#include "borzoi/borzoi_converter.hpp" -#include "l3/circuit_mode_control_entity_packet.hpp" -#include "l3/mobile_link_entity_packet.hpp" -#include "l3/mobile_management_packet.hpp" -#include "l3/short_data_service_packet.hpp" - -inline static auto get_time() -> std::string { - auto t = std::time(nullptr); - auto tm = *std::localtime(&t); - std::stringstream ss; - ss << std::put_time(&tm, "%FT%T%z"); - return ss.str(); -} - -auto BorzoiConverter::to_json(const Slots& slots) -> nlohmann::json { - auto message = nlohmann::json::object(); - - message["time"] = get_time(); - message["burst_type"] = static_cast(slots.get_burst_type()); - /// This may but should not throw. - auto first_slot = slots.get_first_slot().get_logical_channel_data_and_crc(); - message["first_slot_logical_channel"] = static_cast(first_slot.channel); - message["first_slot_data"] = nlohmann::json::array(); - while (first_slot.data.bits_left()) { - unsigned bit = first_slot.data.take<1>(); - message["first_slot_logical_data"].push_back(bit); - } - message["first_slot_crc_ok"] = first_slot.crc_ok; - auto second_slot_present = slots.has_second_slot(); - message["second_slot_present"] = second_slot_present; - if (second_slot_present) { - auto second_slot = slots.get_second_slot().get_logical_channel_data_and_crc(); - message["second_slot_logical_channel"] = static_cast(first_slot.channel); - message["second_slot_data"] = nlohmann::json::array(); - while (first_slot.data.bits_left()) { - unsigned bit = first_slot.data.take<1>(); - message["second_slot_data"].push_back(bit); - } - message["second_slot_crc_ok"] = first_slot.crc_ok; - } - return message; -} \ No newline at end of file diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index 8e562df..8997050 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -7,23 +7,36 @@ */ #include "borzoi/borzoi_sender.hpp" -#include "borzoi/borzoi_converter.hpp" #include "l2/upper_mac_packet.hpp" #include "l3/circuit_mode_control_entity_packet.hpp" #include "l3/mobile_link_entity_packet.hpp" #include "l3/mobile_management_packet.hpp" #include "l3/short_data_service_packet.hpp" +#include "nlohmann_slots.hpp" // IWYU pragma: keep #include "nlohmann_std_unique_ptr_logical_link_control_packet.hpp" // IWYU pragma: keep #include #include #include -#include #include #if defined(__linux__) #include #endif +inline static auto get_time() -> std::string { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + std::stringstream ss; + ss << std::put_time(&tm, "%FT%T%z"); + return ss.str(); +} + +inline static auto with_time_and_uuid(nlohmann::json& j, const std::string& borzoi_uuid) -> nlohmann::json { + j["time"] = get_time(); + j["station"] = borzoi_uuid; + return j; +} + BorzoiSender::BorzoiSender(ThreadSafeFifo, Slots>>& queue, std::atomic_bool& termination_flag, const std::string& borzoi_url, std::string borzoi_uuid) : queue_(queue) @@ -43,8 +56,8 @@ BorzoiSender::~BorzoiSender() { worker_thread_.join(); } void BorzoiSender::send_packet(const std::unique_ptr& packet) { nlohmann::json json = packet; - cpr::Response resp = - cpr::Post(borzoi_url_sds_, cpr::Body{json.dump()}, cpr::Header{{"Content-Type", "application/json"}}); + cpr::Response resp = cpr::Post(borzoi_url_sds_, cpr::Body{with_time_and_uuid(json, borzoi_uuid_).dump()}, + cpr::Header{{"Content-Type", "application/json"}}); if (resp.status_code != 200) { std::cout << "Failed to send packet to Borzoi: " << json.dump() << " Error: " << resp.status_code << " " @@ -53,17 +66,9 @@ void BorzoiSender::send_packet(const std::unique_ptr& } void BorzoiSender::send_failed_slots(const Slots& slots) { - nlohmann::json json; - try { - json = BorzoiConverter::to_json(slots); - json["station"] = borzoi_uuid_; - /// TODO: add json to post request - } catch (std::exception& e) { - std::cout << "Failed to convert packet to json. Error: " << e.what() << std::endl; - return; - } - cpr::Response resp = - cpr::Post(borzoi_url_failed_slots_, cpr::Body{json.dump()}, cpr::Header{{"Content-Type", "application/json"}}); + nlohmann::json json = slots; + cpr::Response resp = cpr::Post(borzoi_url_failed_slots_, cpr::Body{with_time_and_uuid(json, borzoi_uuid_).dump()}, + cpr::Header{{"Content-Type", "application/json"}}); if (resp.status_code != 200) { std::cout << "Failed to send packet to Borzoi: " << json.dump() << " Error: " << resp.status_code << " " diff --git a/src/l2/lower_mac.cpp b/src/l2/lower_mac.cpp index 658e40b..30591c3 100644 --- a/src/l2/lower_mac.cpp +++ b/src/l2/lower_mac.cpp @@ -78,7 +78,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave( LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101))); - slots = Slots(burst_type, SlotsType::kOneSubslot, + slots = Slots(burst_type, SlotType::kOneSubslot, Slot(LogicalChannelDataAndCrc{ .channel = LogicalChannel::kSignallingChannelHalfDownlink, .data = BitVector(std::vector(bkn2_bits.cbegin(), bkn2_bits.cbegin() + 124)), @@ -110,7 +110,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs if (aach.downlink_usage == DownlinkUsage::Traffic) { // Full slot traffic channel defined type 4 bits (only descrambling) - slots = Slots(burst_type, SlotsType::kFullSlot, + slots = Slots(burst_type, SlotType::kFullSlot, Slot(LogicalChannelDataAndCrc{ .channel = LogicalChannel::kTrafficChannel, .data = BitVector(std::vector(bkn1_descrambled.cbegin(), bkn1_descrambled.cend())), @@ -119,7 +119,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs } else { // control channel // ✅done - slots = Slots(burst_type, SlotsType::kFullSlot, + slots = Slots(burst_type, SlotType::kFullSlot, Slot(LogicalChannelDataAndCrc{ .channel = LogicalChannel::kSignallingChannelFull, .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 268)), @@ -162,7 +162,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs // STCH + TCH // STCH + STCH slots = - Slots(burst_type, SlotsType::kTwoSubslots, + Slots(burst_type, SlotType::kTwoSubslots, Slot(LogicalChannelDataAndCrc{ .channel = LogicalChannel::kStealingChannel, .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 124)), @@ -181,7 +181,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs } else { // SCH/HD + SCH/HD // SCH/HD + BNCH - slots = Slots(burst_type, SlotsType::kTwoSubslots, + slots = Slots(burst_type, SlotType::kTwoSubslots, Slot(LogicalChannelDataAndCrc{ .channel = LogicalChannel::kSignallingChannelHalfDownlink, .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 124)), @@ -205,7 +205,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs LowerMacCoding::descramble(cb_input, bsc.scrambling_code), 13))); // SCH/HU - slots = Slots(burst_type, SlotsType::kOneSubslot, + slots = Slots(burst_type, SlotType::kOneSubslot, Slot(LogicalChannelDataAndCrc{ .channel = LogicalChannel::kSignallingChannelHalfUplink, .data = BitVector(std::vector(cb_bits.cbegin(), cb_bits.cbegin() + 92)), @@ -225,7 +225,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614( viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(bkn1_descrambled, 103))); - slots = Slots(burst_type, SlotsType::kFullSlot, + slots = Slots(burst_type, SlotType::kFullSlot, Slot({ LogicalChannelDataAndCrc{ .channel = LogicalChannel::kSignallingChannelFull, @@ -260,7 +260,7 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs // STCH + TCH // STCH + STCH - slots = Slots(burst_type, SlotsType::kTwoSubslots, + slots = Slots(burst_type, SlotType::kTwoSubslots, Slot(LogicalChannelDataAndCrc{ .channel = LogicalChannel::kStealingChannel, .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 124)), diff --git a/src/l2/slot.cpp b/src/l2/slot.cpp index 2d14a61..9305723 100644 --- a/src/l2/slot.cpp +++ b/src/l2/slot.cpp @@ -17,11 +17,11 @@ auto operator<<(std::ostream& stream, const Slot& slot) -> std::ostream& { return stream; } -Slots::Slots(BurstType burst_type, SlotsType slot_type, Slot&& slot) +Slots::Slots(BurstType burst_type, SlotType slot_type, Slot&& slot) : burst_type_(burst_type) , slot_type_(slot_type) , slots_({std::move(slot)}) { - if (slot_type_ == SlotsType::kTwoSubslots) { + if (slot_type_ == SlotType::kTwoSubslots) { throw std::runtime_error("Two subslots need to to have two subslots"); } @@ -38,11 +38,11 @@ Slots::Slots(BurstType burst_type, SlotsType slot_type, Slot&& slot) }; // NOLINTNEXTLINE(readability-function-cognitive-complexity) -Slots::Slots(BurstType burst_type, SlotsType slot_type, Slot&& first_slot, Slot&& second_slot) +Slots::Slots(BurstType burst_type, SlotType slot_type, Slot&& first_slot, Slot&& second_slot) : burst_type_(burst_type) , slot_type_(slot_type) , slots_({std::move(first_slot), std::move(second_slot)}) { - if (slot_type_ != SlotsType::kTwoSubslots) { + if (slot_type_ != SlotType::kTwoSubslots) { throw std::runtime_error("Only two subslots is allowed to have two subslots"); } @@ -131,7 +131,7 @@ auto Slots::has_crc_error() -> bool { auto operator<<(std::ostream& stream, const Slots& slots) -> std::ostream& { stream << "Slots:" << std::endl; stream << " [BurstType] " << to_string(slots.burst_type_) << std::endl; - stream << " [SlotsType] " << to_string(slots.slot_type_) << std::endl; + stream << " [SlotType] " << to_string(slots.slot_type_) << std::endl; for (const auto& slot : slots.slots_) { stream << " Slot:" << std::endl; stream << slot; From 0d7bd3566d193e449dc797d37896e50c9497f387 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Sat, 27 Jul 2024 21:21:06 +0200 Subject: [PATCH 08/20] add missing file --- include/nlohmann_slots.hpp | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 include/nlohmann_slots.hpp diff --git a/include/nlohmann_slots.hpp b/include/nlohmann_slots.hpp new file mode 100644 index 0000000..b65ae78 --- /dev/null +++ b/include/nlohmann_slots.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "l2/slot.hpp" +#include + +namespace nlohmann { +template <> struct adl_serializer { + static void to_json(json& j, const Slots& slots) { + j["burst_type"] = slots.get_burst_type(); + j["slot_type"] = slots.get_slot_type(); + /// This may but should not throw. + auto first_slot = slots.get_first_slot().get_logical_channel_data_and_crc(); + j["first_slot_logical_channel"] = first_slot.channel; + j["first_slot_data"] = first_slot.data; + j["first_slot_crc_ok"] = first_slot.crc_ok; + auto second_slot_present = slots.has_second_slot(); + j["second_slot_present"] = second_slot_present; + if (second_slot_present) { + auto second_slot = slots.get_second_slot().get_logical_channel_data_and_crc(); + j["second_slot_logical_channel"] = first_slot.channel; + j["second_slot_data"] = first_slot.data; + j["second_slot_crc_ok"] = first_slot.crc_ok; + } + } + + static void from_json(const json& j, Slots& slots) { + auto burst_type = j["burst_type"].template get(); + auto slot_type = j["slot_type"].template get(); + auto first_slot_logical_channel = j["first_slot_logical_channel"].template get(); + auto first_slot_data = j["first_slot_data"].template get(); + auto first_slot_crc_ok = j["first_slot_crc_ok"].template get(); + auto second_slot_present = j["second_slot_present"].template get(); + + auto first_slot = Slot(LogicalChannelDataAndCrc{ + .channel = first_slot_logical_channel, + .data = first_slot_data, + .crc_ok = first_slot_crc_ok, + }); + + if (second_slot_present) { + auto second_slot_logical_channel = j["second_slot_logical_channel"].template get(); + auto second_slot_data = j["second_slot_data"].template get(); + auto second_slot_crc_ok = j["second_slot_crc_ok"].template get(); + + auto second_slot = Slot(LogicalChannelDataAndCrc{ + .channel = second_slot_logical_channel, + .data = second_slot_data, + .crc_ok = second_slot_crc_ok, + }); + + slots = Slots(burst_type, slot_type, std::move(first_slot), std::move(second_slot)); + } else { + slots = Slots(burst_type, slot_type, std::move(first_slot)); + } + } +}; +} // namespace nlohmann From 34584157f91674b45654ec3475989cb62a84ba1b Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Tue, 30 Jul 2024 12:28:42 +0200 Subject: [PATCH 09/20] default initialize fields --- include/l2/logical_link_control_packet.hpp | 2 +- include/l2/slot.hpp | 4 +- include/l2/upper_mac_packet.hpp | 112 +++++++++++---------- include/l3/mobile_management_packet.hpp | 2 +- include/l3/short_data_service_packet.hpp | 16 +-- 5 files changed, 71 insertions(+), 65 deletions(-) diff --git a/include/l2/logical_link_control_packet.hpp b/include/l2/logical_link_control_packet.hpp index dfe6806..41f7851 100644 --- a/include/l2/logical_link_control_packet.hpp +++ b/include/l2/logical_link_control_packet.hpp @@ -46,7 +46,7 @@ constexpr auto to_string(BasicLinkType type) noexcept -> const char* { }; struct BasicLinkInformation { - BasicLinkType basic_link_type_; + BasicLinkType basic_link_type_{}; std::optional n_r_; std::optional n_s_; std::optional fcs_good_; diff --git a/include/l2/slot.hpp b/include/l2/slot.hpp index 238bd88..a3f3650 100644 --- a/include/l2/slot.hpp +++ b/include/l2/slot.hpp @@ -113,9 +113,9 @@ struct ConcreateSlot { class Slots { private: /// which burst type ths slots originated from - BurstType burst_type_; + BurstType burst_type_{}; /// the number and types of slots - SlotType slot_type_; + SlotType slot_type_{}; /// The slots, either one half or full slot or two half slots. /// We are doing accesses that would normally not be const but are in this case, because we make assumption about /// the content of this vector based on the constructor used to initialize this class. diff --git a/include/l2/upper_mac_packet.hpp b/include/l2/upper_mac_packet.hpp index cb0ed44..d8fb7f3 100644 --- a/include/l2/upper_mac_packet.hpp +++ b/include/l2/upper_mac_packet.hpp @@ -159,9 +159,9 @@ struct ExtendedServiceBroadcastSection4 { auto operator<<(std::ostream& stream, const ExtendedServiceBroadcastSection4& element) -> std::ostream&; struct ExtendedServiceBroadcast { - unsigned _BitInt(8) security_information_; - unsigned _BitInt(2) sdstl_addressing_method_; - unsigned _BitInt(1) gck_supported_; + unsigned _BitInt(8) security_information_{}; + unsigned _BitInt(2) sdstl_addressing_method_{}; + unsigned _BitInt(1) gck_supported_{}; std::optional section1_; std::optional section2_; @@ -181,16 +181,16 @@ struct ExtendedServiceBroadcast { auto operator<<(std::ostream& stream, const ExtendedServiceBroadcast& element) -> std::ostream&; struct SystemInfo { - unsigned _BitInt(12) main_carrier_; - unsigned _BitInt(4) frequency_band_; - unsigned _BitInt(2) offset_; - unsigned _BitInt(3) duplex_spacing_field_; - unsigned _BitInt(1) reverse_operation_; - unsigned _BitInt(2) number_secondary_control_channels_main_carrier_; - unsigned _BitInt(3) ms_txpwr_max_cell_; - unsigned _BitInt(4) rxlev_access_min_; - unsigned _BitInt(4) access_parameter_; - unsigned _BitInt(4) radio_downlink_timeout_; + unsigned _BitInt(12) main_carrier_{}; + unsigned _BitInt(4) frequency_band_{}; + unsigned _BitInt(2) offset_{}; + unsigned _BitInt(3) duplex_spacing_field_{}; + unsigned _BitInt(1) reverse_operation_{}; + unsigned _BitInt(2) number_secondary_control_channels_main_carrier_{}; + unsigned _BitInt(3) ms_txpwr_max_cell_{}; + unsigned _BitInt(4) rxlev_access_min_{}; + unsigned _BitInt(4) access_parameter_{}; + unsigned _BitInt(4) radio_downlink_timeout_{}; std::optional hyper_frame_number_; std::optional common_cipher_key_identifier_or_static_cipher_key_version_number_; std::optional even_multi_frame_definition_for_ts_mode_; @@ -198,19 +198,19 @@ struct SystemInfo { std::optional defaults_for_access_code_a_; std::optional extended_service_broadcast_; - unsigned _BitInt(14) location_area_; - unsigned _BitInt(16) subscriber_class_; - unsigned _BitInt(1) registration_; - unsigned _BitInt(1) deregistration_; - unsigned _BitInt(1) priority_cell_; - unsigned _BitInt(1) minimum_mode_service_; - unsigned _BitInt(1) migration_; - unsigned _BitInt(1) system_wide_service_; - unsigned _BitInt(1) tetra_voice_service_; - unsigned _BitInt(1) circuit_mode_data_service_; - unsigned _BitInt(1) sndcp_service_; - unsigned _BitInt(1) air_interface_encryption_service_; - unsigned _BitInt(1) advanced_link_supported_; + unsigned _BitInt(14) location_area_{}; + unsigned _BitInt(16) subscriber_class_{}; + unsigned _BitInt(1) registration_{}; + unsigned _BitInt(1) deregistration_{}; + unsigned _BitInt(1) priority_cell_{}; + unsigned _BitInt(1) minimum_mode_service_{}; + unsigned _BitInt(1) migration_{}; + unsigned _BitInt(1) system_wide_service_{}; + unsigned _BitInt(1) tetra_voice_service_{}; + unsigned _BitInt(1) circuit_mode_data_service_{}; + unsigned _BitInt(1) sndcp_service_{}; + unsigned _BitInt(1) air_interface_encryption_service_{}; + unsigned _BitInt(1) advanced_link_supported_{}; SystemInfo() = default; /// construct a SystemInfo from a BitVector @@ -237,9 +237,9 @@ struct SystemInfo { auto operator<<(std::ostream& stream, const SystemInfo& element) -> std::ostream&; struct AccessDefine { - unsigned _BitInt(1) common_or_assigned_control_channel_flag_; - unsigned _BitInt(2) access_code_; - AccessCodeDefinition access_code_definition_; + unsigned _BitInt(1) common_or_assigned_control_channel_flag_{}; + unsigned _BitInt(2) access_code_{}; + AccessCodeDefinition access_code_definition_{}; std::optional subscriber_class_bitmap_; std::optional gssi_; @@ -257,9 +257,9 @@ auto operator<<(std::ostream& stream, const AccessDefine& element) -> std::ostre struct UpperMacBroadcastPacket { /// the type of the logical channel on which this packet is sent - LogicalChannel logical_channel_; + LogicalChannel logical_channel_{}; /// the type of the mac packet - MacPacketType type_; + MacPacketType type_{}; std::optional sysinfo_; std::optional access_define_; @@ -272,6 +272,9 @@ struct UpperMacBroadcastPacket { auto operator<<(std::ostream& stream, const UpperMacBroadcastPacket& packet) -> std::ostream&; /// reconstruct the number of bits from the length indication field +// NOLINTBEGIN(readability-identifier-naming) +// NOLINTBEGIN(readability-identifier-length) +// NOLINTBEGIN(readability-magic-numbers) struct LengthIndication { // Y1 and Z1 octets, for a PDU sent in a subslot (i.e. MAC-ACCESS or MAC-END-HU). // Y2 and Z2 octets, for a PDU sent in a slot (i.e. MAC-DATA, MAC-RESOURCE or MAC-END). @@ -322,12 +325,15 @@ struct LengthIndication { return (18 * Y2 + (length_indication - 18) * Z2); }; }; +// NOLINTEND(readability-magic-numbers) +// NOLINTEND(readability-identifier-length) +// NOLINTEND(readability-identifier-naming) struct ExtendedCarrierNumbering { - unsigned _BitInt(4) frequency_band_; - unsigned _BitInt(2) offset_; - unsigned _BitInt(3) duplex_spacing_; - unsigned _BitInt(1) reverse_operation_; + unsigned _BitInt(4) frequency_band_{}; + unsigned _BitInt(2) offset_{}; + unsigned _BitInt(3) duplex_spacing_{}; + unsigned _BitInt(1) reverse_operation_{}; ExtendedCarrierNumbering() = default; /// construct a ExtendedCarrierNumbering from a BitVector @@ -342,22 +348,22 @@ struct ExtendedCarrierNumbering { auto operator<<(std::ostream& stream, const ExtendedCarrierNumbering& element) -> std::ostream&; struct AugmentedChannelAllocation { - unsigned _BitInt(2) up_downlink_assigned_; - unsigned _BitInt(3) bandwidth_; + unsigned _BitInt(2) up_downlink_assigned_{}; + unsigned _BitInt(3) bandwidth_{}; - unsigned _BitInt(3) modulation_mode_; + unsigned _BitInt(3) modulation_mode_{}; std::optional maximum_uplink_qam_modulation_level_; - unsigned _BitInt(3) conforming_channel_status_; - unsigned _BitInt(4) bs_link_imbalance_; - unsigned _BitInt(5) bs_transmit_power_relative_to_main_carrier_; + unsigned _BitInt(3) conforming_channel_status_{}; + unsigned _BitInt(4) bs_link_imbalance_{}; + unsigned _BitInt(5) bs_transmit_power_relative_to_main_carrier_{}; - unsigned _BitInt(2) napping_status_; + unsigned _BitInt(2) napping_status_{}; std::optional napping_information_; std::optional conditional_element_a_; std::optional conditional_element_b_; - unsigned _BitInt(1) further_augmentation_flag_; + unsigned _BitInt(1) further_augmentation_flag_{}; AugmentedChannelAllocation() = default; /// construct a AugmentedChannelAllocation from a BitVector @@ -374,16 +380,16 @@ struct AugmentedChannelAllocation { auto operator<<(std::ostream& stream, const AugmentedChannelAllocation& element) -> std::ostream&; struct ChannelAllocationElement { - unsigned _BitInt(2) allocation_type_; - unsigned _BitInt(4) timeslot_assigned_; - unsigned _BitInt(2) up_downlink_assigned_; - unsigned _BitInt(1) clch_permission_; - unsigned _BitInt(1) cell_change_flag_; + unsigned _BitInt(2) allocation_type_{}; + unsigned _BitInt(4) timeslot_assigned_{}; + unsigned _BitInt(2) up_downlink_assigned_{}; + unsigned _BitInt(1) clch_permission_{}; + unsigned _BitInt(1) cell_change_flag_{}; - unsigned _BitInt(12) carrier_number_; + unsigned _BitInt(12) carrier_number_{}; std::optional extended_carrier_numbering_; - unsigned _BitInt(2) monitoring_pattern_; + unsigned _BitInt(2) monitoring_pattern_{}; std::optional frame18_monitoring_pattern_; std::optional augmented_channel_allocation_; @@ -404,11 +410,11 @@ auto operator<<(std::ostream& stream, const ChannelAllocationElement& element) - struct UpperMacCPlaneSignallingPacket { /// the burst type which was used to send this pavket - BurstType burst_type_; + BurstType burst_type_{}; /// the type of the logical channel on which this packet is sent - LogicalChannel logical_channel_; + LogicalChannel logical_channel_{}; /// the type of the mac packet - MacPacketType type_; + MacPacketType type_{}; /// Is the content of the packet encrypted bool encrypted_ = false; diff --git a/include/l3/mobile_management_packet.hpp b/include/l3/mobile_management_packet.hpp index e7f6d1e..a34ee4a 100644 --- a/include/l3/mobile_management_packet.hpp +++ b/include/l3/mobile_management_packet.hpp @@ -268,7 +268,7 @@ constexpr auto to_string(GroupIdentityAcceptReject type) -> const char* { }; struct MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement { - GroupIdentityAcceptReject group_identity_accept_reject_; + GroupIdentityAcceptReject group_identity_accept_reject_{}; Type234Parser::Map optional_elements_; MobileManagementDownlinkAttachDetachGroupIdentityAcknowledgement() = default; diff --git a/include/l3/short_data_service_packet.hpp b/include/l3/short_data_service_packet.hpp index 9cff346..c2fbad8 100644 --- a/include/l3/short_data_service_packet.hpp +++ b/include/l3/short_data_service_packet.hpp @@ -14,14 +14,14 @@ #include struct ShortLocationReport { - unsigned _BitInt(2) time_elapsed_; - double longitude_; - double latitude_; + unsigned _BitInt(2) time_elapsed_{}; + double longitude_{}; + double latitude_{}; std::string position_error_; - double horizontal_velocity_; + double horizontal_velocity_{}; std::string direction_of_travel_; - unsigned _BitInt(1) type_of_addition_data_; - unsigned _BitInt(8) additional_data_; + unsigned _BitInt(1) type_of_addition_data_{}; + unsigned _BitInt(8) additional_data_{}; ShortLocationReport() = default; explicit ShortLocationReport(BitVector& data); @@ -33,7 +33,7 @@ struct ShortLocationReport { auto operator<<(std::ostream& stream, const ShortLocationReport& slr) -> std::ostream&; struct LocationInformationProtocol { - unsigned _BitInt(2) pdu_type_; + unsigned _BitInt(2) pdu_type_{}; std::optional short_location_report_; LocationInformationProtocol() = default; @@ -46,7 +46,7 @@ struct LocationInformationProtocol { auto operator<<(std::ostream& stream, const LocationInformationProtocol& lip) -> std::ostream&; struct ShortDataServicePacket : public CircuitModeControlEntityPacket { - unsigned _BitInt(8) protocol_identifier_; + unsigned _BitInt(8) protocol_identifier_{}; std::optional location_information_protocol_; static constexpr const std::size_t kLocationInformationProtocolIdentifier = 0b00001010; From ef0f885793c560cbe455b256995854115d26801d Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Tue, 30 Jul 2024 14:07:56 +0200 Subject: [PATCH 10/20] move json serde to own include folder --- include/l3/circuit_mode_control_entity_packet.hpp | 2 +- include/l3/mobile_management_packet.hpp | 2 +- include/{nlohmann_slots.hpp => nlohmann/slots.hpp} | 0 .../{nlohmann_std_optional.hpp => nlohmann/std_optional.hpp} | 0 .../std_unique_ptr_logical_link_control_packet.hpp} | 0 .../{nlohmann_std_variant.hpp => nlohmann/std_variant.hpp} | 0 .../unsigned_bitint.hpp} | 0 include/utils/address.hpp | 4 ++-- src/borzoi/borzoi_sender.cpp | 4 ++-- 9 files changed, 6 insertions(+), 6 deletions(-) rename include/{nlohmann_slots.hpp => nlohmann/slots.hpp} (100%) rename include/{nlohmann_std_optional.hpp => nlohmann/std_optional.hpp} (100%) rename include/{nlohmann_std_unique_ptr_logical_link_control_packet.hpp => nlohmann/std_unique_ptr_logical_link_control_packet.hpp} (100%) rename include/{nlohmann_std_variant.hpp => nlohmann/std_variant.hpp} (100%) rename include/{nlohmann_unsigned_bitint.hpp => nlohmann/unsigned_bitint.hpp} (100%) diff --git a/include/l3/circuit_mode_control_entity_packet.hpp b/include/l3/circuit_mode_control_entity_packet.hpp index d4c4f8e..b54ffd5 100644 --- a/include/l3/circuit_mode_control_entity_packet.hpp +++ b/include/l3/circuit_mode_control_entity_packet.hpp @@ -9,7 +9,7 @@ #pragma once #include "l3/mobile_link_entity_packet.hpp" -#include "nlohmann_std_variant.hpp" // IWYU pragma: keep +#include "nlohmann/std_variant.hpp" // IWYU pragma: keep #include "utils/address.hpp" #include "utils/bit_vector.hpp" #include "utils/type234_parser.hpp" diff --git a/include/l3/mobile_management_packet.hpp b/include/l3/mobile_management_packet.hpp index a34ee4a..ac2c5ef 100644 --- a/include/l3/mobile_management_packet.hpp +++ b/include/l3/mobile_management_packet.hpp @@ -9,7 +9,7 @@ #pragma once #include "l3/mobile_link_entity_packet.hpp" -#include "nlohmann_std_variant.hpp" // IWYU pragma: keep +#include "nlohmann/std_variant.hpp" // IWYU pragma: keep #include "utils/bit_vector.hpp" #include "utils/type234_parser.hpp" #include diff --git a/include/nlohmann_slots.hpp b/include/nlohmann/slots.hpp similarity index 100% rename from include/nlohmann_slots.hpp rename to include/nlohmann/slots.hpp diff --git a/include/nlohmann_std_optional.hpp b/include/nlohmann/std_optional.hpp similarity index 100% rename from include/nlohmann_std_optional.hpp rename to include/nlohmann/std_optional.hpp diff --git a/include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp b/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp similarity index 100% rename from include/nlohmann_std_unique_ptr_logical_link_control_packet.hpp rename to include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp diff --git a/include/nlohmann_std_variant.hpp b/include/nlohmann/std_variant.hpp similarity index 100% rename from include/nlohmann_std_variant.hpp rename to include/nlohmann/std_variant.hpp diff --git a/include/nlohmann_unsigned_bitint.hpp b/include/nlohmann/unsigned_bitint.hpp similarity index 100% rename from include/nlohmann_unsigned_bitint.hpp rename to include/nlohmann/unsigned_bitint.hpp diff --git a/include/utils/address.hpp b/include/utils/address.hpp index 9a65e5c..7677696 100644 --- a/include/utils/address.hpp +++ b/include/utils/address.hpp @@ -8,8 +8,8 @@ #pragma once -#include "nlohmann_std_optional.hpp" // IWYU pragma: keep -#include "nlohmann_unsigned_bitint.hpp" // IWYU pragma: keep +#include "nlohmann/std_optional.hpp" // IWYU pragma: keep +#include "nlohmann/unsigned_bitint.hpp" // IWYU pragma: keep #include "utils/bit_vector.hpp" #include #include diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index 8997050..5110ba4 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -12,8 +12,8 @@ #include "l3/mobile_link_entity_packet.hpp" #include "l3/mobile_management_packet.hpp" #include "l3/short_data_service_packet.hpp" -#include "nlohmann_slots.hpp" // IWYU pragma: keep -#include "nlohmann_std_unique_ptr_logical_link_control_packet.hpp" // IWYU pragma: keep +#include "nlohmann/slots.hpp" // IWYU pragma: keep +#include "nlohmann/std_unique_ptr_logical_link_control_packet.hpp" // IWYU pragma: keep #include #include #include From e83f72db9e4b0aded386d35636b62b7ff5122279 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Tue, 30 Jul 2024 14:31:43 +0200 Subject: [PATCH 11/20] add to_json function for borzoi packets --- CMakeLists.txt | 1 + include/borzoi/borzoi_packets.hpp | 32 ++++++++++++++++++ include/nlohmann/borzoi_send_tetra_packet.hpp | 24 ++++++++++++++ include/nlohmann/borzoi_send_tetra_slots.hpp | 24 ++++++++++++++ src/borzoi/borzoi_packets.cpp | 30 +++++++++++++++++ src/borzoi/borzoi_sender.cpp | 33 +++++++------------ 6 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 include/borzoi/borzoi_packets.hpp create mode 100644 include/nlohmann/borzoi_send_tetra_packet.hpp create mode 100644 include/nlohmann/borzoi_send_tetra_slots.hpp create mode 100644 src/borzoi/borzoi_packets.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dda6f2..8536222 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(tetra-decoder src/bit_stream_decoder.cpp src/iq_stream_decoder.cpp src/prometheus.cpp + src/borzoi/borzoi_packets.cpp src/borzoi/borzoi_sender.cpp src/l2/access_assignment_channel.cpp src/l2/broadcast_synchronization_channel.cpp diff --git a/include/borzoi/borzoi_packets.hpp b/include/borzoi/borzoi_packets.hpp new file mode 100644 index 0000000..f915d90 --- /dev/null +++ b/include/borzoi/borzoi_packets.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "l2/logical_link_control_packet.hpp" +#include "l2/slot.hpp" + +struct BorzoiSendTetraPacket { + std::string time; + std::string station; + const std::unique_ptr& packet; + + /// Construct a packet for Borzoi containing the parsed packet, the current time and the uuid of this instance of + /// tetra decoder. + BorzoiSendTetraPacket(const std::unique_ptr& packet, std::string borzoi_uuid); +}; + +struct BorzoiSendTetraSlots { + std::string time; + std::string station; + const Slots& slots; + + /// Construct a packet for Borzoi containing the received slot, the current time and the uuid of this instance of + /// tetra decoder. + BorzoiSendTetraSlots(const Slots& slots, std::string borzoi_uuid); +}; \ No newline at end of file diff --git a/include/nlohmann/borzoi_send_tetra_packet.hpp b/include/nlohmann/borzoi_send_tetra_packet.hpp new file mode 100644 index 0000000..4ee878c --- /dev/null +++ b/include/nlohmann/borzoi_send_tetra_packet.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "borzoi/borzoi_packets.hpp" +#include "nlohmann/std_unique_ptr_logical_link_control_packet.hpp" +#include + +namespace nlohmann { +template <> struct adl_serializer { + static void to_json(json& j, const BorzoiSendTetraPacket& bstp) { + j = json::object(); + j["time"] = bstp.time; + j["station"] = bstp.station; + adl_serializer>::to_json(j, bstp.packet); + } +}; +} // namespace nlohmann diff --git a/include/nlohmann/borzoi_send_tetra_slots.hpp b/include/nlohmann/borzoi_send_tetra_slots.hpp new file mode 100644 index 0000000..6d35f75 --- /dev/null +++ b/include/nlohmann/borzoi_send_tetra_slots.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "borzoi/borzoi_packets.hpp" +#include "nlohmann/slots.hpp" +#include + +namespace nlohmann { +template <> struct adl_serializer { + static void to_json(json& j, const BorzoiSendTetraSlots& bsts) { + j = json::object(); + j["time"] = bsts.time; + j["station"] = bsts.station; + adl_serializer::to_json(j, bsts.slots); + } +}; +} // namespace nlohmann diff --git a/src/borzoi/borzoi_packets.cpp b/src/borzoi/borzoi_packets.cpp new file mode 100644 index 0000000..5a39fa5 --- /dev/null +++ b/src/borzoi/borzoi_packets.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#include "borzoi/borzoi_packets.hpp" + +inline static auto get_time() -> std::string { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + std::stringstream ss; + ss << std::put_time(&tm, "%FT%T%z"); + return ss.str(); +} + +BorzoiSendTetraPacket::BorzoiSendTetraPacket(const std::unique_ptr& packet, + std::string borzoi_uuid) + : station(std::move(borzoi_uuid)) + , packet(packet) { + time = get_time(); +} + +BorzoiSendTetraSlots::BorzoiSendTetraSlots(const Slots& slots, std::string borzoi_uuid) + : station(std::move(borzoi_uuid)) + , slots(slots) { + time = get_time(); +} \ No newline at end of file diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index 5110ba4..d0abe36 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -7,13 +7,14 @@ */ #include "borzoi/borzoi_sender.hpp" +#include "borzoi/borzoi_packets.hpp" #include "l2/upper_mac_packet.hpp" #include "l3/circuit_mode_control_entity_packet.hpp" #include "l3/mobile_link_entity_packet.hpp" #include "l3/mobile_management_packet.hpp" #include "l3/short_data_service_packet.hpp" -#include "nlohmann/slots.hpp" // IWYU pragma: keep -#include "nlohmann/std_unique_ptr_logical_link_control_packet.hpp" // IWYU pragma: keep +#include "nlohmann/borzoi_send_tetra_packet.hpp" // IWYU pragma: keep +#include "nlohmann/borzoi_send_tetra_slots.hpp" // IWYU pragma: keep #include #include #include @@ -23,20 +24,6 @@ #include #endif -inline static auto get_time() -> std::string { - auto t = std::time(nullptr); - auto tm = *std::localtime(&t); - std::stringstream ss; - ss << std::put_time(&tm, "%FT%T%z"); - return ss.str(); -} - -inline static auto with_time_and_uuid(nlohmann::json& j, const std::string& borzoi_uuid) -> nlohmann::json { - j["time"] = get_time(); - j["station"] = borzoi_uuid; - return j; -} - BorzoiSender::BorzoiSender(ThreadSafeFifo, Slots>>& queue, std::atomic_bool& termination_flag, const std::string& borzoi_url, std::string borzoi_uuid) : queue_(queue) @@ -55,9 +42,10 @@ BorzoiSender::BorzoiSender(ThreadSafeFifo& packet) { - nlohmann::json json = packet; - cpr::Response resp = cpr::Post(borzoi_url_sds_, cpr::Body{with_time_and_uuid(json, borzoi_uuid_).dump()}, - cpr::Header{{"Content-Type", "application/json"}}); + nlohmann::json json = BorzoiSendTetraPacket(packet, borzoi_uuid_); + + cpr::Response resp = + cpr::Post(borzoi_url_sds_, cpr::Body{json.dump()}, cpr::Header{{"Content-Type", "application/json"}}); if (resp.status_code != 200) { std::cout << "Failed to send packet to Borzoi: " << json.dump() << " Error: " << resp.status_code << " " @@ -66,9 +54,10 @@ void BorzoiSender::send_packet(const std::unique_ptr& } void BorzoiSender::send_failed_slots(const Slots& slots) { - nlohmann::json json = slots; - cpr::Response resp = cpr::Post(borzoi_url_failed_slots_, cpr::Body{with_time_and_uuid(json, borzoi_uuid_).dump()}, - cpr::Header{{"Content-Type", "application/json"}}); + nlohmann::json json = BorzoiSendTetraSlots(slots, borzoi_uuid_); + + cpr::Response resp = + cpr::Post(borzoi_url_failed_slots_, cpr::Body{json.dump()}, cpr::Header{{"Content-Type", "application/json"}}); if (resp.status_code != 200) { std::cout << "Failed to send packet to Borzoi: " << json.dump() << " Error: " << resp.status_code << " " From e7bd52fa3c78ec3cd23cd359860d0ebc2617f3c2 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Wed, 31 Jul 2024 16:42:46 +0200 Subject: [PATCH 12/20] fix from_json implementation for std::unique_ptr. fix std variant from_json. add example for downloaded csv back to packets. add print function for std::unique_ptr. --- .gitmodules | 3 + CMakeLists.txt | 71 +++++++++-------- include/borzoi/borzoi_packets.hpp | 38 ++++++++- .../nlohmann/borzoi_receive_tetra_packet.hpp | 23 ++++++ .../nlohmann/borzoi_receive_tetra_slots.hpp | 23 ++++++ ...unique_ptr_logical_link_control_packet.hpp | 12 +-- include/nlohmann/std_variant.hpp | 5 +- ...am_std_unique_ptr_logical_link_control.hpp | 36 +++++++++ lib/rapidcsv | 1 + src/borzoi/borzoi_packets.cpp | 31 +++++++- src/borzoi/borzoi_sender.cpp | 37 ++------- src/experiments/.gitignore | 1 + src/experiments/CMakeLists.txt | 6 ++ src/experiments/README.md | 8 ++ src/experiments/packet_parser_example.cpp | 78 +++++++++++++++++++ 15 files changed, 302 insertions(+), 71 deletions(-) create mode 100644 include/nlohmann/borzoi_receive_tetra_packet.hpp create mode 100644 include/nlohmann/borzoi_receive_tetra_slots.hpp create mode 100644 include/utils/ostream_std_unique_ptr_logical_link_control.hpp create mode 160000 lib/rapidcsv create mode 100644 src/experiments/.gitignore create mode 100644 src/experiments/CMakeLists.txt create mode 100644 src/experiments/README.md create mode 100644 src/experiments/packet_parser_example.cpp diff --git a/.gitmodules b/.gitmodules index dfd68d4..3cb901f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "lib/ViterbiDecoderCpp"] path = lib/ViterbiDecoderCpp url = https://github.com/FiendChain/ViterbiDecoderCpp.git +[submodule "lib/rapidcsv"] + path = lib/rapidcsv + url = https://github.com/d99kris/rapidcsv.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 8536222..d65fcbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,36 +5,38 @@ set(CMAKE_CXX_STANDARD 17) option(NIX_BUILD "Is CMake called by a nix build?" OFF) +add_library(tetra-decoder-library + src/decoder.cpp + src/bit_stream_decoder.cpp + src/iq_stream_decoder.cpp + src/prometheus.cpp + src/borzoi/borzoi_packets.cpp + src/borzoi/borzoi_sender.cpp + src/l2/access_assignment_channel.cpp + src/l2/broadcast_synchronization_channel.cpp + src/l2/logical_link_control_formatter.cpp + src/l2/logical_link_control_packet.cpp + src/l2/lower_mac.cpp + src/l2/slot.cpp + src/l2/timebase_counter.cpp + src/l2/upper_mac.cpp + src/l2/upper_mac_packet.cpp + src/l2/upper_mac_packet_builder.cpp + src/l2/upper_mac_packet_formatter.cpp + src/l3/circuit_mode_control_entity_formatter.cpp + src/l3/circuit_mode_control_entity_packet.cpp + src/l3/mobile_link_entity_formatter.cpp + src/l3/mobile_link_entity_packet.cpp + src/l3/mobile_management_formatter.cpp + src/l3/mobile_management_packet.cpp + src/l3/short_data_service_formatter.cpp + src/l3/short_data_service_packet.cpp + src/utils/address.cpp + src/utils/bit_vector.cpp + src/utils/viter_bi_codec.cpp) + add_executable(tetra-decoder - src/main.cpp - src/decoder.cpp - src/bit_stream_decoder.cpp - src/iq_stream_decoder.cpp - src/prometheus.cpp - src/borzoi/borzoi_packets.cpp - src/borzoi/borzoi_sender.cpp - src/l2/access_assignment_channel.cpp - src/l2/broadcast_synchronization_channel.cpp - src/l2/logical_link_control_formatter.cpp - src/l2/logical_link_control_packet.cpp - src/l2/lower_mac.cpp - src/l2/slot.cpp - src/l2/timebase_counter.cpp - src/l2/upper_mac.cpp - src/l2/upper_mac_packet.cpp - src/l2/upper_mac_packet_builder.cpp - src/l2/upper_mac_packet_formatter.cpp - src/l3/circuit_mode_control_entity_formatter.cpp - src/l3/circuit_mode_control_entity_packet.cpp - src/l3/mobile_link_entity_formatter.cpp - src/l3/mobile_link_entity_packet.cpp - src/l3/mobile_management_formatter.cpp - src/l3/mobile_management_packet.cpp - src/l3/short_data_service_formatter.cpp - src/l3/short_data_service_packet.cpp - src/utils/address.cpp - src/utils/bit_vector.cpp - src/utils/viter_bi_codec.cpp) + src/main.cpp) add_executable(tetra-puncturing src/examples/tetra_puncturing.cpp) @@ -43,11 +45,13 @@ add_executable(tetra-viterbi src/examples/viter_bi_codec.cpp src/examples/tetra_viterbi.cpp) -target_compile_options(tetra-decoder PUBLIC -std=c++17 -Wall -Wno-unused-variable -msse4.1 -O3 -fcolor-diagnostics) +target_compile_options(tetra-decoder-library PUBLIC -std=c++17 -Wall -Wno-unused-variable -msse4.1 -O3 -fcolor-diagnostics) +target_compile_options(tetra-decoder PUBLIC -std=c++17 -Wall -Wno-unused-variable) target_compile_options(tetra-puncturing PUBLIC -std=c++17 -Wall -Wno-unused-variable) target_compile_options(tetra-viterbi PUBLIC -std=c++17 -Wall -Wno-unused-variable) include(lib/ViterbiDecoderCpp/viterbi-config.cmake) +include_directories(lib/rapidcsv/src) include_directories(src) @@ -61,12 +65,15 @@ find_package(cpr REQUIRED) include_directories(${CMAKE_SOURCE_DIR}/include) if (NOT NIX_BUILD) - target_link_libraries(tetra-decoder cxxopts::cxxopts) + target_link_libraries(tetra-decoder-library cxxopts::cxxopts) endif() -target_link_libraries(tetra-decoder ZLIB::ZLIB fmt::fmt nlohmann_json::nlohmann_json viterbi prometheus-cpp::pull cpr::cpr) +target_link_libraries(tetra-decoder-library ZLIB::ZLIB fmt::fmt nlohmann_json::nlohmann_json viterbi prometheus-cpp::pull cpr::cpr) +target_link_libraries(tetra-decoder tetra-decoder-library) target_link_libraries(tetra-viterbi viterbi) install(TARGETS tetra-decoder DESTINATION bin) install(TARGETS tetra-puncturing DESTINATION bin) install(TARGETS tetra-viterbi DESTINATION bin) + +include(src/experiments/CMakeLists.txt) \ No newline at end of file diff --git a/include/borzoi/borzoi_packets.hpp b/include/borzoi/borzoi_packets.hpp index f915d90..c02da0c 100644 --- a/include/borzoi/borzoi_packets.hpp +++ b/include/borzoi/borzoi_packets.hpp @@ -16,17 +16,53 @@ struct BorzoiSendTetraPacket { std::string station; const std::unique_ptr& packet; + BorzoiSendTetraPacket() = delete; + /// Construct a packet for Borzoi containing the parsed packet, the current time and the uuid of this instance of /// tetra decoder. BorzoiSendTetraPacket(const std::unique_ptr& packet, std::string borzoi_uuid); + + friend auto operator<<(std::ostream& stream, const BorzoiSendTetraPacket& packet) -> std::ostream&; }; +auto operator<<(std::ostream& stream, const BorzoiSendTetraPacket& packet) -> std::ostream&; + +struct BorzoiReceiveTetraPacket { + std::string time; + std::string station; + std::unique_ptr packet; + + BorzoiReceiveTetraPacket() = default; + + friend auto operator<<(std::ostream& stream, const BorzoiReceiveTetraPacket& packet) -> std::ostream&; +}; + +auto operator<<(std::ostream& stream, const BorzoiReceiveTetraPacket& packet) -> std::ostream&; + struct BorzoiSendTetraSlots { std::string time; std::string station; const Slots& slots; + BorzoiSendTetraSlots() = delete; + /// Construct a packet for Borzoi containing the received slot, the current time and the uuid of this instance of /// tetra decoder. BorzoiSendTetraSlots(const Slots& slots, std::string borzoi_uuid); -}; \ No newline at end of file + + friend auto operator<<(std::ostream& stream, const BorzoiSendTetraSlots& packet) -> std::ostream&; +}; + +auto operator<<(std::ostream& stream, const BorzoiSendTetraSlots& packet) -> std::ostream&; + +struct BorzoiReceiveTetraSlots { + std::string time; + std::string station; + Slots slots; + + BorzoiReceiveTetraSlots() = default; + + friend auto operator<<(std::ostream& stream, const BorzoiReceiveTetraSlots& packet) -> std::ostream&; +}; + +auto operator<<(std::ostream& stream, const BorzoiReceiveTetraSlots& packet) -> std::ostream&; \ No newline at end of file diff --git a/include/nlohmann/borzoi_receive_tetra_packet.hpp b/include/nlohmann/borzoi_receive_tetra_packet.hpp new file mode 100644 index 0000000..2d65723 --- /dev/null +++ b/include/nlohmann/borzoi_receive_tetra_packet.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "borzoi/borzoi_packets.hpp" +#include "nlohmann/std_unique_ptr_logical_link_control_packet.hpp" +#include + +namespace nlohmann { +template <> struct adl_serializer { + static void from_json(const json& j, BorzoiReceiveTetraPacket& brtp) { + brtp.time = j["time"]; + brtp.station = j["station"]; + adl_serializer>::from_json(j, brtp.packet); + } +}; +} // namespace nlohmann diff --git a/include/nlohmann/borzoi_receive_tetra_slots.hpp b/include/nlohmann/borzoi_receive_tetra_slots.hpp new file mode 100644 index 0000000..448d93e --- /dev/null +++ b/include/nlohmann/borzoi_receive_tetra_slots.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "borzoi/borzoi_packets.hpp" +#include "nlohmann/slots.hpp" +#include + +namespace nlohmann { +template <> struct adl_serializer { + static void from_json(const json& j, BorzoiReceiveTetraSlots& brtp) { + brtp.time = j["time"]; + brtp.station = j["station"]; + adl_serializer::from_json(j, brtp.slots); + } +}; +} // namespace nlohmann diff --git a/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp b/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp index f340d03..3ba3e60 100644 --- a/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp +++ b/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp @@ -50,7 +50,7 @@ template <> struct adl_serializer> { } static void from_json(const json& j, std::unique_ptr& packet) { - auto protocol_version = j["protocol_version"].template get(); + auto protocol_version = std::stoi(j["protocol_version"].template get()); if (protocol_version != kPacketApiVersion) { throw std::runtime_error("Cannot process packets different API version."); } @@ -60,14 +60,14 @@ template <> struct adl_serializer> { if (key == "LogicalLinkControlPacket") { packet = std::make_unique(j["value"].template get()); } else if (key == "MobileLinkEntityPacket") { - packet = std::make_unique(j["value"].template get()); + packet = std::make_unique(j["value"].template get()); } else if (key == "MobileManagementPacket") { - packet = std::make_unique(j["value"].template get()); + packet = std::make_unique(j["value"].template get()); } else if (key == "CircuitModeControlEntityPacket") { - packet = - std::make_unique(j["value"].template get()); + packet = std::make_unique( + j["value"].template get()); } else if (key == "ShortDataServicePacket") { - packet = std::make_unique(j["value"].template get()); + packet = std::make_unique(j["value"].template get()); } else { throw std::runtime_error("Unknown packet type: " + key); } diff --git a/include/nlohmann/std_variant.hpp b/include/nlohmann/std_variant.hpp index ff43a1d..30c971b 100644 --- a/include/nlohmann/std_variant.hpp +++ b/include/nlohmann/std_variant.hpp @@ -46,8 +46,9 @@ template struct adl_serializer> { var = std::variant(typename std::tuple_element<3, std::tuple>::type(variant)); } } - - throw std::runtime_error("Cannot deserialize a std::variant with more than four variants."); + if constexpr (sizeof...(Ts) > 4) { + throw std::runtime_error("Cannot deserialize a std::variant with more than four variants."); + } } }; } // namespace nlohmann diff --git a/include/utils/ostream_std_unique_ptr_logical_link_control.hpp b/include/utils/ostream_std_unique_ptr_logical_link_control.hpp new file mode 100644 index 0000000..646dec1 --- /dev/null +++ b/include/utils/ostream_std_unique_ptr_logical_link_control.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "l3/mobile_link_entity_packet.hpp" +#include "l3/mobile_management_packet.hpp" +#include "l3/short_data_service_packet.hpp" + +inline auto operator<<(std::ostream& stream, const std::unique_ptr& packet) -> std::ostream& { + /// process the parsed packet + auto* cplane_signalling = dynamic_cast(packet.get()); + auto* llc = dynamic_cast(cplane_signalling); + + stream << *cplane_signalling; + stream << *llc; + if (auto* mle = dynamic_cast(llc)) { + stream << *mle; + if (auto* cmce = dynamic_cast(llc)) { + stream << *cmce; + if (auto* sds = dynamic_cast(llc)) { + stream << *sds; + } + } + if (auto* mm = dynamic_cast(llc)) { + stream << *mm; + } + } + + return stream; +} \ No newline at end of file diff --git a/lib/rapidcsv b/lib/rapidcsv new file mode 160000 index 0000000..f438d37 --- /dev/null +++ b/lib/rapidcsv @@ -0,0 +1 @@ +Subproject commit f438d3774848e3c5e281fb15e12f97c0872cf6a8 diff --git a/src/borzoi/borzoi_packets.cpp b/src/borzoi/borzoi_packets.cpp index 5a39fa5..41ad47a 100644 --- a/src/borzoi/borzoi_packets.cpp +++ b/src/borzoi/borzoi_packets.cpp @@ -7,6 +7,7 @@ */ #include "borzoi/borzoi_packets.hpp" +#include "utils/ostream_std_unique_ptr_logical_link_control.hpp" inline static auto get_time() -> std::string { auto t = std::time(nullptr); @@ -27,4 +28,32 @@ BorzoiSendTetraSlots::BorzoiSendTetraSlots(const Slots& slots, std::string borzo : station(std::move(borzoi_uuid)) , slots(slots) { time = get_time(); -} \ No newline at end of file +} + +auto operator<<(std::ostream& stream, const BorzoiSendTetraPacket& packet) -> std::ostream& { + stream << packet.time << std::endl; + stream << packet.station << std::endl; + stream << packet.packet << std::endl; + return stream; +}; + +auto operator<<(std::ostream& stream, const BorzoiReceiveTetraPacket& packet) -> std::ostream& { + stream << packet.time << std::endl; + stream << packet.station << std::endl; + stream << packet.packet << std::endl; + return stream; +}; + +auto operator<<(std::ostream& stream, const BorzoiSendTetraSlots& packet) -> std::ostream& { + stream << packet.time << std::endl; + stream << packet.station << std::endl; + stream << packet.slots << std::endl; + return stream; +}; + +auto operator<<(std::ostream& stream, const BorzoiReceiveTetraSlots& packet) -> std::ostream& { + stream << packet.time << std::endl; + stream << packet.station << std::endl; + stream << packet.slots << std::endl; + return stream; +}; \ No newline at end of file diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index d0abe36..1a120a6 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -8,13 +8,9 @@ #include "borzoi/borzoi_sender.hpp" #include "borzoi/borzoi_packets.hpp" -#include "l2/upper_mac_packet.hpp" -#include "l3/circuit_mode_control_entity_packet.hpp" -#include "l3/mobile_link_entity_packet.hpp" -#include "l3/mobile_management_packet.hpp" -#include "l3/short_data_service_packet.hpp" -#include "nlohmann/borzoi_send_tetra_packet.hpp" // IWYU pragma: keep -#include "nlohmann/borzoi_send_tetra_slots.hpp" // IWYU pragma: keep +#include "nlohmann/borzoi_send_tetra_packet.hpp" // IWYU pragma: keep +#include "nlohmann/borzoi_send_tetra_slots.hpp" // IWYU pragma: keep +#include "utils/ostream_std_unique_ptr_logical_link_control.hpp" // IWYU pragma: keep #include #include #include @@ -81,32 +77,15 @@ void BorzoiSender::worker() { [this](const auto& arg) { using T = std::decay_t; if constexpr (std::is_same_v>) { - /// process the parsed packet - auto* cplane_signalling = dynamic_cast(arg.get()); - auto* llc = dynamic_cast(cplane_signalling); + send_packet(arg); // Do not log acknowledgements - if (llc->basic_link_information_ && - (llc->basic_link_information_->basic_link_type_ == BasicLinkType::kBlAckWithoutFcs || - llc->basic_link_information_->basic_link_type_ == BasicLinkType::kBlAckWithFcs)) { + if (arg->basic_link_information_ && + (arg->basic_link_information_->basic_link_type_ == BasicLinkType::kBlAckWithoutFcs || + arg->basic_link_information_->basic_link_type_ == BasicLinkType::kBlAckWithFcs)) { return; } - std::cout << *cplane_signalling; - std::cout << *llc; - if (auto* mle = dynamic_cast(llc)) { - std::cout << *mle; - if (auto* cmce = dynamic_cast(llc)) { - std::cout << *cmce; - if (auto* sds = dynamic_cast(llc)) { - std::cout << *sds; - } - } - if (auto* mm = dynamic_cast(llc)) { - std::cout << *mm; - } - std::cout << std::endl; - } - send_packet(arg); + std::cout << arg << std::endl; } else if constexpr (std::is_same_v) { /// send out the slots which had an error while parsing send_failed_slots(arg); diff --git a/src/experiments/.gitignore b/src/experiments/.gitignore new file mode 100644 index 0000000..afed073 --- /dev/null +++ b/src/experiments/.gitignore @@ -0,0 +1 @@ +*.csv diff --git a/src/experiments/CMakeLists.txt b/src/experiments/CMakeLists.txt new file mode 100644 index 0000000..fd68018 --- /dev/null +++ b/src/experiments/CMakeLists.txt @@ -0,0 +1,6 @@ +# Here we create an executable for each experiment and link it to the rest of the software. + +add_executable(packet-parser-example + src/experiments/packet_parser_example.cpp) + +target_link_libraries(packet-parser-example tetra-decoder-library) \ No newline at end of file diff --git a/src/experiments/README.md b/src/experiments/README.md new file mode 100644 index 0000000..daedd23 --- /dev/null +++ b/src/experiments/README.md @@ -0,0 +1,8 @@ +# Experiments using TETRA data + +The borzoi integration allows to save all relevant packet data of a TETRA cell. +We can use this data to do queries and further analysis. + +Using a query we can extract all saved data through the grafana explore pane: `SELECT key, value::jsonb, time, station, protocol_version FROM tetra_data WHERE $__timeFilter(time) ORDER BY time desc`. + +To download the selected data as CSV click on: `Query inspector` -> `Data` -> `Download CSV`. The application `parser_example` show how to convert this data back into the correct C++ structures. \ No newline at end of file diff --git a/src/experiments/packet_parser_example.cpp b/src/experiments/packet_parser_example.cpp new file mode 100644 index 0000000..bb6cdf3 --- /dev/null +++ b/src/experiments/packet_parser_example.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#include "borzoi/borzoi_packets.hpp" +#include "nlohmann/borzoi_receive_tetra_packet.hpp" // IWYU pragma: keep +#include +#include +#include +#include +#include +#include +#include +#include + +auto main(int argc, char** argv) -> int { + std::string datafile; + + cxxopts::Options options("parser-example", "Reads a csv file and extracts the contained packets."); + + // clang-format off + options.add_options() + ("h,help", "Print usage") + ("datafile", "the path to the file containing historic packet data", cxxopts::value(datafile)->default_value("datafile.csv")) + ; + // clang-format on + + try { + auto result = options.parse(argc, argv); + + if (result.count("help")) { + std::cout << options.help() << std::endl; + return EXIT_SUCCESS; + } + } catch (std::exception& e) { + std::cout << "error parsing options: " << e.what() << std::endl; + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(datafile)) { + std::cout << "Datafile does not exists." << std::endl; + return EXIT_FAILURE; + } + + /// The variable datafile contains the path to the csv file. + std::cout << "Parsing datafile: " << datafile << std::endl; + + rapidcsv::Document doc(datafile); + + std::cout << "Read " << doc.GetRowCount() << " rows." << std::endl; + + auto column_names = doc.GetColumnNames(); + + for (std::size_t i = 0; i < doc.GetRowCount(); i++) { + auto row = doc.GetRow(i); + auto json = nlohmann::json::object(); + + for (std::size_t i = 0; i < row.size(); i++) { + auto value = row.at(i); + auto column = column_names.at(i); + if (column == "value") { + json[column] = nlohmann::json::parse(value); + } else { + json[column] = value; + } + } + + std::cout << json << std::endl; + BorzoiReceiveTetraPacket packet = json; + std::cout << packet << std::endl; + } + + return EXIT_SUCCESS; +} \ No newline at end of file From 875bde34bcef67313186e3c69aa668c3242e989e Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Wed, 31 Jul 2024 16:46:27 +0200 Subject: [PATCH 13/20] move ostream_std_unique_ptr_logical_link_control.hpp to ostream_std_unique_ptr_logical_link_control_packet.hpp --- ... ostream_std_unique_ptr_logical_link_control_packet.hpp} | 0 src/borzoi/borzoi_packets.cpp | 2 +- src/borzoi/borzoi_sender.cpp | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename include/utils/{ostream_std_unique_ptr_logical_link_control.hpp => ostream_std_unique_ptr_logical_link_control_packet.hpp} (100%) diff --git a/include/utils/ostream_std_unique_ptr_logical_link_control.hpp b/include/utils/ostream_std_unique_ptr_logical_link_control_packet.hpp similarity index 100% rename from include/utils/ostream_std_unique_ptr_logical_link_control.hpp rename to include/utils/ostream_std_unique_ptr_logical_link_control_packet.hpp diff --git a/src/borzoi/borzoi_packets.cpp b/src/borzoi/borzoi_packets.cpp index 41ad47a..aaa797e 100644 --- a/src/borzoi/borzoi_packets.cpp +++ b/src/borzoi/borzoi_packets.cpp @@ -7,7 +7,7 @@ */ #include "borzoi/borzoi_packets.hpp" -#include "utils/ostream_std_unique_ptr_logical_link_control.hpp" +#include "utils/ostream_std_unique_ptr_logical_link_control_packet.hpp" inline static auto get_time() -> std::string { auto t = std::time(nullptr); diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index 1a120a6..a00a9e4 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -8,9 +8,9 @@ #include "borzoi/borzoi_sender.hpp" #include "borzoi/borzoi_packets.hpp" -#include "nlohmann/borzoi_send_tetra_packet.hpp" // IWYU pragma: keep -#include "nlohmann/borzoi_send_tetra_slots.hpp" // IWYU pragma: keep -#include "utils/ostream_std_unique_ptr_logical_link_control.hpp" // IWYU pragma: keep +#include "nlohmann/borzoi_send_tetra_packet.hpp" // IWYU pragma: keep +#include "nlohmann/borzoi_send_tetra_slots.hpp" // IWYU pragma: keep +#include "utils/ostream_std_unique_ptr_logical_link_control_packet.hpp" // IWYU pragma: keep #include #include #include From 9fe7fa292d66cafd2196aec5432f2c4ce03de651 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Thu, 1 Aug 2024 22:12:03 +0200 Subject: [PATCH 14/20] update readme --- src/experiments/README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/experiments/README.md b/src/experiments/README.md index daedd23..3f28912 100644 --- a/src/experiments/README.md +++ b/src/experiments/README.md @@ -3,6 +3,15 @@ The borzoi integration allows to save all relevant packet data of a TETRA cell. We can use this data to do queries and further analysis. +## Received Packets + Using a query we can extract all saved data through the grafana explore pane: `SELECT key, value::jsonb, time, station, protocol_version FROM tetra_data WHERE $__timeFilter(time) ORDER BY time desc`. -To download the selected data as CSV click on: `Query inspector` -> `Data` -> `Download CSV`. The application `parser_example` show how to convert this data back into the correct C++ structures. \ No newline at end of file +To download the selected data as CSV click on: `Query inspector` -> `Data` -> `Download CSV`. The application `packet_parser_example` show how to convert this data back into the correct C++ structures. + +## Slots with CRC errors + +Query: `SELECT * FROM tetra_failed_slots WHERE $__timeFilter(time) ORDER BY time desc`. + +There is no example application provided showing how to convert the csv from grafana to C++ structures. +However, the principle is the same as in the `packet_parser_example`. \ No newline at end of file From bbc5fb308bd7e862afa176acc97323d0282b0b5e Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Tue, 6 Aug 2024 17:48:02 +0200 Subject: [PATCH 15/20] use enum for json serialization in LogicalLinkControlPacket --- ...unique_ptr_logical_link_control_packet.hpp | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp b/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp index 3ba3e60..bf5fe40 100644 --- a/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp +++ b/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp @@ -17,6 +17,14 @@ static constexpr const int kPacketApiVersion = 0; +enum class PacketType { + kLogicalLinkControlPacket, + kMobileLinkEntityPacket, + kCircuitModeControlEntityPacket, + kMobileManagementPacket, + kShortDataServicePacket, +}; + namespace nlohmann { template <> struct adl_serializer> { static void to_json(json& j, const std::unique_ptr& packet) { @@ -26,25 +34,25 @@ template <> struct adl_serializer> { if (auto* cmce = dynamic_cast(mle)) { if (auto* sds = dynamic_cast(mle)) { // Emit ShortDataServicePacket packet to json - j["key"] = "ShortDataServicePacket"; + j["key"] = PacketType::kShortDataServicePacket; j["value"] = *sds; } else { // Emit CircuitModeControlEntityPacket packet to json - j["key"] = "CircuitModeControlEntityPacket"; + j["key"] = PacketType::kCircuitModeControlEntityPacket; j["value"] = *cmce; } } else if (auto* mm = dynamic_cast(mle)) { // Emit MobileManagementPacket packet to json - j["key"] = "MobileManagementPacket"; + j["key"] = PacketType::kMobileManagementPacket; j["value"] = *mm; } else { // Emit MobileLinkEntityPacket packet to json - j["key"] = "MobileLinkEntityPacket"; + j["key"] = PacketType::kMobileLinkEntityPacket; j["value"] = *mle; } } else { // Emit LogicalLinkControlPacket packet to json - j["key"] = "LogicalLinkControlPacket"; + j["key"] = PacketType::kLogicalLinkControlPacket; j["value"] = *packet; } } @@ -55,21 +63,20 @@ template <> struct adl_serializer> { throw std::runtime_error("Cannot process packets different API version."); } - auto key = j["key"].template get(); + auto key = j["key"].template get(); - if (key == "LogicalLinkControlPacket") { + switch (key) { + case PacketType::kLogicalLinkControlPacket: packet = std::make_unique(j["value"].template get()); - } else if (key == "MobileLinkEntityPacket") { + case PacketType::kMobileLinkEntityPacket: packet = std::make_unique(j["value"].template get()); - } else if (key == "MobileManagementPacket") { - packet = std::make_unique(j["value"].template get()); - } else if (key == "CircuitModeControlEntityPacket") { + case PacketType::kCircuitModeControlEntityPacket: packet = std::make_unique( j["value"].template get()); - } else if (key == "ShortDataServicePacket") { + case PacketType::kMobileManagementPacket: + packet = std::make_unique(j["value"].template get()); + case PacketType::kShortDataServicePacket: packet = std::make_unique(j["value"].template get()); - } else { - throw std::runtime_error("Unknown packet type: " + key); } } }; From 3e4c02146a5290f9d69ecc8fe9e50f4000b02951 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Sun, 18 Aug 2024 21:12:22 +0200 Subject: [PATCH 16/20] comment out debug prints --- src/borzoi/borzoi_sender.cpp | 2 +- src/l2/lower_mac.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/borzoi/borzoi_sender.cpp b/src/borzoi/borzoi_sender.cpp index a00a9e4..12f61ac 100644 --- a/src/borzoi/borzoi_sender.cpp +++ b/src/borzoi/borzoi_sender.cpp @@ -85,7 +85,7 @@ void BorzoiSender::worker() { arg->basic_link_information_->basic_link_type_ == BasicLinkType::kBlAckWithFcs)) { return; } - std::cout << arg << std::endl; + // std::cout << arg << std::endl; } else if constexpr (std::is_same_v) { /// send out the slots which had an error while parsing send_failed_slots(arg); diff --git a/src/l2/lower_mac.cpp b/src/l2/lower_mac.cpp index 30591c3..ccdf614 100644 --- a/src/l2/lower_mac.cpp +++ b/src/l2/lower_mac.cpp @@ -287,7 +287,7 @@ auto LowerMac::process(std::vector frame, BurstType burst_type) -> Lowe // Set to true if there was some decoding error in the lower MAC bool decode_error = false; - fmt::print("[Physical Channel] Decoding: {}\n", burst_type); + // fmt::print("[Physical Channel] Decoding: {}\n", burst_type); // Once we received the Synchronization on the downlink, increment the time counter for every received burst. // We do not have any time handling for uplink processing. From aed2f6b26ac3511c0e286ba72a07e0b6852c7162 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Sun, 18 Aug 2024 22:43:52 +0200 Subject: [PATCH 17/20] increase receive buffer for 4KB to 64KB --- include/decoder.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/decoder.hpp b/include/decoder.hpp index e168180..f5190ca 100644 --- a/include/decoder.hpp +++ b/include/decoder.hpp @@ -88,5 +88,6 @@ class Decoder { // bit stream -> false bool iq_or_bit_stream_; - static const std::size_t kRX_BUFFER_SIZE = 4096; + // 64KB receive buffer. + static const std::size_t kRX_BUFFER_SIZE = 64 * 1024; }; From 180e4aebdc4602506cfc9c78f5f1f493a6ec8589 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Wed, 21 Aug 2024 01:03:20 +0200 Subject: [PATCH 18/20] fix borzoi json packet receive --- .../std_unique_ptr_logical_link_control_packet.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp b/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp index bf5fe40..62e69a3 100644 --- a/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp +++ b/include/nlohmann/std_unique_ptr_logical_link_control_packet.hpp @@ -63,20 +63,25 @@ template <> struct adl_serializer> { throw std::runtime_error("Cannot process packets different API version."); } - auto key = j["key"].template get(); + auto key = PacketType(std::stoi(j["key"].template get())); switch (key) { case PacketType::kLogicalLinkControlPacket: packet = std::make_unique(j["value"].template get()); + break; case PacketType::kMobileLinkEntityPacket: packet = std::make_unique(j["value"].template get()); + break; case PacketType::kCircuitModeControlEntityPacket: packet = std::make_unique( j["value"].template get()); + break; case PacketType::kMobileManagementPacket: packet = std::make_unique(j["value"].template get()); + break; case PacketType::kShortDataServicePacket: packet = std::make_unique(j["value"].template get()); + break; } } }; From 5ba88d51807c4ffb4a3c9471824a269ab22578f6 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Wed, 21 Aug 2024 15:11:37 +0200 Subject: [PATCH 19/20] add example application to parse failed slots --- include/nlohmann/slots.hpp | 36 ++++++++++++++++++----- src/experiments/CMakeLists.txt | 7 ++++- src/experiments/README.md | 3 +- src/experiments/packet_parser_example.cpp | 2 +- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/include/nlohmann/slots.hpp b/include/nlohmann/slots.hpp index b65ae78..a061b86 100644 --- a/include/nlohmann/slots.hpp +++ b/include/nlohmann/slots.hpp @@ -11,6 +11,26 @@ #include "l2/slot.hpp" #include +static auto stob(const std::string& str) -> bool { + bool retval = false; + + // convert integer (0 and 1) to bool + std::istringstream is(str); + is >> retval; + + // convert boolean string (false and true) to bool + if (is.fail()) { + is.clear(); + is >> std::boolalpha >> retval; + } + + if (is.fail()) { + throw std::invalid_argument("Cannot convert: " + str + " to bool."); + } + + return retval; +}; + namespace nlohmann { template <> struct adl_serializer { static void to_json(json& j, const Slots& slots) { @@ -32,12 +52,13 @@ template <> struct adl_serializer { } static void from_json(const json& j, Slots& slots) { - auto burst_type = j["burst_type"].template get(); - auto slot_type = j["slot_type"].template get(); - auto first_slot_logical_channel = j["first_slot_logical_channel"].template get(); + auto burst_type = BurstType(std::stoi(j["burst_type"].template get())); + auto slot_type = SlotType(std::stoi(j["slot_type"].template get())); + auto first_slot_logical_channel = + LogicalChannel(std::stoi(j["first_slot_logical_channel"].template get())); auto first_slot_data = j["first_slot_data"].template get(); - auto first_slot_crc_ok = j["first_slot_crc_ok"].template get(); - auto second_slot_present = j["second_slot_present"].template get(); + auto first_slot_crc_ok = stob(j["first_slot_crc_ok"].template get()); + auto second_slot_present = stob(j["second_slot_present"].template get()); auto first_slot = Slot(LogicalChannelDataAndCrc{ .channel = first_slot_logical_channel, @@ -46,9 +67,10 @@ template <> struct adl_serializer { }); if (second_slot_present) { - auto second_slot_logical_channel = j["second_slot_logical_channel"].template get(); + auto second_slot_logical_channel = + LogicalChannel(std::stoi(j["second_slot_logical_channel"].template get())); auto second_slot_data = j["second_slot_data"].template get(); - auto second_slot_crc_ok = j["second_slot_crc_ok"].template get(); + auto second_slot_crc_ok = stob(j["second_slot_crc_ok"].template get()); auto second_slot = Slot(LogicalChannelDataAndCrc{ .channel = second_slot_logical_channel, diff --git a/src/experiments/CMakeLists.txt b/src/experiments/CMakeLists.txt index fd68018..91eaf0d 100644 --- a/src/experiments/CMakeLists.txt +++ b/src/experiments/CMakeLists.txt @@ -3,4 +3,9 @@ add_executable(packet-parser-example src/experiments/packet_parser_example.cpp) -target_link_libraries(packet-parser-example tetra-decoder-library) \ No newline at end of file +target_link_libraries(packet-parser-example tetra-decoder-library) + +add_executable(slots-parser-example + src/experiments/slots_parser_example.cpp) + +target_link_libraries(slots-parser-example tetra-decoder-library) \ No newline at end of file diff --git a/src/experiments/README.md b/src/experiments/README.md index 3f28912..4176af6 100644 --- a/src/experiments/README.md +++ b/src/experiments/README.md @@ -13,5 +13,4 @@ To download the selected data as CSV click on: `Query inspector` -> `Data` -> `D Query: `SELECT * FROM tetra_failed_slots WHERE $__timeFilter(time) ORDER BY time desc`. -There is no example application provided showing how to convert the csv from grafana to C++ structures. -However, the principle is the same as in the `packet_parser_example`. \ No newline at end of file +The application `slots_parser_example` show how to convert this data back into the correct C++ structures. \ No newline at end of file diff --git a/src/experiments/packet_parser_example.cpp b/src/experiments/packet_parser_example.cpp index bb6cdf3..cf7be05 100644 --- a/src/experiments/packet_parser_example.cpp +++ b/src/experiments/packet_parser_example.cpp @@ -20,7 +20,7 @@ auto main(int argc, char** argv) -> int { std::string datafile; - cxxopts::Options options("parser-example", "Reads a csv file and extracts the contained packets."); + cxxopts::Options options("packet-parser-example", "Reads a csv file and extracts the contained packets."); // clang-format off options.add_options() From 5c529aef79cee6360dab662cbb7dcaae95a88b67 Mon Sep 17 00:00:00 2001 From: Markus Schmidl Date: Wed, 21 Aug 2024 15:13:28 +0200 Subject: [PATCH 20/20] add missing file --- src/experiments/slots_parser_example.cpp | 78 ++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/experiments/slots_parser_example.cpp diff --git a/src/experiments/slots_parser_example.cpp b/src/experiments/slots_parser_example.cpp new file mode 100644 index 0000000..dc2bb13 --- /dev/null +++ b/src/experiments/slots_parser_example.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#include "borzoi/borzoi_packets.hpp" +#include "nlohmann/borzoi_receive_tetra_slots.hpp" // IWYU pragma: keep +#include +#include +#include +#include +#include +#include +#include +#include + +auto main(int argc, char** argv) -> int { + std::string datafile; + + cxxopts::Options options("slots-parser-example", "Reads a csv file and extracts the contained slots."); + + // clang-format off + options.add_options() + ("h,help", "Print usage") + ("datafile", "the path to the file containing historic slots data", cxxopts::value(datafile)->default_value("datafile.csv")) + ; + // clang-format on + + try { + auto result = options.parse(argc, argv); + + if (result.count("help")) { + std::cout << options.help() << std::endl; + return EXIT_SUCCESS; + } + } catch (std::exception& e) { + std::cout << "error parsing options: " << e.what() << std::endl; + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(datafile)) { + std::cout << "Datafile does not exists." << std::endl; + return EXIT_FAILURE; + } + + /// The variable datafile contains the path to the csv file. + std::cout << "Parsing datafile: " << datafile << std::endl; + + rapidcsv::Document doc(datafile); + + std::cout << "Read " << doc.GetRowCount() << " rows." << std::endl; + + auto column_names = doc.GetColumnNames(); + + for (std::size_t i = 0; i < doc.GetRowCount(); i++) { + auto row = doc.GetRow(i); + auto json = nlohmann::json::object(); + + for (std::size_t i = 0; i < row.size(); i++) { + auto value = row.at(i); + auto column = column_names.at(i); + if (column == "first_slot_data" || (column == "second_slot_data" && !value.empty())) { + json[column] = nlohmann::json::parse(value); + } else { + json[column] = value; + } + } + + std::cout << json << std::endl; + BorzoiReceiveTetraSlots packet = json; + std::cout << packet << std::endl; + } + + return EXIT_SUCCESS; +} \ No newline at end of file