Fix RIP bugs, add in UART

This commit is contained in:
Johnathon Slightham
2026-03-31 14:26:37 -04:00
committed by Johnathon Slightham
parent d4602012f1
commit 548e8db484
26 changed files with 704 additions and 434 deletions

View File

@@ -1,4 +1,4 @@
idf_component_register(SRCS "DataLinkManager.cpp" "DataLinkRIP.cpp" "DataLinkScheduler.cpp" "DataLinkFrames.cpp"
PRIV_REQUIRES driver esp_event nvs_flash esp_netif rmt
PRIV_REQUIRES driver esp_event nvs_flash esp_netif rmt softUART
REQUIRES esp_timer ptrQueue
INCLUDE_DIRS "include")

View File

@@ -289,6 +289,15 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
return ESP_ERR_INVALID_RESPONSE;
}
// Preamble sanity check — if byte 0 is not START_OF_FRAME this buffer
// contains a merged frame, a partial capture, or line noise. Discard
// immediately rather than letting it propagate to the CRC checker.
if (data[0] != START_OF_FRAME){
ESP_LOGW(DEBUG_LINK_TAG, "Discarding frame on ch %d: bad preamble 0x%02X (expected 0x%02X)",
channel, data[0], START_OF_FRAME);
return ESP_ERR_INVALID_RESPONSE;
}
// ---- LUT fast-path for control frames ----
// Raw wire layout for control frames:
// [0] preamble
@@ -301,7 +310,8 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
// [12..] actual payload
// [-2..-1] CRC-16
bool is_control = IS_CONTROL_FRAME(data[5]);
if (is_control && recv_len >= (size_t)(CONTROL_FRAME_OVERHEAD + CONTROL_FRAME_HASH_SIZE)){
bool is_rip = (GET_TYPE(data[5]) == static_cast<uint8_t>(FrameType::RIP_TABLE_CONTROL));
if (is_control && !is_rip && recv_len >= (size_t)(CONTROL_FRAME_OVERHEAD + CONTROL_FRAME_HASH_SIZE)){
uint32_t peeked_hash = ((uint32_t)data[8] ) |
((uint32_t)data[9] << 8) |
((uint32_t)data[10] << 16) |
@@ -323,20 +333,36 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
// RIP control frames are handled internally replay them too
if (static_cast<FrameType>(GET_TYPE(cached_header.type_flag)) == FrameType::RIP_TABLE_CONTROL){
// Re-run the RIP update using the cached message
for (size_t i = 0; i < cached_message.size() - 1; i += 2){
uint8_t board_id = cached_message[i];
uint8_t hops = cached_message[i + 1];
RIPRow* entry = nullptr;
// Re-run the RIP update using the cached message (3-byte stride: board_id, hops, sum_of_hops)
for (size_t i = 0; i + 2 < cached_message.size(); i += RIP_WIRE_STRIDE){
uint8_t board_id = cached_message[i];
uint8_t hops = cached_message[i + 1];
uint8_t sum_of_hops = cached_message[i + 2];
// Skip routes about ourselves
if (board_id == this_board_id){
continue;
}
RIPRow* entry = nullptr;
if (rip_find_entry(board_id, &entry, true) != ESP_OK || entry == nullptr){
continue;
}
if (entry->valid == RIP_NEW_ROW){
rip_add_entry(board_id, hops + 1, channel, &entry);
rip_add_entry(board_id, hops + 1, sum_of_hops, channel, &entry);
} else {
rip_update_entry(hops + 1, channel, &entry);
rip_update_entry(hops + 1, sum_of_hops, channel, &entry);
}
}
// If this was a discovery request, send our routing table back
if (GET_FLAG(cached_header.type_flag) == FLAG_DISCOVERY){
esp_err_t disc_res = send_rip_frame(false, cached_header.sender_id);
if (disc_res != ESP_OK){
ESP_LOGE(DEBUG_LINK_TAG, "Failed to send back rip table to board %d (LUT path)", cached_header.sender_id);
}
}
return ESP_OK;
}
@@ -407,9 +433,8 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
return res;
}
// Control frame fully validated store in LUT for future replays
// Extract the hash that was embedded at data[8..11] (already validated in get_data_from_frame)
{
// Control frame fully validated store in LUT for future replays (skip RIP frames: their payload is dynamic)
if (!is_rip){
uint32_t validated_hash = ((uint32_t)data[8] ) |
((uint32_t)data[9] << 8) |
((uint32_t)data[10] << 16) |
@@ -424,10 +449,17 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
if (static_cast<FrameType>(GET_TYPE(header.type_flag)) == FrameType::RIP_TABLE_CONTROL){
ESP_LOGI(DEBUG_LINK_TAG, "Got a RIP frame from channel %d", channel);
for (size_t i = 0; i < message_size-1; i+=2){
uint8_t board_id = message->data()[i];
uint8_t hops = message->data()[i+1];
ESP_LOGI(DEBUG_LINK_TAG, "Received: board_id %d and number of hops %d on channel %d", board_id, hops, channel);
for (size_t i = 0; i + 2 < message_size; i += RIP_WIRE_STRIDE){
uint8_t board_id = message->data()[i];
uint8_t hops = message->data()[i + 1];
uint8_t sum_of_hops = message->data()[i + 2];
// Skip routes about ourselves - we already know we're 0 hops away from ourselves
if (board_id == this_board_id){
continue;
}
ESP_LOGI(DEBUG_LINK_TAG, "Received: board_id %d hops %d sum_of_hops %d on channel %d", board_id, hops, sum_of_hops, channel);
RIPRow* entry = nullptr;
@@ -443,15 +475,14 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
if (entry->valid == RIP_NEW_ROW){
//adding a new entry
rip_add_entry(board_id, hops + 1, channel, &entry);
rip_add_entry(board_id, hops + 1, sum_of_hops, channel, &entry);
} else {
//updating an entry
rip_update_entry(hops + 1, channel, &entry);
rip_update_entry(hops + 1, sum_of_hops, channel, &entry);
}
if (GET_FLAG(header.type_flag) == FLAG_DISCOVERY){
//discovery -> send routing table
// ESP_LOGI(DEBUG_LINK_TAG, "got discovery reply");
RIPRow_public row_queue = {
.info = entry->info,
.channel = entry->channel
@@ -461,7 +492,19 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
}
}
if (message_size == RIP_DISCOVERY_MESSAGE_SIZE){
// Print the finalized RIP table after processing all received rows
ESP_LOGI(DEBUG_LINK_TAG, "--- RIP Table (after update from channel %d) ---", channel);
for (size_t i = 0; i < RIP_MAX_ROUTES; i++){
RIPRow* row = nullptr;
if (rip_get_row(&row, i) == ESP_OK && row != nullptr){
ESP_LOGI(DEBUG_LINK_TAG, " [%d] board_id=%d hops=%d sum_of_hops=%d channel=%d ttl=%d",
i, row->info.board_id, row->info.hops, row->info.sum_of_hops, row->channel, row->ttl);
}
}
ESP_LOGI(DEBUG_LINK_TAG, "---------------------------------------------------");
if (GET_FLAG(header.type_flag) == FLAG_DISCOVERY){
res = send_rip_frame(false, header.sender_id);
if (res != ESP_OK){
ESP_LOGE(DEBUG_LINK_TAG, "Failed to send back rip table to board %d", header.sender_id);

View File

@@ -2,6 +2,7 @@
#include "BlockingQueue.h"
#include "Frames.h"
#include "RMTManager.h"
#include "SoftUARTManager.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <memory>
@@ -13,9 +14,15 @@
*
* @param board_id Board ID of the current board. Will be written to the NVM under key "board" if not already written.
*/
DataLinkManager::DataLinkManager(uint8_t board_id, uint8_t num_channels = MAX_CHANNELS){
DataLinkManager::DataLinkManager(uint8_t board_id, uint8_t num_channels, PhysicalLayerType phy_type){
//init table for this board and set up link layer priority queue
phys_comms = std::make_unique<RMTManager>(num_channels);
if (phy_type == PhysicalLayerType::SOFT_UART){
phys_comms = std::make_unique<SoftUARTManager>(num_channels);
ESP_LOGI(DEBUG_LINK_TAG, "Using SoftUART physical layer");
} else {
phys_comms = std::make_unique<RMTManager>(num_channels);
ESP_LOGI(DEBUG_LINK_TAG, "Using RMT physical layer");
}
if (phys_comms == nullptr){
ESP_LOGE(DEBUG_LINK_TAG, "RMT object was not created. Link layer communications will not function.");
return;

View File

@@ -27,6 +27,7 @@ void DataLinkManager::init_rip(){
rip_table[0].info = {
.board_id = this_board_id,
.hops = 0,
.sum_of_hops = 0,
};
rip_table[0].channel = MAX_CHANNELS + 1;
rip_table[0].ttl = RIP_TTL_START;
@@ -37,7 +38,7 @@ void DataLinkManager::init_rip(){
start_rip_tasks();
}
esp_err_t DataLinkManager::rip_add_entry(uint8_t board_id, uint8_t hops, uint8_t channel, RIPRow** entry){
esp_err_t DataLinkManager::rip_add_entry(uint8_t board_id, uint8_t hops, uint8_t sum_of_hops, uint8_t channel, RIPRow** entry){
if (entry == nullptr){
return ESP_FAIL;
}
@@ -49,16 +50,16 @@ esp_err_t DataLinkManager::rip_add_entry(uint8_t board_id, uint8_t hops, uint8_t
(*entry)->channel = channel;
(*entry)->info = {
.board_id = board_id,
.hops = hops
.hops = hops,
.sum_of_hops = sum_of_hops,
};
(*entry)->ttl = RIP_TTL_START;
(*entry)->valid = 1;
// ESP_LOGI(DEBUG_LINK_TAG, "board_id %d now has hops %d from channel %d", (*entry)->info.board_id, (*entry)->info.hops, channel);
xSemaphoreGive((*entry)->row_sem);
rip_update_self_sum_of_hops();
if (uxQueueMessagesWaiting(manual_broadcasts) == 0){
bool dummy = true;
xQueueSend(manual_broadcasts, &dummy, 0); //new row - send broadcast
@@ -67,7 +68,32 @@ esp_err_t DataLinkManager::rip_add_entry(uint8_t board_id, uint8_t hops, uint8_t
return ESP_OK;
}
/**
* @brief Recomputes and stores this board's own sum_of_hops (centrality score).
* Called whenever the routing table changes. No semaphores are held on entry.
*/
void DataLinkManager::rip_update_self_sum_of_hops(){
uint32_t total = 0;
for (size_t i = 1; i < RIP_MAX_ROUTES; i++){
if (xSemaphoreTake(rip_table[i].row_sem, pdMS_TO_TICKS(RIP_MAX_SEM_WAIT_MS)) != pdTRUE){
continue;
}
if (rip_table[i].valid == RIP_VALID_ROW && rip_table[i].info.hops <= RIP_MAX_HOPS){
total += rip_table[i].info.hops;
}
xSemaphoreGive(rip_table[i].row_sem);
}
// Clamp to uint8_t max — with RIP_MAX_ROUTES=10 and RIP_MAX_HOPS=15 the max is 9*15=135, fits fine.
if (xSemaphoreTake(rip_table[0].row_sem, pdMS_TO_TICKS(RIP_MAX_SEM_WAIT_MS)) == pdTRUE){
rip_table[0].info.sum_of_hops = (total > 255) ? 255 : static_cast<uint8_t>(total);
xSemaphoreGive(rip_table[0].row_sem);
}
}
esp_err_t DataLinkManager::rip_reset_entry_ttl(uint8_t board_id){
// ...existing code...
RIPRow* entry = nullptr;
esp_err_t res;
@@ -92,7 +118,7 @@ esp_err_t DataLinkManager::rip_reset_entry_ttl(uint8_t board_id){
return ESP_OK;
}
esp_err_t DataLinkManager::rip_update_entry(uint8_t new_hop, uint8_t channel, RIPRow** entry){
esp_err_t DataLinkManager::rip_update_entry(uint8_t new_hop, uint8_t new_sum_of_hops, uint8_t channel, RIPRow** entry){
if (entry == nullptr){
return ESP_FAIL; //board doesn't exist
}
@@ -102,22 +128,33 @@ esp_err_t DataLinkManager::rip_update_entry(uint8_t new_hop, uint8_t channel, RI
}
uint8_t old_hops = (*entry)->info.hops;
uint8_t old_sum_of_hops = (*entry)->info.sum_of_hops;
bool hops_improved = (new_hop < (*entry)->info.hops) || ((*entry)->info.hops == RIP_MAX_HOPS + 1);
if ((*entry)->info.hops >= new_hop && (*entry)->info.hops != RIP_MAX_HOPS + 1){ //no count to infinity if path is invalid
if (hops_improved){ //accept better paths and allow recovery from infinity
(*entry)->info.hops = new_hop;
(*entry)->info.sum_of_hops = new_sum_of_hops;
(*entry)->channel = channel;
// ESP_LOGI(DEBUG_LINK_TAG, "updated board_id %d now has hops %d from channel %d", (*entry)->info.board_id, (*entry)->info.hops, channel);
} else {
// Even if hops didn't improve, update the centrality score if it came from the same channel
if ((*entry)->channel == channel){
(*entry)->info.sum_of_hops = new_sum_of_hops;
}
}
(*entry)->ttl = RIP_TTL_START;
(*entry)->valid = 1;
// ESP_LOGI(DEBUG_LINK_TAG, "refreshed board_id %d ttl", (*entry)->info.board_id);
bool sum_of_hops_changed = (old_sum_of_hops != (*entry)->info.sum_of_hops);
xSemaphoreGive((*entry)->row_sem);
if (uxQueueMessagesWaiting(manual_broadcasts) == 0 && old_hops > new_hop && old_hops != RIP_MAX_HOPS + 1){
//if hops were changed, send broadcast (if there isn't already one manual broadcast request pending)
if (hops_improved || sum_of_hops_changed){
rip_update_self_sum_of_hops();
}
if (uxQueueMessagesWaiting(manual_broadcasts) == 0 && (old_hops > new_hop || old_hops == RIP_MAX_HOPS + 1 || sum_of_hops_changed)){
//if hops were changed (or recovered from infinity), or sum_of_hops changed, send broadcast
bool dummy = true;
xQueueSend(manual_broadcasts, &dummy, 0);
}
@@ -139,7 +176,7 @@ esp_err_t DataLinkManager::rip_find_entry(uint8_t board_id, RIPRow** entry, bool
if (xSemaphoreTake(rip_table[i].row_sem, pdMS_TO_TICKS(RIP_MAX_SEM_WAIT_MS)) != pdTRUE){
return ESP_FAIL;
}
if (rip_table[i].valid == RIP_VALID_ROW && rip_table[i].info.board_id == board_id){
if ((rip_table[i].valid == RIP_VALID_ROW || rip_table[i].valid == RIP_NEW_ROW) && rip_table[i].info.board_id == board_id){
*entry = &rip_table[i];
xSemaphoreGive(rip_table[i].row_sem);
// ESP_LOGI(DEBUG_LINK_TAG, "Found %d in table at row %d", board_id, i);
@@ -198,14 +235,11 @@ esp_err_t DataLinkManager::rip_get_row(RIPRow** entry, uint8_t row_num){
return ESP_ERR_INVALID_STATE;
}
if (rip_table[row_num].info.hops == RIP_MAX_HOPS + 1){
//invalid hop, decrement counter
rip_table[row_num].ttl_flush--;
if (rip_table[row_num].ttl_flush == 0){
rip_table[row_num].valid = RIP_INVALID_ROW;
xSemaphoreGive(rip_table[row_num].row_sem);
return ESP_FAIL;
}
if (rip_table[row_num].info.hops == RIP_MAX_HOPS + 1 && rip_table[row_num].ttl_flush == 0){
//flush countdown has expired, invalidate the row
rip_table[row_num].valid = RIP_INVALID_ROW;
xSemaphoreGive(rip_table[row_num].row_sem);
return ESP_FAIL;
}
static RIPRow row_snapshots[RIP_MAX_ROUTES];
@@ -228,8 +262,7 @@ esp_err_t DataLinkManager::rip_get_row(RIPRow** entry, uint8_t row_num){
* @return esp_err_t
*/
esp_err_t DataLinkManager::send_rip_frame(bool broadcast, uint8_t dest_id){
//use the control frame for the demo (as the number of rows increase, we will need to use the generic frame)
//data will be [board_id (1), hops (1), board_id (2), hops (2), ...]
// Wire format: [board_id (1), hops (1), sum_of_hops (1), ...] (RIP_WIRE_STRIDE bytes per entry)
uint16_t message_idx = 0;
esp_err_t res;
@@ -240,7 +273,7 @@ esp_err_t DataLinkManager::send_rip_frame(bool broadcast, uint8_t dest_id){
if(broadcast){
for (size_t channel = 0; channel < num_channels; channel++){
auto rip_message = std::make_unique<std::vector<uint8_t>>();
rip_message->resize(RIP_MAX_ROUTES * 2);
rip_message->resize(RIP_MAX_ROUTES * RIP_WIRE_STRIDE);
for (size_t i = 0; i < RIP_MAX_ROUTES; i++){
res = rip_get_row(&entry, i);
@@ -253,15 +286,15 @@ esp_err_t DataLinkManager::send_rip_frame(bool broadcast, uint8_t dest_id){
continue;
}
// ESP_LOGI(DEBUG_LINK_TAG, "Found entry for board %d with hops %d", entry->info.board_id, entry->info.hops);
if (entry->channel == channel){
//poisoned reverse
rip_message->at(message_idx++) = entry->info.board_id;
rip_message->at(message_idx++) = RIP_MAX_HOPS + 1;
rip_message->at(message_idx++) = entry->info.sum_of_hops;
} else {
rip_message->at(message_idx++) = entry->info.board_id;
rip_message->at(message_idx++) = entry->info.hops;
rip_message->at(message_idx++) = entry->info.sum_of_hops;
}
}
@@ -299,7 +332,7 @@ esp_err_t DataLinkManager::send_rip_frame(bool broadcast, uint8_t dest_id){
}
} else {
auto rip_message = std::make_unique<std::vector<uint8_t>>();
rip_message->resize(RIP_MAX_ROUTES * 2);
rip_message->resize(RIP_MAX_ROUTES * RIP_WIRE_STRIDE);
for (size_t i = 0; i < RIP_MAX_ROUTES; i++){
res = rip_get_row(&entry, i);
@@ -313,6 +346,7 @@ esp_err_t DataLinkManager::send_rip_frame(bool broadcast, uint8_t dest_id){
}
rip_message->data()[message_idx++] = entry->info.board_id;
rip_message->data()[message_idx++] = entry->info.hops;
rip_message->data()[message_idx++] = entry->info.sum_of_hops;
}
ESP_LOGI(DEBUG_LINK_TAG, "replying to discovery request to board %d", dest_id);
res = send(dest_id, std::move(rip_message), FrameType::RIP_TABLE_CONTROL, FLAG_DISCOVERY);
@@ -382,7 +416,7 @@ esp_err_t DataLinkManager::get_routing_table(RIPRow_public* table, size_t* table
return ESP_FAIL;
}
if (rip_table[i].valid == RIP_VALID_ROW){
table[i].info = rip_table[i].info;
table[i].info = rip_table[i].info; // copies board_id, hops, and sum_of_hops
table[i].channel = rip_table[i].channel;
curr_size++;
}
@@ -439,15 +473,20 @@ esp_err_t DataLinkManager::get_routing_table(RIPRow_public* table, size_t* table
continue;
}
if (link_layer_obj->rip_table[i].ttl != 0){
// link_layer_obj->rip_table[i].valid = RIP_INVALID_ROW;
// ESP_LOGI(DEBUG_LINK_TAG, "Entry %d now has ttl %d", i, link_layer_obj->rip_table[i].ttl);
// } else {
link_layer_obj->rip_table[i].ttl--;
if (link_layer_obj->rip_table[i].ttl == 0){
link_layer_obj->rip_table[i].info.hops = RIP_MAX_HOPS + 1;
link_layer_obj->rip_table[i].ttl_flush = RIP_FLUSH_COUNT;
broadcast = true;
}
} else if (link_layer_obj->rip_table[i].info.hops == RIP_MAX_HOPS + 1){
// TTL already zero and route is poisoned — count down the flush timer
if (link_layer_obj->rip_table[i].ttl_flush > 0){
link_layer_obj->rip_table[i].ttl_flush--;
}
if (link_layer_obj->rip_table[i].ttl_flush == 0){
link_layer_obj->rip_table[i].valid = RIP_INVALID_ROW;
}
}
xSemaphoreGive(link_layer_obj->rip_table[i].row_sem);

View File

@@ -275,15 +275,11 @@ esp_err_t DataLinkManager::scheduler_send(uint8_t channel){
esp_err_t DataLinkManager::scheduler_send_rmt(uint8_t channel, SchedulerMetadata frame, uint8_t* send_data, size_t frame_size, bool wait_for_tx_done){
esp_err_t res;
uint8_t channel_to_route = MAX_CHANNELS;
rmt_transmit_config_t config = {
.loop_count = 0,
.flags = {
.eot_level = 0, // typically 0 or 1, depending on your output idle level
}
};
// config is physical-layer specific; each IPhysicalLayer implementation
// uses its own internal configuration set at init time, so nullptr is fine.
if (frame.header.receiver_id == BROADCAST_ADDR){
// printf("Sending on channel %d\n", i);
res = phys_comms->send(send_data, frame_size, &config, channel);
res = phys_comms->send(send_data, frame_size, nullptr, channel);
} else {
res = route_frame(frame.header.receiver_id, &channel_to_route);
@@ -291,18 +287,12 @@ esp_err_t DataLinkManager::scheduler_send_rmt(uint8_t channel, SchedulerMetadata
ESP_LOGE(DEBUG_LINK_TAG, "Failed to find entry for %d", frame.header.receiver_id);
return ESP_FAIL;
}
// ESP_LOGI(DEBUG_LINK_TAG, "Sending frame %d on channel %d to board %d frag_info 0x%X", frame.header.seq_num, channel, frame.header.receiver_id, frame.header.frag_info);
res = phys_comms->send(send_data, frame_size, &config, channel_to_route);
// if (wait_for_tx_done){
// phys_comms->wait_until_send_complete(channel_to_route);
// }
res = phys_comms->send(send_data, frame_size, nullptr, channel_to_route);
}
if (res != ESP_OK){
ESP_LOGE(DEBUG_LINK_TAG, "Failed to send message");
return ESP_FAIL;
} else{
// ESP_LOGI(DEBUG_LINK_TAG, "Sent frame %d frag_info 0x%X", frame.header.seq_num, frame.header.frag_info);
}
return ESP_OK;

View File

@@ -10,12 +10,20 @@
#include "freertos/semphr.h"
#include "Frames.h"
#include "Tables.h"
#include "RMTManager.h"
#include "IPhysicalLayer.h"
#include "BlockingQueue.h"
#include "BlockingPriorityQueue.h"
#include <unordered_map>
#include "Scheduler.h"
/**
* @brief Selects which physical layer implementation to instantiate.
*/
enum class PhysicalLayerType : uint8_t {
RMT = 0, ///< Use the RMT-based Manchester-encoded physical layer (default)
SOFT_UART = 1, ///< Use the software-UART physical layer
};
#define DEBUG_LINK_TAG "LinkLayer"
#define CRC_POLYNOMIAL 0x1021
@@ -56,7 +64,7 @@ static const uint16_t crc16_table[256] = {
*/
class DataLinkManager{
public:
DataLinkManager(uint8_t board_id, uint8_t num_channels);
DataLinkManager(uint8_t board_id, uint8_t num_channels, PhysicalLayerType phy_type = PhysicalLayerType::SOFT_UART);
~DataLinkManager();
esp_err_t send(uint8_t dest_board, std::unique_ptr<std::vector<uint8_t>>&& buffer, FrameType type, uint8_t flag);
esp_err_t start_receive_frames(uint8_t curr_channel);
@@ -69,7 +77,7 @@ class DataLinkManager{
private:
uint8_t this_board_id = 0;
uint8_t num_channels = MAX_CHANNELS;
std::unique_ptr<RMTManager> phys_comms;
std::unique_ptr<IPhysicalLayer> phys_comms;
std::unordered_map<uint8_t, uint16_t> sequence_num_map;
SemaphoreHandle_t sequence_num_map_mutex;
@@ -93,10 +101,11 @@ class DataLinkManager{
void init_rip();
esp_err_t rip_find_entry(uint8_t board_id, RIPRow** entry, bool reserve_row);
esp_err_t rip_update_entry(uint8_t new_hop, uint8_t channel, RIPRow** entry);
esp_err_t rip_add_entry(uint8_t board_id, uint8_t hops, uint8_t channel, RIPRow** entry);
esp_err_t rip_update_entry(uint8_t new_hop, uint8_t new_sum_of_hops, uint8_t channel, RIPRow** entry);
esp_err_t rip_add_entry(uint8_t board_id, uint8_t hops, uint8_t sum_of_hops, uint8_t channel, RIPRow** entry);
esp_err_t rip_reset_entry_ttl(uint8_t board_id);
esp_err_t rip_get_row(RIPRow** entry, uint8_t row_num);
void rip_update_self_sum_of_hops();
//this is stored locally with metadata `ttl`
// std::unordered_map<uint8_t, RIPRow> rip_table; //using a hash map to store the routes to other boards - will be used as we scale up

View File

@@ -7,7 +7,7 @@
#define RIP_INVALID_ROW 0
#define RIP_VALID_ROW 1
#define RIP_NEW_ROW 2
#define RIP_BROADCAST_INTERVAL 30000 //broadcast every 30 seconds (30000ms)
#define RIP_BROADCAST_INTERVAL 15000 //broadcast every 30 seconds (15000ms)
// #define RIP_BROADCAST_INTERVAL 3000 //temp broadcast every 3 seconds (3000ms)
#define RIP_TTL_START 180 //seconds
#define RIP_MS_TO_SEC 1000 //1000 ms to 1 sec
@@ -15,13 +15,15 @@
#define RIP_FLUSH_COUNT 8 //flush after 8*30 seconds = 240 seconds
#define RIP_DISCOVERY_MESSAGE_SIZE 1
#define RIP_WIRE_STRIDE 3 // bytes per entry on the wire: board_id, hops, sum_of_hops
/**
* @brief Routing data to a board
* This struct will be sent to other boards
*/
typedef struct _rip_hops{
uint8_t board_id; //ID of the destination
uint8_t hops; //hop count to `board_id`
uint8_t board_id; //ID of the destination
uint8_t hops; //hop count to `board_id`
uint8_t sum_of_hops; //sum of hops from `board_id` to all other known boards (centrality score)
} RIPHop;
typedef struct _rip_row{
@@ -36,7 +38,7 @@ typedef struct _rip_row{
/**
* @brief Public facing RIP table row
*
*
*/
typedef struct _rip_public_row{
RIPHop info;