Files

131 lines
5.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifdef DATA_LINK
#pragma once
#include "freertos/FreeRTOS.h"
#include <variant>
#include <cstdint>
#include <vector>
#define BROADCAST_ADDR 0xFF //used for discovery (finding the board's neighbours). this will mean the board ids will have 2^8-2 = 254 unique IDs that could be assigned
#define PC_ADDR 0x0 //setting 0 to be the PC
#define START_OF_FRAME 0xAB //0b1010_1011 - denotes the start of frame
#define MAX_FRAME_SIZE 121 //Max 121B (due to rmt) - note this includes the overhead of the frame. the actual payload max depends on the frame type (eg. 121 - 9 B is the max control data length)
#define MAX_GENERIC_NUM_FRAG (1 << 16) // Max 2**16 Fragments can be made with a generic frame (total 2**16 *MAX_GENERIC_DATA_LEN B of data can be sent ~ 6.7 MiB)
#define MAX_FRAME_QUEUE_SIZE 15 //Size of the queue for the frame scheduler (per channel)
//Flags
#define FLAG_FRAG 0x8 //0b1000 //this fragmented frame is part of a larger frame
#define FLAG_DISCOVERY 0x4 //0b0100
#define FLAG_NEIGH_TABLE 0x2 //0b0010 - used to denote the frame contains the neighbour tables (used for finding the configuration/topology of the network); similar to an ARP or MAC table
#define FLAG_ACK 0x1 //0b0001_0000 - used for confirming receipt of different types of frames from the neighbours
#define GET_TYPE(x) ((x) & 0xF0)
#define GET_FLAG(x) ((x) & 0x0F)
#define MAKE_TYPE_FLAG(type, flag) ((uint8_t)((type & 0xF0) | (flag & 0xF)))
#define IS_CONTROL_FRAME(x) (((x) & 0x80) != 0)
#define CONTROL_FRAME_OVERHEAD 9
#define GENERIC_FRAME_OVERHEAD 14
#define CONTROL_FRAME_HASH_SIZE 4 // 4-byte FNV-1a hash prepended to control frame payload on the wire
#define MAX_GENERIC_DATA_LEN (MAX_FRAME_SIZE - GENERIC_FRAME_OVERHEAD)
// Control data max accounts for the 4-byte hash prefix that is prepended on transmit and stripped on receive
#define MAX_CONTROL_DATA_LEN (MAX_FRAME_SIZE - CONTROL_FRAME_OVERHEAD - CONTROL_FRAME_HASH_SIZE)
//Generic Frame Fragment ACK
#define GENERIC_FRAG_ACK_DATA_SIZE 7
#define GENERIC_FRAG_ACK_PREAMBLE 0x69
#define CONTROL_FRAME_TYPE 0x80 //if the frame type MSB is set to 1, use the control frame
//Types (total 2^4 = 16 different types)
enum class FrameType : uint8_t {
//Control Frames
MOTOR_TYPE = 0x80, //0b1000_0000
RIP_TABLE_CONTROL = 0x90, //0b1001_0000 - using the control frame to broadcast the RIP table
DISTANCE_SENSOR_TYPE = 0xA0, //0b1010_0000
SERVO_TYPE = 0xC0, //0b1100_0000
MISC_CONTROL_TYPE = 0xD0, //0b1101_0000
//Generic Frames
MISC_GENERIC_TYPE = 0x00, //0b0000_0000
MISC_UDP_GENERIC_TYPE = 0x10, // 0b0001_0000 - Same as MISC_GENERIC_TYPE except no ACK frames will be expected
SYSTEM_TYPE = 0x30, //0b0011_0000 - used for statuses, discovery, and other maintainence requests
ACK_TYPE = 0x60, //0b0110_0000 - ACK frames for Generic Fragments
RIP_TABLE_GENERIC = 0x70 //0b0111_0000 - using the generic frame to broadcast the RIP table (not used rn)
};
enum class FrameFlags : uint8_t {
ANY_FLAG = 0x0,
};
#pragma pack(push, 1) //these structs will be transmitted as is (ensure the structs are structured using 1B alignment - no padding)
typedef struct _control_frame{
uint8_t preamble; //Start of Frame
uint8_t sender_id; //sender board id
uint8_t receiver_id; //receiver board id
uint16_t seq_num; //sequence number to differentiate frames being sent from sender to receiver
uint8_t type_flag; //(type << 4) | flag - both are 4 bits
uint16_t data_len; //Data Length (max 256B)
uint8_t data[MAX_FRAME_SIZE]; //Variable Length of Data
uint16_t crc_16; //CRC-16
} ControlFrame; //this will have a max size of 9 + 256B = 265B
typedef struct _data_link_frame{
uint8_t preamble; //Start of Frame
uint8_t sender_id; //sender board id
uint8_t receiver_id; //receiver board id
uint16_t seq_num; //sequence number to differentiate frames being sent from sender to receiver
uint8_t type_flag; //(type << 4) | flag - both are 4 bits
uint16_t total_frag; //total number of fragments for this sequence
uint16_t frag_num; //current fragment number
uint16_t data_len; //Data Length (max 178B)
uint8_t data[MAX_FRAME_SIZE]; //Variable Length of Data
uint16_t crc_16; //CRC-16
} GenericFrame; //this will have a max size of 14 + 2^8 B = 270 B
#pragma pack(pop)
typedef struct _header{
uint8_t preamble; //Start of Frame
uint8_t sender_id; //sender board id
uint8_t receiver_id; //receiver board id
uint16_t seq_num; //sequence number to differentiate frames being sent from sender to receiver
uint8_t type_flag; //(type << 4) | flag - both are 4 bits
uint32_t frag_info; //(total_frag_num << 16) | frag_num - total_frag_num denotes the total number of fragmented frames to expect for this sequence number(?) and frag_num denotes the fragment frame num
uint16_t data_len; //Data Length (max 178B)
uint16_t crc_16; //CRC-16
} FrameHeader;
using Frame = std::variant<ControlFrame, GenericFrame>;
ControlFrame make_control_frame_from_header(const FrameHeader& header);
GenericFrame make_generic_frame_from_header(const FrameHeader& header);
typedef struct _fragment_metadata {
std::vector<GenericFrame> fragments;
uint16_t num_fragments_rx;
} FragmentMetadata;
/**
* @brief Entry in the receiver-side control-frame LFU lookup table
*/
typedef struct _control_frame_lut_entry {
uint32_t hash; // FNV-1a hash of the original payload (key)
std::vector<uint8_t> message; // Cached decoded payload (sans hash prefix)
FrameHeader header; // Cached frame header
uint32_t frequency; // Hit count used for LFU eviction
bool valid; // Is this slot populated?
} ControlFrameLutEntry;
typedef struct _receive_metadata{
std::unique_ptr<std::vector<uint8_t>> data;
uint16_t data_len;
FrameHeader header;
} Rx_Metadata;
#endif //DATA_LINK