mirror of
https://github.com/BotChain-Robots/firmware.git
synced 2026-07-08 09:37:21 +02:00
Add a cache to data link layer for control frames with hash
This commit is contained in:
@@ -281,6 +281,74 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
}
|
||||
|
||||
// ---- LUT fast-path for control frames ----
|
||||
// Raw wire layout for control frames:
|
||||
// [0] preamble
|
||||
// [1] sender_id
|
||||
// [2] receiver_id
|
||||
// [3..4] seq_num (LE)
|
||||
// [5] type_flag
|
||||
// [6..7] wire_data_len (LE) -- includes CONTROL_FRAME_HASH_SIZE
|
||||
// [8..11] 4-byte FNV-1a hash (LE)
|
||||
// [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)){
|
||||
uint32_t peeked_hash = ((uint32_t)data[8] ) |
|
||||
((uint32_t)data[9] << 8) |
|
||||
((uint32_t)data[10] << 16) |
|
||||
((uint32_t)data[11] << 24);
|
||||
|
||||
std::vector<uint8_t> cached_message;
|
||||
FrameHeader cached_header;
|
||||
|
||||
if (lut_lookup(peeked_hash, cached_message, cached_header)){
|
||||
// Cache hit: replay the previously validated payload directly onto the receive queue.
|
||||
// Skip CRC checking, hash verification, data-length checks, and full parsing.
|
||||
|
||||
auto message = std::make_unique<std::vector<uint8_t>>(cached_message);
|
||||
|
||||
// Update per-frame dynamic fields from the raw bytes (sender/receiver/seq differ per transmission)
|
||||
cached_header.sender_id = data[1];
|
||||
cached_header.receiver_id = data[2];
|
||||
cached_header.seq_num = (uint16_t)data[3] | ((uint16_t)data[4] << 8);
|
||||
|
||||
// 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;
|
||||
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);
|
||||
} else {
|
||||
rip_update_entry(hops + 1, channel, &entry);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Data is already validated – enqueue directly, no further checks needed.
|
||||
Rx_Metadata metadata = {
|
||||
.data = std::move(message),
|
||||
.data_len = (uint16_t)cached_message.size(),
|
||||
.header = cached_header
|
||||
};
|
||||
|
||||
if (!async_receive_queue->enqueue(std::move(metadata), std::chrono::milliseconds(ASYNC_QUEUE_WAIT_TICKS))){
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
// Cache miss – fall through to full validation below
|
||||
// ESP_LOGI("TMP", "Control frame LUT cache MISS - hash=0x%08lX", peeked_hash);
|
||||
}
|
||||
// ---- end LUT fast-path ----
|
||||
|
||||
auto message = std::make_unique<std::vector<uint8_t>>();
|
||||
message->resize(MAX_FRAME_SIZE);
|
||||
|
||||
@@ -314,12 +382,6 @@ esp_err_t DataLinkManager::receive_rmt(uint8_t channel){
|
||||
|
||||
res = inc_head_sliding_window(channel, header.sender_id, record.seq_num, &record);
|
||||
|
||||
// if (res == ESP_OK){
|
||||
// ESP_LOGI(DEBUG_LINK_TAG, "Got ACK for seq number %d from board %d! Highest Conseq ACK: 0x%X%X Total Frag: 0x%X%X", record.seq_num, header.sender_id, message[1], message[2], message[3], message[4]);
|
||||
// } else {
|
||||
// ESP_LOGI(DEBUG_LINK_TAG, "Got ACK for seq number %d from board %d but got a lower conseq ack 0x%x%X Total Frag: 0x%X%X", record.seq_num, header.sender_id, message[1], message[2], message[3], message[4]);
|
||||
// }
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -335,6 +397,16 @@ 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)
|
||||
{
|
||||
uint32_t validated_hash = ((uint32_t)data[8] ) |
|
||||
((uint32_t)data[9] << 8) |
|
||||
((uint32_t)data[10] << 16) |
|
||||
((uint32_t)data[11] << 24);
|
||||
lut_insert(validated_hash, message->data(), message_size, header);
|
||||
}
|
||||
|
||||
//control frame handling: - TODO: clean up :)
|
||||
// ESP_LOGI(DEBUG_LINK_TAG, "Received frame of type 0x%X destined for board %d", GET_TYPE(header.type_flag), header.receiver_id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user