136 lines
3.3 KiB
C++
136 lines
3.3 KiB
C++
//
|
|
// Created by erki on 18.07.22.
|
|
//
|
|
|
|
#ifndef SKL_TUNNEL_RADIO_FRAME_HPP
|
|
#define SKL_TUNNEL_RADIO_FRAME_HPP
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
#include <optional>
|
|
#include <variant>
|
|
|
|
#include <utility_assert.hpp>
|
|
|
|
/**
|
|
* 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<std::uint16_t, std::uint64_t> mac = 0ull;
|
|
std::uint16_t pan_id = 0;
|
|
|
|
FrameControlField::AddressingMode getAddressingMode() const
|
|
{
|
|
if (std::holds_alternative<std::uint16_t>(mac))
|
|
return FrameControlField::ADDRESSING_MODE_SHORT;
|
|
else if (std::holds_alternative<std::uint64_t>(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<std::uint16_t>(&mac);
|
|
SKULLC_ASSERT_DEBUG(addr != nullptr);
|
|
|
|
return *addr;
|
|
}
|
|
|
|
std::uint64_t getLongAddress() const
|
|
{
|
|
const std::uint64_t* addr = std::get_if<std::uint64_t>(&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<std::uint8_t, max_payload_size> payload;
|
|
|
|
FrameStructure();
|
|
|
|
static FrameStructure createDataFrame();
|
|
|
|
FrameStructure& setPayload(const std::uint8_t* data, const std::uint8_t length);
|
|
template<std::size_t N>
|
|
FrameStructure& setPayload(const std::array<std::uint8_t, N>& 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
|