mirror of
https://github.com/BotChain-Robots/firmware.git
synced 2026-07-08 17:47:21 +02:00
updates to topology with flatbuffers
This commit is contained in:
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
// Ensure the included flatbuffers.h is the same version as when this file was
|
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||||
// generated, otherwise it may not be compatible.
|
// generated, otherwise it may not be compatible.
|
||||||
static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
// static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||||
FLATBUFFERS_VERSION_MINOR == 12 &&
|
// FLATBUFFERS_VERSION_MINOR == 12 &&
|
||||||
FLATBUFFERS_VERSION_REVISION == 19,
|
// FLATBUFFERS_VERSION_REVISION == 19,
|
||||||
"Non-compatible flatbuffers version included");
|
// "Non-compatible flatbuffers version included");
|
||||||
|
|
||||||
namespace Movement {
|
namespace Movement {
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
// Ensure the included flatbuffers.h is the same version as when this file was
|
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||||
// generated, otherwise it may not be compatible.
|
// generated, otherwise it may not be compatible.
|
||||||
static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
// static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||||
FLATBUFFERS_VERSION_MINOR == 12 &&
|
// FLATBUFFERS_VERSION_MINOR == 12 &&
|
||||||
FLATBUFFERS_VERSION_REVISION == 19,
|
// FLATBUFFERS_VERSION_REVISION == 19,
|
||||||
"Non-compatible flatbuffers version included");
|
// "Non-compatible flatbuffers version included");
|
||||||
|
|
||||||
namespace Topology {
|
namespace Topology {
|
||||||
|
|
||||||
|
|||||||
@@ -17,70 +17,182 @@ TopologyManager::~TopologyManager(){
|
|||||||
nvs_close(handle);
|
nvs_close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// esp_err_t TopologyManager::add_board_to_topology(struct NeighbourBlob& blob){
|
/**
|
||||||
// if (!ready){
|
* @brief Creates a `Topology::NeighbourBlob` based on the input parameters and adds the blob to the internal topology map
|
||||||
// return ESP_ERR_INVALID_STATE;
|
*
|
||||||
// }
|
* @param connections This is a vector of pairs (uint8_t: `channel number`, uint16_t: `board_id`) representing the connection from the `curr_board_id` to `board_id` via `channel number`
|
||||||
|
* @param curr_board_id This is the board id, from its perspective, has the connections to the other boards in the vector `connections`
|
||||||
|
* @return esp_err_t
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Connections to fail:
|
||||||
|
*
|
||||||
|
* 1. Any of the `board_id` in the vector is `PC_ADDR` or `BROADCAST_ADDR` - Reserved addresses
|
||||||
|
*
|
||||||
|
* 2. Any of the `board_id` in the vector is `curr_board_id` - No loopback connections are allowed
|
||||||
|
*
|
||||||
|
* 3. Any of the `channel` in the vector is greater than or equal to `MAX_CHANNELS` - Channels are 0-indexed and there are at most 4 channels
|
||||||
|
*
|
||||||
|
* 4. All `board_id` is not unique in the vector - Should be a 1:1 connection between the boards
|
||||||
|
*/
|
||||||
|
esp_err_t TopologyManager::add_board_to_topology(std::vector<std::pair<uint8_t, uint16_t>>& connections, uint16_t curr_board_id){
|
||||||
|
if (!ready){
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
// if (blob.num_connections > MAX_CHANNELS || blob.curr_board_id == PC_ADDR || blob.curr_board_id == BROADCAST_ADDR){
|
if (connections.size() == 0 || connections.size() > MAX_CHANNELS){
|
||||||
// return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// for (uint8_t i = 0; i < blob.num_connections; i++){
|
if (curr_board_id == PC_ADDR || curr_board_id == BROADCAST_ADDR){
|
||||||
// ChannelBoardConn connection = blob.neighbour_connections[i];
|
return ESP_ERR_INVALID_ARG;
|
||||||
// if (connection.channel > MAX_CHANNELS || connection.board_id == PC_ADDR
|
}
|
||||||
// || connection == BROADCAST_ADDR || connection.board_id == blob.curr_board_id){
|
|
||||||
// return ESP_ERR_INVALID_ARG;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// topology[blob.curr_board_id] = blob;
|
//verify the connections in the vector
|
||||||
|
std::unordered_set<uint8_t> check_set;
|
||||||
|
|
||||||
|
std::vector<Topology::ChannelBoardConn> conns;
|
||||||
|
|
||||||
|
for (const std::pair<uint8_t, uint16_t>& pair : connections){
|
||||||
|
if (pair.second >= MAX_CHANNELS || pair.first == curr_board_id || pair.first == PC_ADDR
|
||||||
|
|| pair.first == BROADCAST_ADDR || check_set.find(pair.first) != check_set.end()){
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_set.insert(pair.first);
|
||||||
|
|
||||||
|
conns.push_back(builder.build_connections(pair.first, pair.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
topology[curr_board_id] = conns;
|
||||||
|
|
||||||
// return ESP_OK;
|
return ESP_OK;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// esp_err_t TopologyManager::remove_board_from_topology(uint16_t board_id){
|
esp_err_t TopologyManager::remove_board_from_topology(uint16_t board_id){
|
||||||
// if (!ready){
|
if (!ready){
|
||||||
// return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (topology.find(board_id) == topology.end()){
|
if (topology.find(board_id) == topology.end()){
|
||||||
// return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// topology.erase(board_id);
|
topology.erase(board_id);
|
||||||
|
|
||||||
// return ESP_OK;
|
return ESP_OK;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// esp_err_t TopologyManager::get_board_in_topology(struct NeighbourBlob& blob){
|
esp_err_t TopologyManager::get_board_in_topology(std::vector<std::pair<uint8_t, uint16_t>>& connections, uint16_t curr_board_id){
|
||||||
// if (!ready){
|
if (!ready){
|
||||||
// return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (topology.find(board_id) == topology.end()){
|
if (topology.find(curr_board_id) == topology.end()){
|
||||||
// return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// blob = topology.find(board_id);
|
std::vector<Topology::ChannelBoardConn> conn = topology[curr_board_id];
|
||||||
|
|
||||||
// return ESP_OK;
|
connections.clear();
|
||||||
// }
|
|
||||||
|
|
||||||
// esp_err_t TopologyManager::verify_topology(){
|
for (const Topology::ChannelBoardConn c : conn){
|
||||||
// if (!ready){
|
connections.push_back(std::pair<uint8_t, uint16_t>(c.channel(), c.board_id()));
|
||||||
// return ESP_ERR_INVALID_STATE;
|
}
|
||||||
// }
|
|
||||||
// return ESP_OK;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// esp_err_t TopologyManager::get_curr_topology(struct Topology& topology){
|
return ESP_OK;
|
||||||
// if (!ready){
|
}
|
||||||
// return ESP_ERR_INVALID_STATE;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return ESP_OK;
|
esp_err_t TopologyManager::verify_topology(){
|
||||||
// }
|
if (!ready){
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topology.size() == 0){
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditions to fail:
|
||||||
|
* 1. Any board that is referenced in the topology does not have a reciprocal connection (eg. A -> B and B -> A)
|
||||||
|
* 2. The topology contains 2 separate graphs (a board in the topology should be in the same graph with some sort of path to all other boards)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//condition 1
|
||||||
|
|
||||||
|
for (const auto& pair : topology){
|
||||||
|
for (const Topology::ChannelBoardConn& conn : pair.second){
|
||||||
|
if (topology.find(conn.board_id()) == topology.end()){
|
||||||
|
return ESP_ERR_INVALID_STATE; //could not find reciprocal board
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Topology::ChannelBoardConn> topology_board_conn = topology[conn.board_id()];
|
||||||
|
bool found = false;
|
||||||
|
for (const Topology::ChannelBoardConn& c : topology_board_conn){
|
||||||
|
if (c.board_id() == pair.first){
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found){
|
||||||
|
return ESP_ERR_INVALID_STATE; //reciprocal board does not have a connection back to `pair.first`
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//condition 2 - dfs
|
||||||
|
std::unordered_set<uint16_t> visited;
|
||||||
|
std::stack<uint16_t> backtrack;
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
backtrack.push(topology.begin()->first);
|
||||||
|
|
||||||
|
while (!backtrack.empty()){
|
||||||
|
uint16_t curr_node = backtrack.top();
|
||||||
|
backtrack.pop();
|
||||||
|
|
||||||
|
if (visited.find(curr_node) != visited.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
visited.insert(curr_node);
|
||||||
|
count++;
|
||||||
|
|
||||||
|
const std::vector<Topology::ChannelBoardConn>& conns = topology[curr_node];
|
||||||
|
|
||||||
|
for (const Topology::ChannelBoardConn& conn : conns) {
|
||||||
|
uint16_t next = conn.board_id();
|
||||||
|
if (visited.find(next) != visited.end()) {
|
||||||
|
backtrack.push(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != topology.size()){
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t TopologyManager::get_curr_topology(std::unordered_map<uint16_t, std::vector<std::pair<uint8_t, uint16_t>>>& topology){
|
||||||
|
if (!ready){
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
topology.clear();
|
||||||
|
|
||||||
|
for (const auto& [key, value] : this->topology){
|
||||||
|
topology[key] = std::vector<std::pair<uint8_t, uint16_t>>();
|
||||||
|
for (const Topology::ChannelBoardConn c : value){
|
||||||
|
topology[key].push_back(std::pair<uint8_t, uint16_t>(c.channel(), c.board_id()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// esp_err_t TopologyManager::write_nvs_topology(){
|
// esp_err_t TopologyManager::write_nvs_topology(){
|
||||||
// if (!ready){
|
// if (!ready){
|
||||||
|
|||||||
@@ -1,31 +1,36 @@
|
|||||||
#include "MovementManager.h"
|
#include "MovementManager.h"
|
||||||
|
|
||||||
|
#ifdef MOVEMENTS
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
// move these to constants header file?
|
// move these to constants header file?
|
||||||
#include "RMTManager.h"
|
#include "RMTManager.h"
|
||||||
#include "DataLinkManager.h"
|
#include "DataLinkManager.h"
|
||||||
#include "Frames.h"
|
#include "Frames.h"
|
||||||
|
#include "TopologyBuilder.h"
|
||||||
#ifdef MOVEMENTS
|
#include <vector>
|
||||||
#pragma once
|
#include <stack>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
class TopologyManager {
|
class TopologyManager {
|
||||||
public:
|
public:
|
||||||
TopologyManager();
|
TopologyManager();
|
||||||
~TopologyManager();
|
~TopologyManager();
|
||||||
// esp_err_t add_board_to_topology(struct NeighbourBlob& blob);
|
esp_err_t add_board_to_topology(std::vector<std::pair<uint8_t, uint16_t>>& connections, uint16_t curr_board_id);
|
||||||
// esp_err_t remove_board_from_topology(uint16_t board_id);
|
esp_err_t remove_board_from_topology(uint16_t board_id);
|
||||||
// esp_err_t get_board_in_topology(struct NeighbourBlob& blob);
|
esp_err_t get_board_in_topology(std::vector<std::pair<uint8_t, uint16_t>>& connections, uint16_t curr_board_id);
|
||||||
// esp_err_t verify_topology();
|
esp_err_t verify_topology();
|
||||||
// esp_err_t get_curr_topology(struct Topology& topology);
|
esp_err_t get_curr_topology(std::unordered_map<uint16_t, std::vector<std::pair<uint8_t, uint16_t>>>& topology);
|
||||||
// esp_err_t write_nvs_topology();
|
esp_err_t write_nvs_topology();
|
||||||
// esp_err_t get_nvs_topology(struct Topology& topology);
|
esp_err_t get_nvs_topology(std::unordered_map<uint16_t, std::vector<Topology::ChannelBoardConn>>& topology);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// std::unordered_map<uint16_t, struct NeighbourBlob> topology;
|
std::unordered_map<uint16_t, std::vector<Topology::ChannelBoardConn>> topology;
|
||||||
nvs_handle_t handle;
|
nvs_handle_t handle;
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
|
Flatbuffers::TopologyBuilder builder;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //MOVEMENTS
|
#endif //MOVEMENTS
|
||||||
@@ -12,6 +12,8 @@ To run the sample code, add the compiler variable `RMT_TEST=1` when compiling: `
|
|||||||
|
|
||||||
With `main_rmt_test.cpp`, flash one or more boards, ensuring that `BOARD_ID` are unique and `RECEIVER_BOARD_ID` is a board that exists and is connected on the same network.
|
With `main_rmt_test.cpp`, flash one or more boards, ensuring that `BOARD_ID` are unique and `RECEIVER_BOARD_ID` is a board that exists and is connected on the same network.
|
||||||
|
|
||||||
|
Please note that `SRC_BOARD` and `RECEIVER_BOARD` should be an 8 bit value (that is not 0x0 or 0xFF).
|
||||||
|
|
||||||
### Example Usage:
|
### Example Usage:
|
||||||
|
|
||||||
Board A: `idf.py -B ./build_A build -D SRC_BOARD=1 -D RECEIVER_BOARD=69 -D RMT_TEST=1 flash monitor -p COM3`
|
Board A: `idf.py -B ./build_A build -D SRC_BOARD=1 -D RECEIVER_BOARD=69 -D RMT_TEST=1 flash monitor -p COM3`
|
||||||
@@ -32,6 +34,14 @@ When monitoring both boards, you should see `Received message '%.*s' on channel
|
|||||||
|
|
||||||
The specific message being sent can vary depending on the setup (determined at compile time). Simply changing the `snprintf` on the `send_buf` and/or `FrameType` argument of `send()` will change the message/frames being sent (from the perspective of the user).
|
The specific message being sent can vary depending on the setup (determined at compile time). Simply changing the `snprintf` on the `send_buf` and/or `FrameType` argument of `send()` will change the message/frames being sent (from the perspective of the user).
|
||||||
|
|
||||||
|
# Preprogrammed Movements Sample Code
|
||||||
|
|
||||||
|
See `main_preprogrammed_test.cpp`.
|
||||||
|
|
||||||
|
To run the sample code, add the compiler variable `PP_MOVE=1` when compiling.
|
||||||
|
|
||||||
|
You can use the `SRC_BOARD` compiler variable to set a custom board id.
|
||||||
|
|
||||||
# cat
|
# cat
|
||||||
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⡷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⡷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if !defined(RMT_TEST) || (defined(RMT_TEST) && RMT_TEST == 0)
|
#if (!defined(RMT_TEST) || (defined(RMT_TEST) && RMT_TEST == 0)) && (!defined(PP_MOVE) || (defined(PP_MOVE) && PP_MOVE == 0))
|
||||||
// #include <cstdio>
|
// #include <cstdio>
|
||||||
// #include <memory>
|
// #include <memory>
|
||||||
|
|
||||||
|
|||||||
48
main/main_preprogrammed_test.cpp
Normal file
48
main/main_preprogrammed_test.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#if (defined(RMT_TEST) && RMT_TEST == 0) && (!defined(PP_MOVE) || (defined(PP_MOVE) && PP_MOVE == 1))
|
||||||
|
#include <cstdio>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_flash.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
#include "constants/datalink.h"
|
||||||
|
#include "TopologyManager.h"
|
||||||
|
|
||||||
|
#include <esp_netif.h>
|
||||||
|
#include <esp_event.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
#include "driver/gptimer.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#if !defined(SRC_BOARD)
|
||||||
|
const uint8_t BOARD_ID = 1;
|
||||||
|
#else
|
||||||
|
const uint8_t BOARD_ID = SRC_BOARD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" [[noreturn]] void app_main(void) {
|
||||||
|
esp_err_t ret = nvs_flash_init();
|
||||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
ret = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
|
esp_netif_init();
|
||||||
|
esp_event_loop_create_default();
|
||||||
|
|
||||||
|
printf("finished esp init\n");
|
||||||
|
|
||||||
|
printf("Hello world!\n");
|
||||||
|
|
||||||
|
TopologyManager obj = TopologyManager();
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
//do nothing
|
||||||
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#if defined(RMT_TEST) && RMT_TEST == 1
|
#if (defined(RMT_TEST) && RMT_TEST == 1) && (!defined(PP_MOVE) || (defined(PP_MOVE) && PP_MOVE == 0))
|
||||||
//Used for link layer testing (change name to main.cpp to use)
|
//Used for link layer testing (change name to main.cpp to use)
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|||||||
Reference in New Issue
Block a user