mirror of
https://github.com/BotChain-Robots/firmware.git
synced 2026-07-08 17:47:21 +02:00
movement set read write to nvs working
This commit is contained in:
@@ -3,6 +3,7 @@ idf_component_register(SRCS "MPIMessageBuilder.cpp"
|
||||
"TopologyMessageBuilder.cpp"
|
||||
"SensorMessageBuilder.cpp"
|
||||
"TopologyBuilder.cpp"
|
||||
"MovementSetBuilder.cpp"
|
||||
REQUIRES "constants"
|
||||
INCLUDE_DIRS "include"
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifdef MOVEMENTSETBUILDER
|
||||
|
||||
namespace Flatbuffers {
|
||||
SerializedMessage MovementSetBuilder::build_movement_set(const std::unordered_map<uint8_t, std::vector<MovementEntryInput>>& input){
|
||||
SerializedMessage MovementSetBuilder::build_movement_set(const std::unordered_map<uint8_t, std::vector<MovementEntryData>>& input){
|
||||
builder_.Clear();
|
||||
|
||||
std::vector<flatbuffers::Offset<Movement::MovementVector>> map_entries;
|
||||
@@ -17,50 +17,50 @@ namespace Flatbuffers {
|
||||
keys.reserve(input.size());
|
||||
|
||||
for (const auto& [key, _] : input) {
|
||||
keys.push_back(key);
|
||||
keys.push_back(key);
|
||||
}
|
||||
|
||||
std::sort(keys.begin(), keys.end());
|
||||
|
||||
// 2. Build MovementVector entries in key order
|
||||
for (uint8_t key : keys) {
|
||||
const auto& entries = input.at(key);
|
||||
const auto& entries = input.at(key);
|
||||
|
||||
std::vector<flatbuffers::Offset<Movement::MovementEntry>> fb_entries;
|
||||
fb_entries.reserve(entries.size());
|
||||
std::vector<flatbuffers::Offset<Movement::MovementEntry>> fb_entries;
|
||||
fb_entries.reserve(entries.size());
|
||||
|
||||
for (const auto& e : entries) {
|
||||
fb_entries.push_back(
|
||||
Movement::CreateMovementEntry(
|
||||
for (const auto& e : entries) {
|
||||
fb_entries.push_back(
|
||||
Movement::CreateMovementEntry(
|
||||
builder_,
|
||||
e.board_id,
|
||||
e.module_type,
|
||||
e.value_action,
|
||||
&e.condition,
|
||||
e.ack,
|
||||
e.ack_ttl_ms,
|
||||
e.post_delay_ms
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
auto movements_vector = builder_.CreateVector(fb_entries);
|
||||
|
||||
map_entries.push_back(
|
||||
Movement::CreateMovementVector(
|
||||
builder_,
|
||||
e.board_id,
|
||||
e.module_type,
|
||||
e.value_action,
|
||||
&e.condition,
|
||||
e.ack,
|
||||
e.ack_ttl_ms,
|
||||
e.post_delay_ms
|
||||
key,
|
||||
movements_vector
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
auto movements_vector = builder_.CreateVector(fb_entries);
|
||||
|
||||
map_entries.push_back(
|
||||
Movement::CreateMovementVector(
|
||||
builder_,
|
||||
key,
|
||||
movements_vector
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Build the map vector
|
||||
auto map_vector = builder_.CreateVector(map_entries);
|
||||
|
||||
auto message = Movement::CreateMovementSet(
|
||||
builder_,
|
||||
map_vector
|
||||
builder_,
|
||||
map_vector
|
||||
);
|
||||
|
||||
builder_.Finish(message);
|
||||
|
||||
@@ -11,22 +11,36 @@
|
||||
#include "flatbuffers_generated/Movement_generated.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
struct MovementEntryInput {
|
||||
struct MovementEntryData {
|
||||
uint16_t board_id;
|
||||
uint8_t module_type;
|
||||
uint16_t value_action;
|
||||
Movement::ConditionBlob condition;
|
||||
Movement::ConditionBlob condition; // struct is fine to reuse
|
||||
uint8_t ack;
|
||||
uint16_t ack_ttl_ms;
|
||||
uint16_t post_delay_ms;
|
||||
|
||||
bool operator==(const MovementEntryData& other) const {
|
||||
return board_id == other.board_id &&
|
||||
module_type == other.module_type &&
|
||||
value_action == other.value_action &&
|
||||
condition.value() == other.condition.value() &&
|
||||
condition.cond() == other.condition.cond() &&
|
||||
condition.module_type() == other.condition.module_type() &&
|
||||
condition.in_use() == other.condition.in_use() &&
|
||||
ack == other.ack &&
|
||||
ack_ttl_ms == other.ack_ttl_ms &&
|
||||
post_delay_ms == other.post_delay_ms;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace Flatbuffers {
|
||||
class MovementSetBuilder {
|
||||
public:
|
||||
MovementSetBuilder() : builder_(MAX_MOVEMENTS_IN_SET*sizeof(Movement::MovementEntry)) {}
|
||||
|
||||
SerializedMessage build_movement_set(const std::unordered_map<uint8_t, std::vector<MovementEntryInput>>& input);
|
||||
SerializedMessage build_movement_set(const std::unordered_map<uint8_t, std::vector<MovementEntryData>>& input);
|
||||
Movement::ConditionBlob build_condition_blob(uint16_t value, uint8_t cond, uint8_t module_type, uint8_t in_use);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS "MovementManager.cpp" "MovementManager.cpp" "TopologyManager.cpp"
|
||||
idf_component_register(SRCS "MovementManager.cpp" "MovementSetManager.cpp" "TopologyManager.cpp"
|
||||
PRIV_REQUIRES esp_event nvs_flash rmt dataLink flatbuffers
|
||||
# REQUIRES esp_timer
|
||||
INCLUDE_DIRS "include")
|
||||
|
||||
@@ -10,11 +10,6 @@ MovementSetManager::MovementSetManager(){
|
||||
return;
|
||||
}
|
||||
|
||||
if (!topology_manager->is_ready()){
|
||||
ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Topology Manager is not ready!");
|
||||
return;
|
||||
}
|
||||
|
||||
ready = true;
|
||||
};
|
||||
|
||||
@@ -22,28 +17,51 @@ MovementSetManager::~MovementSetManager(){
|
||||
nvs_close(handle);
|
||||
}
|
||||
|
||||
esp_err_t MovementSetManager::add_movement(Movement::MovementEntry& entry, uint8_t& index){
|
||||
/**
|
||||
* @brief Adds a movement entry into the movements map
|
||||
*
|
||||
* @param entry Movement entry information
|
||||
* @param index Sequence number of the movements
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t MovementSetManager::add_movement(MovementEntryData& entry, uint8_t index){
|
||||
if (!ready){
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (entry.board_id() == PC_ADDR || entry.board_id() == BROADCAST_ADDR){
|
||||
if (entry.board_id == PC_ADDR || entry.board_id == BROADCAST_ADDR){
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (movements.find(index) != movements.end()){
|
||||
for (Movement::MovementEntry& e : movements[index]){
|
||||
if (e.board_id() == entry.board_id()){
|
||||
for (MovementEntryData& e : movements[index]){
|
||||
if (e.board_id == entry.board_id){
|
||||
return ESP_ERR_INVALID_ARG; //only unique board ids per index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.post_delay_ms == 0){
|
||||
//we don't want 0ms delay in between the movements, so we will add the default delay
|
||||
entry.post_delay_ms = DEFAULT_DELAY_MS;
|
||||
}
|
||||
|
||||
if (entry.ack != static_cast<uint8_t>(ACK_VALUES::NO_ACK) && entry.ack_ttl_ms == 0){
|
||||
entry.ack_ttl_ms = DEFAULT_ACK_TTL_MS;
|
||||
}
|
||||
|
||||
movements[index].push_back(entry);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes a movement entry from the sequence, given the board id
|
||||
*
|
||||
* @param index Sequence number
|
||||
* @param board_id
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t MovementSetManager::remove_movement(uint8_t index, uint8_t board_id){
|
||||
if (board_id == PC_ADDR || board_id == BROADCAST_ADDR){
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -53,10 +71,14 @@ esp_err_t MovementSetManager::remove_movement(uint8_t index, uint8_t board_id){
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!ready){
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto it = movements[index].begin(); it != movements[index].end(); ++it) {
|
||||
if (it->board_id() == board_id){
|
||||
if (it->board_id == board_id){
|
||||
movements[index].erase(it);
|
||||
found = true;
|
||||
break;
|
||||
@@ -70,23 +92,116 @@ esp_err_t MovementSetManager::remove_movement(uint8_t index, uint8_t board_id){
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t MovementSetManager::update_movement(Movement::MovementEntry& entry, uint8_t index){
|
||||
esp_err_t MovementSetManager::get_curr_movement_set(std::unordered_map<uint8_t, std::vector<MovementEntryData>>& set){
|
||||
if (!ready){
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
set = movements;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t MovementSetManager::get_curr_movement_set(Movement::MovementSet& set){
|
||||
return ESP_OK;
|
||||
}
|
||||
esp_err_t MovementSetManager::get_nvs_movement_set(std::unordered_map<uint8_t, std::vector<MovementEntryData>>& set){
|
||||
if (!ready){
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t MovementSetManager::verify_movement_set(){
|
||||
return ESP_OK;
|
||||
}
|
||||
size_t size = 0;
|
||||
esp_err_t res = nvs_get_u32(handle, MOVEMENTS_NVS_SET_SIZE_KEY, reinterpret_cast<uint32_t*>(&size));
|
||||
|
||||
esp_err_t MovementSetManager::get_nvs_movement_set(Movement::MovementSet& set){
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to read data size");
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> buffer(size);
|
||||
|
||||
res = nvs_get_blob(handle, MOVEMENTS_NVS_SET_KEY, buffer.data(), &size);
|
||||
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to read blob");
|
||||
return res;
|
||||
}
|
||||
|
||||
// Verify the FlatBuffer
|
||||
flatbuffers::Verifier verifier(buffer.data(), buffer.size());
|
||||
if (!Movement::VerifyMovementSetBuffer(verifier)) {
|
||||
ESP_LOGE(MOVEMENTS_DEBUG_TAG, "FlatBuffer verification failed");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Parse root
|
||||
const Movement::MovementSet* movement_set = Movement::GetMovementSet(buffer.data());
|
||||
|
||||
movements.clear();
|
||||
|
||||
const auto* map = movement_set->movement_map();
|
||||
if (!map) {
|
||||
return ESP_OK; // empty set
|
||||
}
|
||||
|
||||
// Iterate map entries
|
||||
for (const Movement::MovementVector* mv : *map) {
|
||||
uint8_t key = mv->key();
|
||||
|
||||
auto& vec = movements[key];
|
||||
vec.clear();
|
||||
|
||||
const auto* entries = mv->movements();
|
||||
if (!entries) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec.reserve(entries->size());
|
||||
|
||||
// Must iterate over Movement::MovementEntry* (FlatBuffers table)
|
||||
for (const Movement::MovementEntry* e : *entries) {
|
||||
vec.push_back({
|
||||
e->board_id(),
|
||||
e->module_type(),
|
||||
e->value_action(),
|
||||
*e->condition(), // copy struct
|
||||
e->ack(),
|
||||
e->ack_ttl_ms(),
|
||||
e->post_delay_ms()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
set = movements;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t MovementSetManager::write_nvs_movement_set(){
|
||||
if (!ready){
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
Flatbuffers::SerializedMessage m = builder.build_movement_set(movements);
|
||||
|
||||
esp_err_t res = nvs_set_u32(handle, MOVEMENTS_NVS_SET_SIZE_KEY, static_cast<uint32_t>(m.size));
|
||||
|
||||
res = nvs_commit(handle);
|
||||
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to commit data size");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = nvs_set_blob(handle, MOVEMENTS_NVS_SET_KEY, m.data, m.size);
|
||||
|
||||
if (res != ESP_OK){
|
||||
ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to write to nvs");
|
||||
return res;
|
||||
}
|
||||
|
||||
res = nvs_commit(handle);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to commit topology");
|
||||
return res;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#define MOVEMENTS_NVS_KEY "key"
|
||||
#define MOVEMENTS_NVS_TOPOLOGY_KEY "topology"
|
||||
#define MOVEMENTS_NVS_TOPOLOGY_DATA_SIZE_KEY "data_size"
|
||||
#define MOVEMENTS_NVS_SET_KEY "mvt_set"
|
||||
#define MOVEMENTS_NVS_SET_SIZE_KEY "mvt_data_size"
|
||||
#define MOVEMENTS_DEBUG_TAG "movements"
|
||||
|
||||
class MovementManager {
|
||||
|
||||
@@ -1,29 +1,47 @@
|
||||
#include "MovementManager.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "TopologyManager.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "MovementSetBuilder.h"
|
||||
#include "unordered_map"
|
||||
#include "constants/rmt.h"
|
||||
#include "constants/datalink.h"
|
||||
|
||||
#ifdef MOVEMENTS
|
||||
#pragma once
|
||||
|
||||
#define DEFAULT_DELAY_MS 50 //some random value that i am using to default to for the delay after a movement has been completed
|
||||
#define DEFAULT_ACK_TTL_MS 100
|
||||
#define CONDITION_BLOB_NOT_IN_USE 0
|
||||
#define CONDITION_BLOB_IN_USE 1
|
||||
|
||||
enum class ACK_VALUES : uint8_t {
|
||||
NO_ACK, //no acks required
|
||||
ACK, //acks required to be sent and received properly within ttl
|
||||
ACK_NO_FAIL, //acks required to be send but not necessarily required to be received properly within ttl
|
||||
};
|
||||
|
||||
enum class CONDITION_VALUES : uint8_t {
|
||||
LT,
|
||||
LEQ,
|
||||
GT,
|
||||
GEQ,
|
||||
EQ,
|
||||
NE,
|
||||
};
|
||||
|
||||
class MovementSetManager {
|
||||
public:
|
||||
MovementSetManager();
|
||||
~MovementSetManager();
|
||||
esp_err_t add_movement(Movement::MovementEntry& entry, uint8_t& index);
|
||||
esp_err_t add_movement(MovementEntryData& entry, uint8_t index);
|
||||
esp_err_t remove_movement(uint8_t index, uint8_t board_id);
|
||||
esp_err_t update_movement(Movement::MovementEntry& entry, uint8_t index);
|
||||
esp_err_t get_curr_movement_set(Movement::MovementSet& set);
|
||||
esp_err_t verify_movement_set();
|
||||
esp_err_t get_nvs_movement_set(Movement::MovementSet& set);
|
||||
esp_err_t get_curr_movement_set(std::unordered_map<uint8_t, std::vector<MovementEntryData>>& set);
|
||||
esp_err_t get_nvs_movement_set(std::unordered_map<uint8_t, std::vector<MovementEntryData>>& set);
|
||||
esp_err_t write_nvs_movement_set();
|
||||
|
||||
private:
|
||||
std::unique_ptr<TopologyManager> topology_manager = std::make_unique<TopologyManager>();
|
||||
std::unordered_map<uint8_t, std::vector<Movement::MovementEntry>> movements;
|
||||
std::unordered_map<uint8_t, std::vector<MovementEntryData>> movements;
|
||||
nvs_handle_t handle;
|
||||
bool ready = false;
|
||||
Flatbuffers::MovementSetBuilder builder;
|
||||
|
||||
Reference in New Issue
Block a user