// // Created by erki on 18.07.22. // #ifndef SKL_TUNNEL_RADIO_FRAME_HPP #define SKL_TUNNEL_RADIO_FRAME_HPP #include #include #include #include #include #include /** * Reference section 37.1 of the SAMR21 datasheet for these structures. */ namespace radio::protocol { struct PhyHeader { std::uint8_t frame_length : 7; std::uint8_t reserved : 1; } __attribute__((packed)); struct FrameControlField { enum FrameType { FRAME_TYPE_BEACON = 0b000, FRAME_TYPE_DATA = 0b001, FRAME_TYPE_ACKNOWLEDGE = 0b010, FRAME_TYPE_MAC_COMMAND = 0b011 }; enum AddressingMode { ADDRESSING_MODE_NOT_SPECIFIED = 0b00, ADDRESSING_MODE_SHORT = 0b10, ADDRESSING_MODE_LONG = 0b11 }; FrameType type : 3; std::uint8_t security_enabled : 1; std::uint8_t frame_pending : 1; std::uint8_t ack_requested : 1; std::uint8_t pan_id_compression : 1; std::uint8_t : 3; AddressingMode destination_addressing_mode : 2; std::uint8_t frame_version : 2; AddressingMode source_addressing_mode : 2; } __attribute__((packed)); struct Address { std::variant mac = 0ull; std::uint16_t pan_id = 0; FrameControlField::AddressingMode getAddressingMode() const { if (std::holds_alternative(mac)) return FrameControlField::ADDRESSING_MODE_SHORT; else if (std::holds_alternative(mac)) return FrameControlField::ADDRESSING_MODE_LONG; else return FrameControlField::ADDRESSING_MODE_NOT_SPECIFIED; } void setShortAddress(const std::uint16_t address) { mac = address; } void setLongAddress(const std::uint64_t address) { mac = address; } std::uint16_t getShortAddress() const { const std::uint16_t* addr = std::get_if(&mac); SKULLC_ASSERT_DEBUG(addr != nullptr); return *addr; } std::uint64_t getLongAddress() const { const std::uint64_t* addr = std::get_if(&mac); SKULLC_ASSERT_DEBUG(addr != nullptr); return *addr; } }; struct FrameStructure { FrameControlField frame_control_field; std::uint8_t sequence_number; Address destination_address; Address source_address; std::uint16_t frame_checksum; static constexpr std::size_t max_frame_size = 127; static constexpr std::size_t max_payload_size = max_frame_size - sizeof(FrameControlField) - sizeof(frame_checksum) - sizeof(sequence_number) - (2 * (sizeof(std::uint16_t) + sizeof(std::uint64_t))); std::uint8_t payload_length; std::array payload; FrameStructure(); static FrameStructure createDataFrame(); FrameStructure& setPayload(const std::uint8_t* data, const std::uint8_t length); template FrameStructure& setPayload(const std::array& data) { static_assert(N <= max_payload_size, "Data length N exceeds max_payload_size."); return setPayload(data.data(), std::uint8_t(N)); } FrameStructure& setSourceAddress(const Address& addr); FrameStructure& setDestinationAddress(const Address& addr); std::uint8_t getTotalFrameLength() const; std::uint8_t calculatePayloadLength(const std::uint8_t total_frame_length) const; }; } #endif //SKL_TUNNEL_RADIO_FRAME_HPP