From ace2c5a544d7e3563cde9dd5b8b666a199e3ebd4 Mon Sep 17 00:00:00 2001 From: superkor Date: Tue, 13 Jan 2026 03:55:49 -0500 Subject: [PATCH] add some classes for movement set handling --- components/movements/CMakeLists.txt | 4 + components/movements/MovementManager.cpp | 25 ++++++ components/movements/MovementSetManager.cpp | 18 ++++ components/movements/README.md | 83 ++++++++++++++++++- components/movements/TopologyManager.cpp | 18 ++++ components/movements/include/MovementBlobs.h | 50 +++++++++++ .../movements/include/MovementManager.h | 23 +++++ components/movements/include/TopologyBlobs.h | 42 ++++++++++ components/movements/include/movements.h | 4 - components/movements/movements.cpp | 3 - main/CMakeLists.txt | 2 +- 11 files changed, 263 insertions(+), 9 deletions(-) create mode 100644 components/movements/CMakeLists.txt create mode 100644 components/movements/MovementManager.cpp create mode 100644 components/movements/MovementSetManager.cpp create mode 100644 components/movements/TopologyManager.cpp create mode 100644 components/movements/include/MovementBlobs.h create mode 100644 components/movements/include/MovementManager.h create mode 100644 components/movements/include/TopologyBlobs.h delete mode 100644 components/movements/include/movements.h delete mode 100644 components/movements/movements.cpp diff --git a/components/movements/CMakeLists.txt b/components/movements/CMakeLists.txt new file mode 100644 index 0000000..d922653 --- /dev/null +++ b/components/movements/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "MovementManager.cpp" "MovementManager.cpp" "TopologyManager.cpp" + PRIV_REQUIRES esp_event nvs_flash + # REQUIRES esp_timer + INCLUDE_DIRS "include") diff --git a/components/movements/MovementManager.cpp b/components/movements/MovementManager.cpp new file mode 100644 index 0000000..58349c4 --- /dev/null +++ b/components/movements/MovementManager.cpp @@ -0,0 +1,25 @@ +#include "MovementManager.h" +#include "nvs_flash.h" +#include "esp_log.h" +#ifdef MOVEMENTS + +MovementManager::MovementManager(){ + esp_err_t res = nvs_open(MOVEMENTS_NVS_NAMESPACE, NVS_READWRITE, &handle); + + if (res != ESP_OK){ + ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to open nvs for %s", MOVEMENTS_NVS_NAMESPACE); + return; + } + + status = ESP_OK; +}; + +esp_err_t MovementManager::get_movement_status(){ + return status; +} + +MovementManager::~MovementManager(){ + nvs_close(handle); +} + +#endif //MOVEMENTS \ No newline at end of file diff --git a/components/movements/MovementSetManager.cpp b/components/movements/MovementSetManager.cpp new file mode 100644 index 0000000..88138c7 --- /dev/null +++ b/components/movements/MovementSetManager.cpp @@ -0,0 +1,18 @@ +#include "MovementBlobs.h" +#include "esp_log.h" +#ifdef MOVEMENTS + +MovementSetManager::MovementSetManager(){ + esp_err_t res = nvs_open(MOVEMENTS_NVS_NAMESPACE, NVS_READWRITE, &handle); + + if (res != ESP_OK){ + ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to open nvs for %s", MOVEMENTS_NVS_NAMESPACE); + return; + } +}; + +MovementSetManager::~MovementSetManager(){ + nvs_close(handle); +} + +#endif //MOVEMENTS \ No newline at end of file diff --git a/components/movements/README.md b/components/movements/README.md index fbe5439..9f22b1a 100644 --- a/components/movements/README.md +++ b/components/movements/README.md @@ -1,3 +1,84 @@ +WIP + # Preprogrammed Movement -This component will handle the preprogrammed movements from the UI and then execute them (with or without a) connection to the PC/UI. \ No newline at end of file +This component will handle the preprogrammed movements from the UI and then execute them (with or without a) connection to the PC/UI. + +See [ESP32 NVS](https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/storage/nvs_flash.html) for more information about the NVS. + +## Movement Entries Stored on NVS + +The movements will be stored on the NVS of the leader board on the network, under the namespace `MOVEMENTS_NVS_NAMESPACE`. + +The movements themselves will be a table under the key `MOVEMENTS_NVS_KEY` as a blob: + +``` +{ + num_movements: uint8_t, + movements: MovementEntry[] +} +``` + +where `MovementEntry` is: + +``` +{ + board_id: uint16_t, + moduleType: uint8_t, + value_action: uint16_t, + condition: ConditionBlob, + ack: uint8_t, + ack_ttl_ms: uint16_t, + post_delay_ms: uint16_t +} +``` + +and `ConditionBlob` is: + +``` +{ + value: uint16_t, + cond: uint8_t (0: <, 1: <=, 2: >, 3: >=, 4: ==, 5: !=), + moduleType: uint8_t (check value/sensor data if possible or set to UNUSED if not in use) +} +``` + +Each entry will have a size of 14B. With a max number of 255 movements stored, that will represent 3570 B that will be stored on the NVS. + +There will only be one set of movements stored on the board (meaning a new movement set would have to overwrite the existing movement set). + +Blobs are written in the NVS with the entry metadata written first, then the actual data written in subsequent entries (32B per entry). + +## Storing the Toplogy for the Movement Set + +To run the movement set stored on a particular board, the board itself has to be the leader on the network (to resolve conflicts with multiple movement sets stored on different boards). + +Since the boards on the network will most likely have different ids assigned, the leader will have manually assign ids based on the expected toplogy that will correspond to the saved movement set. This is done to ensure the correct board is being properly referenced in the movement set. However, the stored board id on the NVS will not be overwritten with the board id assigned by the movement set but rather a simple 1:1 translation map will be used (making the movement-assigned board id functionally in use but the underlying board id will be used purely for wired communications). + +In order to do this, the toplogy will need to be saved onto the NVS (along with the movement entries). This will be stored in the same namespace but under a different key, `MOVEMENTS_NVS_TOPOLOGY_KEY`. + +The structure of the topology data stored on the NVS will look like: + +``` +{ + boards: NeighbourBlob[] (index 0 is leader) +} +``` + +where `NeighbourBlob` is: + +``` +{ + curr_board_id: uint16_t, + neighbour_connections: ChannelBoardConn[] (max 4, min 1) +} +``` + +where `ChannelBoardConn` is: +``` +{ + channel: uint8_t, + board_id: uint16_t +} +``` + diff --git a/components/movements/TopologyManager.cpp b/components/movements/TopologyManager.cpp new file mode 100644 index 0000000..0e0c052 --- /dev/null +++ b/components/movements/TopologyManager.cpp @@ -0,0 +1,18 @@ +#include "TopologyBlobs.h" +#include "esp_log.h" +#ifdef MOVEMENTS + +TopologyManager::TopologyManager(){ + esp_err_t res = nvs_open(MOVEMENTS_NVS_NAMESPACE, NVS_READWRITE, &handle); + + if (res != ESP_OK){ + ESP_LOGE(MOVEMENTS_DEBUG_TAG, "Failed to open nvs for %s", MOVEMENTS_NVS_NAMESPACE); + return; + } +}; + +TopologyManager::~TopologyManager(){ + nvs_close(handle); +} + +#endif //MOVEMENTS \ No newline at end of file diff --git a/components/movements/include/MovementBlobs.h b/components/movements/include/MovementBlobs.h new file mode 100644 index 0000000..435bfca --- /dev/null +++ b/components/movements/include/MovementBlobs.h @@ -0,0 +1,50 @@ +#include "MovementManager.h" +#include "nvs_flash.h" +#include "TopologyBlobs.h" +#include +#include + +#ifdef MOVEMENTS +#pragma once + +typedef struct _condition_blob { + uint16_t value; + uint8_t cond; + uint8_t moduleType; + uint8_t in_use; +} ConditionBlob; + +typedef struct _movement_entry { + uint16_t board_id; + uint8_t moduleType; + uint16_t value_action; + ConditionBlob condition; + uint8_t ack; + uint16_t ack_ttl_ms; + uint16_t post_delay_ms; +} MovementEntry; + +typedef struct _movement { + uint8_t num_movements; + MovementEntry movements[]; +} MovementSet; + +class MovementSetManager { + public: + MovementSetManager(); + ~MovementSetManager(); + esp_err_t add_movement(MovementEntry& entry, uint8_t& index); + esp_err_t remove_movement(uint8_t index); + esp_err_t update_movement(MovementEntry& entry, uint8_t index); + esp_err_t get_curr_movement_set(MovementSet& set); + esp_err_t verify_movement_set(); + esp_err_t get_nvs_movement_set(MovementSet& set); + esp_err_t write_nvs_movement_set(); + + private: + std::unique_ptr topology_manager; + std::vector movements; + nvs_handle_t handle; +}; + +#endif //MOVEMENTS \ No newline at end of file diff --git a/components/movements/include/MovementManager.h b/components/movements/include/MovementManager.h new file mode 100644 index 0000000..f7ed809 --- /dev/null +++ b/components/movements/include/MovementManager.h @@ -0,0 +1,23 @@ +#ifndef MOVEMENTS +#define MOVEMENTS + +#include "nvs_flash.h" + +#define MOVEMENTS_NVS_NAMESPACE "movements" +#define MOVEMENTS_NVS_KEY "key" +#define MOVEMENTS_NVS_TOPOLOGY_KEY "topology" +#define MOVEMENTS_DEBUG_TAG "movements" + +class MovementManager { + public: + MovementManager(); + ~MovementManager(); + esp_err_t get_movement_status(); + + private: + nvs_handle_t handle = 0; + esp_err_t status = ESP_ERR_INVALID_STATE; + +}; + +#endif //MOVEMENTS \ No newline at end of file diff --git a/components/movements/include/TopologyBlobs.h b/components/movements/include/TopologyBlobs.h new file mode 100644 index 0000000..6f15e93 --- /dev/null +++ b/components/movements/include/TopologyBlobs.h @@ -0,0 +1,42 @@ +#include "MovementManager.h" +#include "nvs_flash.h" +#include + +#ifdef MOVEMENTS +#pragma once + +typedef struct _channel_board_conn { + uint8_t channel; + uint16_t board_id; +} ChannelBoardConn; + +typedef struct _neighbour_blob { + uint16_t curr_board_id; + uint8_t num_connections; + ChannelBoardConn neighbour_connections[]; +} NeighbourBlob; + +typedef struct _topology { + uint16_t num_boards; + NeighbourBlob boards[]; +} Topology; + +class TopologyManager { + public: + TopologyManager(); + ~TopologyManager(); + esp_err_t add_board_to_topology(NeighbourBlob blob); + esp_err_t remove_board_from_topology(uint16_t board_id); + esp_err_t update_board_in_topology(NeighbourBlob blob); + esp_err_t get_board_in_topology(NeighbourBlob& blob); + esp_err_t verify_topology(); + esp_err_t get_curr_topology(Topology& topology); + esp_err_t write_nvs_topology(); + esp_err_t get_nvs_topology(Topology& topology); + + private: + std::unordered_map topology; + nvs_handle_t handle; +}; + +#endif //MOVEMENTS \ No newline at end of file diff --git a/components/movements/include/movements.h b/components/movements/include/movements.h deleted file mode 100644 index 1630f8b..0000000 --- a/components/movements/include/movements.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef MOVEMENTS -#define MOVEMENTS - -#endif //MOVEMENTS \ No newline at end of file diff --git a/components/movements/movements.cpp b/components/movements/movements.cpp deleted file mode 100644 index 21e7a7f..0000000 --- a/components/movements/movements.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#ifdef MOVEMENTS - -#endif //MOVEMENTS \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 260c604..a50cdc1 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -17,7 +17,7 @@ else() endif() idf_component_register(SRCS ${ALL_SRCS} - PRIV_REQUIRES esp_psram spi_flash nvs_flash esp_event rpc constants config rmt esp_driver_gptimer dataLink flatbuffers esp_driver_ledc + PRIV_REQUIRES esp_psram spi_flash nvs_flash esp_event rpc constants config rmt esp_driver_gptimer dataLink flatbuffers esp_driver_ledc movements INCLUDE_DIRS "include") if(DEFINED SRC_BOARD AND SRC_BOARD)