diff --git a/CLC-qthing/CMakeLists.txt b/CLC-qthing/CMakeLists.txt index 2daa6ed90ff637b3dc342d7defc2376143594d71..8449b2a3f9bcc8e281a966fdabb7771e3e25beff 100644 --- a/CLC-qthing/CMakeLists.txt +++ b/CLC-qthing/CMakeLists.txt @@ -3,7 +3,7 @@ idf_component_register( "." "SiliconTorch" "SpiderLib" INCLUDE_DIRS - "." + "." "SpiderLib" REQUIRES main diff --git a/CLC-qthing/CyanLight.cpp b/CLC-qthing/CyanLight.cpp index f7007b9bae0fe46113eac4ae70f622bad3d90590..d97ff2aa5f7612a8184081faaa66fd8c601b85e1 100644 --- a/CLC-qthing/CyanLight.cpp +++ b/CLC-qthing/CyanLight.cpp @@ -6,20 +6,23 @@ // ESP32 specific #include "esp_log.h" +// project specific +#include "SpiderLib/NumberTypes.hpp" -uint8_t MAX_CHANNELS = 8; + +u8 MAX_CHANNELS = 8; const char* TAG = "CyanLight"; -const uint8_t channelGPIOs[] = { 27, 16, 17, 18, 19, 21, 22, 23 }; +const u8 channelGPIOs[] = { 27, 16, 17, 18, 19, 21, 22, 23 }; namespace CyanLight { - CyanLightControl::CyanLightControl(uint8_t channelsConfigured, uint32_t baseChannel) : SiliconTorch::FxCyanF(baseChannel) { + CyanLightControl::CyanLightControl(u8 channelsConfigured, u32 baseChannel) : SiliconTorch::FxCyanF::FxCyanF(baseChannel) { - uint8_t channels = std::min(channelsConfigured, MAX_CHANNELS); + u8 channels = std::min(channelsConfigured, MAX_CHANNELS); - for (uint8_t i = 0; i < channels; i++) this->addChannel(); + for (u8 i = 0; i < channels; i++) this->addChannel(); } @@ -28,7 +31,7 @@ namespace CyanLight { auto ch = this->getChannelCount(); if (ch < MAX_CHANNELS) { - return SiliconTorch::FxCyanF::addChannel((uint8_t)channelGPIOs[ch]); + return SiliconTorch::FxCyanF::FxCyanF::addChannel((u8)channelGPIOs[ch]); } else { ESP_LOGE(TAG, "Cannot create channel#[ %i ]! CLC hardware limit is #[ %i ]", ch, MAX_CHANNELS); return false; diff --git a/CLC-qthing/CyanLight.hpp b/CLC-qthing/CyanLight.hpp index 85538773cde97b477f8bc33787feb10b3d6e2eb8..63dd53a93ab6d0fe437e73a7cce9c761274a6fac 100644 --- a/CLC-qthing/CyanLight.hpp +++ b/CLC-qthing/CyanLight.hpp @@ -1,18 +1,21 @@ #pragma once -// TODO: should we include <cinttypes> here or accepts its ingress via FxCyanF.hpp ??? +// TODO: should we include NumberTypes.hpp here or accepts its ingress via FxCyanF.hpp ??? #include "SiliconTorch/FxCyanF.hpp" +#include "SpiderLib/NumberTypes.hpp" + + namespace CyanLight { - class CyanLightControl : public SiliconTorch::FxCyanF { + class CyanLightControl : public SiliconTorch::FxCyanF::FxCyanF { public: - CyanLightControl(uint8_t channelsConfigured, uint32_t baseChannel = 0); + CyanLightControl(u8 channelsConfigured, u32 baseChannel = 0); bool addChannel(); - using SiliconTorch::FxCyanF::addChannel; + using SiliconTorch::FxCyanF::FxCyanF::addChannel; }; diff --git a/CLC-qthing/IRSender.cpp b/CLC-qthing/IRSender.cpp index 86f3e982067b9d3bf608a10b24a24e3014655c59..8c9581654188ba022affcc28062ebe83a602a52f 100644 --- a/CLC-qthing/IRSender.cpp +++ b/CLC-qthing/IRSender.cpp @@ -5,8 +5,11 @@ #include "driver/gpio.h" #include "driver/ledc.h" +// project specific +#include "SpiderLib/NumberTypes.hpp" -IRSender::IRSender(uint8_t TXpin, uint8_t CLKpin, uint8_t UARTchannel, uint8_t LEDCchannel) { + +IRSender::IRSender(u8 TXpin, u8 CLKpin, u8 UARTchannel, u8 LEDCchannel) { ledc_timer_config_t ledc_timer; ledc_timer.duty_resolution = LEDC_TIMER_1_BIT; @@ -48,7 +51,7 @@ IRSender::IRSender(uint8_t TXpin, uint8_t CLKpin, uint8_t UARTchannel, uint8_t L } -void IRSender::send(uint8_t byte) { +void IRSender::send(u8 byte) { } @@ -56,7 +59,7 @@ void IRSender::send(std::string &data) { } -void IRSender::send(uint8_t *buffer, size_t length) { +void IRSender::send(u8 *buffer, size_t length) { } diff --git a/CLC-qthing/IRSender.hpp b/CLC-qthing/IRSender.hpp index 82ebf9a32d53e513b19619099ec5ab9f4e5767a2..618059dbd768ac8b89196f9678a89cbec4b0fb9e 100644 --- a/CLC-qthing/IRSender.hpp +++ b/CLC-qthing/IRSender.hpp @@ -1,17 +1,17 @@ #pragma once -#include <cinttypes> +#include "SpiderLib/NumberTypes.hpp" #include <string> class IRSender { public: - IRSender(uint8_t TXpin, uint8_t CLKpin, uint8_t UARTchannel = 1, uint8_t LEDCchannel = 7); + IRSender(u8 TXpin, u8 CLKpin, u8 UARTchannel = 1, u8 LEDCchannel = 7); - void send(uint8_t byte); + void send(u8 byte); void send(std::string &data); - void send(uint8_t *buffer, size_t length); + void send(u8 *buffer, size_t length); }; diff --git a/CLC-qthing/SiliconTorch/CapMan.cpp b/CLC-qthing/SiliconTorch/CapMan.cpp index 138fa285c1926825e4814279320d4e7460d08c63..e6933fe794e75bcf9771000780098cebdfc2f24f 100644 --- a/CLC-qthing/SiliconTorch/CapMan.cpp +++ b/CLC-qthing/SiliconTorch/CapMan.cpp @@ -3,7 +3,6 @@ // C++ system level // #include <cstring> // memset, strncmp // #include <cstdlib> // TODO: is this for memcpy? -#include <cinttypes> // #include <functional> // ESP32 specific @@ -13,7 +12,7 @@ // #include "driver/uart.h" // project specific -// #include "" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include <qthing> diff --git a/CLC-qthing/SiliconTorch/CapMan.hpp b/CLC-qthing/SiliconTorch/CapMan.hpp index 2bcf8840f7b310a4a4ff3a5927bb0c1f6e359340..f84ccabc4b71877cf73f5fd91fd8f77cd9c0eca0 100644 --- a/CLC-qthing/SiliconTorch/CapMan.hpp +++ b/CLC-qthing/SiliconTorch/CapMan.hpp @@ -4,7 +4,6 @@ // #include <string> // #include <cstring> // memset, strncmp // #include <cstdlib> // TODO: is this for memcpy? -#include <cinttypes> // #include <functional> // ESP32 specific @@ -14,7 +13,7 @@ // #include "driver/uart.h" // project specific -// #include "" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include <qthing> @@ -42,7 +41,7 @@ namespace SiliconTorch { - void registerLEDStrip(std::string& name, uint16_t startIdx, uint16_t length, ColorType); + void registerLEDStrip(std::string& name, u16 startIdx, u16 length, ColorType); diff --git a/CLC-qthing/SiliconTorch/CyanBus.cpp b/CLC-qthing/SiliconTorch/CyanBus.cpp index a53644d5818abaefc5c50de7ecc0795eadd55d72..13e5b35eac04dbd358ba2dc43480ba82ddfaeacb 100644 --- a/CLC-qthing/SiliconTorch/CyanBus.cpp +++ b/CLC-qthing/SiliconTorch/CyanBus.cpp @@ -3,7 +3,6 @@ // C++ system level #include <cstring> // memset, strncmp #include <cstdlib> // TODO: is this for memcpy? -#include <cinttypes> #include <functional> // ESP32 specific @@ -19,6 +18,7 @@ #include "LambdaTask.hpp" #include "SpiderLib/Callback.hpp" #include "SpiderLib/CallbackMap.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include "" @@ -29,7 +29,7 @@ static const char* TAG = "CyanBus"; // Extract the length from a buffer; Network order / Big-Endian -static uint16_t getLength(const uint8_t* buffer) { +static u16 getLength(const u8* buffer) { return (buffer[0] << 8) | buffer[1]; } @@ -42,9 +42,9 @@ namespace SiliconTorch { const char* const HEADER = "fxCyan"; - CyanBus::CyanBus(uint8_t tx, uint8_t rx, uint8_t de, uint8_t re, uint32_t baudRate, uint8_t uartChannel) : tx(tx), rx(rx), de(de), re(re), uartChannel(uartChannel) { + CyanBus::CyanBus(u8 tx, u8 rx, u8 de, u8 re, u32 baudRate, u8 uartChannel) : tx(tx), rx(rx), de(de), re(re), uartChannel(uartChannel) { - uint64_t bitMask = 0; + u64 bitMask = 0; bitMask |= 1ULL << tx; bitMask |= 1ULL << de; @@ -113,14 +113,14 @@ namespace SiliconTorch { uart_port_t _ch = (uart_port_t)uartChannel; - const uint32_t bufLEN = MTU + 256; // MTU + maxEventSize(120) + slack - uint8_t* buffer = new uint8_t[bufLEN]; // our packet buffer - uint8_t* bufPTR = buffer; // points inside our buffer; used for envelope parsing… + const u32 bufLEN = MTU + 256; // MTU + maxEventSize(120) + slack + u8* buffer = new u8[bufLEN]; // our packet buffer + u8* bufPTR = buffer; // points inside our buffer; used for envelope parsing… - uint16_t payloadLEN = 0; - const uint8_t crcLEN = 4; - const uint8_t lengthLEN = 2; - const uint8_t headerLEN = std::strlen(HEADER); + u16 payloadLEN = 0; + const u8 crcLEN = 4; + const u8 lengthLEN = 2; + const u8 headerLEN = std::strlen(HEADER); std::memset(buffer, 0x00, bufLEN); @@ -260,8 +260,8 @@ namespace SiliconTorch { } void CyanBus::packetTask() { - const uint8_t* buffer = new uint8_t[MTU]; - uint16_t payloadLEN = 0; + const u8* buffer = new u8[MTU]; + u16 payloadLEN = 0; auto Q = packetQ; while (true) { @@ -293,12 +293,12 @@ namespace SiliconTorch { } - void CyanBus::setBaudRate(uint32_t baudRate) { + void CyanBus::setBaudRate(u32 baudRate) { uart_set_baudrate((uart_port_t)uartChannel, baudRate); } - uint32_t CyanBus::getBaudRate() { - uint32_t baudRate = 0; + u32 CyanBus::getBaudRate() { + u32 baudRate = 0; uart_get_baudrate((uart_port_t)uartChannel, &baudRate); return baudRate; } diff --git a/CLC-qthing/SiliconTorch/CyanBus.hpp b/CLC-qthing/SiliconTorch/CyanBus.hpp index 9891c54e262af1c94a178bc434c39e8c9bab6d6e..de76ae3afde325c893412ef74c2da18e8833423a 100644 --- a/CLC-qthing/SiliconTorch/CyanBus.hpp +++ b/CLC-qthing/SiliconTorch/CyanBus.hpp @@ -2,7 +2,6 @@ // C++ system level #include <string> -#include <cinttypes> #include <functional> // ESP32 specific @@ -13,6 +12,7 @@ #include "LambdaTask.hpp" #include "SpiderLib/Callback.hpp" #include "SpiderLib/CallbackMap.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include "" @@ -25,29 +25,29 @@ namespace SiliconTorch { // CyanBus payload MTU // This leads to ~54 P/s @ 2 MBaud at 100% load - constexpr uint32_t MTU = 4096; + constexpr u32 MTU = 4096; // CyanBus envelope header extern const char* const HEADER; typedef struct { - const uint8_t* payload; - const uint16_t length; + const u8* payload; + const u16 length; } PacketData; typedef struct { const bool crcOK; - const uint16_t payloadLEN; + const u16 payloadLEN; } PacketMetrics; class CyanBus { public: - CyanBus(uint8_t tx, uint8_t rx, uint8_t de, uint8_t re, uint32_t baudRate = 115200, uint8_t uartChannel = 1); + CyanBus(u8 tx, u8 rx, u8 de, u8 re, u32 baudRate = 115200, u8 uartChannel = 1); - uint32_t getBaudRate(); - void setBaudRate(uint32_t baudRate); + u32 getBaudRate(); + void setBaudRate(u32 baudRate); const SpiderLib::CallbackMap<void(const PacketData&)> packetCallback; const SpiderLib::Callback<void(const PacketMetrics&)> metricsCallback; @@ -57,8 +57,8 @@ namespace SiliconTorch { QueueHandle_t uartEvQ; QueueHandle_t packetQ; - uint8_t uartChannel; - uint8_t tx, rx, de, re; + u8 uartChannel; + u8 tx, rx, de, re; void txEN(bool state); void rxEN(bool state); @@ -67,7 +67,7 @@ namespace SiliconTorch { // Receive only ATM! (make public after sound implementation…) void write(std::string& data); - void write(const uint8_t* data, uint32_t length); + void write(const u8* data, u32 length); void readerTask(); diff --git a/CLC-qthing/SiliconTorch/CyanBusCRC.cpp b/CLC-qthing/SiliconTorch/CyanBusCRC.cpp index fc6a9a7057769ec4febd5ddb3cb43ddf3fd43ec1..7d5cbef8c5b3199800303cb88a1d68252f66e962 100644 --- a/CLC-qthing/SiliconTorch/CyanBusCRC.cpp +++ b/CLC-qthing/SiliconTorch/CyanBusCRC.cpp @@ -1,14 +1,14 @@ #include "CyanBusCRC.hpp" // C++ system level -#include <cinttypes> +// #include <functional> // ESP32 specific #include "esp_log.h" #include "esp32/rom/crc.h" // project specific -// #include "LambdaTask.hpp" +#include "SpiderLib/NumberTypes.hpp" static const char* TAG = "CyanBus"; @@ -20,17 +20,17 @@ namespace SiliconTorch { // Checks CyanBus CRC // Note: The last 4 bytes of buffer contain the CRC to check against and are included in the given length - bool checkCRC(uint8_t* buffer, uint32_t length) { + bool checkCRC(u8* buffer, u32 length) { if (length < 4) { ESP_LOGD(TAG, "CRC calculation failed: Input buffer too small! Got bytes[ %d ] but needs bytes[ >= 4 ]", length); return false; } - // uint32_t _init = 0x00000000; - uint32_t _init = 0xFFFFFFFF; - uint32_t calculatedCRC = crc32_be(_init, buffer, length - 4); - uint32_t packetCRC = reinterpret_cast<uint32_t*>(&buffer[length - 4])[0]; + // u32 _init = 0x00000000; + u32 _init = 0xFFFFFFFF; + u32 calculatedCRC = crc32_be(_init, buffer, length - 4); + u32 packetCRC = reinterpret_cast<u32*>(&buffer[length - 4])[0]; bool crcOK = packetCRC == calculatedCRC; diff --git a/CLC-qthing/SiliconTorch/CyanBusCRC.hpp b/CLC-qthing/SiliconTorch/CyanBusCRC.hpp index 2cf93e5513c644c7ddb7ac117eb66ff1f32cae8e..23da20d7a1f7b702241f045d0e768ce00fa96699 100644 --- a/CLC-qthing/SiliconTorch/CyanBusCRC.hpp +++ b/CLC-qthing/SiliconTorch/CyanBusCRC.hpp @@ -1,13 +1,13 @@ #pragma once // C++ system level -#include <cinttypes> +// #include <functional> // ESP32 specific // #include "esp_log.h" // project specific -// #include "LambdaTask.hpp" +#include "SpiderLib/NumberTypes.hpp" @@ -17,7 +17,7 @@ namespace SiliconTorch { // Checks CyanBus CRC // seems to work against Crc32Posix from python crccheck package - bool checkCRC(uint8_t* buffer, uint32_t length); + bool checkCRC(u8* buffer, u32 length); } diff --git a/CLC-qthing/SiliconTorch/FxCyanF-classImplementation.cpp b/CLC-qthing/SiliconTorch/FxCyanF-classImplementation.cpp index 162f12664ef49b1140f98c1d1d0ef6dbeff0bcf2..3db8792d2b07593e99d061898c587519549591ac 100644 --- a/CLC-qthing/SiliconTorch/FxCyanF-classImplementation.cpp +++ b/CLC-qthing/SiliconTorch/FxCyanF-classImplementation.cpp @@ -1,29 +1,30 @@ #include "FxCyanF.hpp" +// C++ system level +#include <cstdio> +#include <cstdlib> +#include <algorithm> +#include <functional> + // ESP32 specific #include "esp_err.h" #include "esp_log.h" #include "driver/ledc.h" #include "tcpip_adapter.h" -// misc -#include <nlohmann/json.hpp> +// project specific +#include "FxVSync.hpp" +#include "CyanBus.hpp" +#include "Metrics.hpp" +#include <SpiderLib/NumberTypes.hpp> +#include <SpiderLib/ObjectTypes.hpp> // qthing stuff #include <qthing> #include <qthing/mqtt_common.hpp> -// C++ system level -#include <string> -#include <cstdio> -#include <cstdlib> -#include <algorithm> -#include <functional> - -// project specific -#include "FxVSync.hpp" -#include "CyanBus.hpp" -#include "Metrics.hpp" +// misc +#include <nlohmann/json.hpp> using namespace qthing; @@ -33,19 +34,16 @@ using json = nlohmann::json; namespace SiliconTorch { - //namespace FxCyanF { + namespace FxCyanF { const char* TAG = "FxCyanF"; + const str nvsNameSpace = TAG; + const str HEADER("fxCyanF"); - const std::string HEADER("fxCyanF"); - - - const uint8_t MAX_CHANNELS = 8; // Maybe 16…? - - const std::string delimiter = ":"; + const str delimiter = ":"; - static float bytes2float(const uint8_t* bytes) { + static float bytes2float(const u8* bytes) { float f; memcpy(&f, bytes, sizeof(f)); @@ -54,7 +52,7 @@ namespace SiliconTorch { } - FxCyanF::FxCyanF(uint32_t baseChannel) : metrics(Metrics::Metrics("fxCyan")), baseChannel(baseChannel) { + FxCyanF::FxCyanF(u32 baseChannel) : metrics(Metrics::Metrics("fxCyan")), baseChannel(baseChannel) { this->metrics.registerMetric("frames", "frameCounter"); this->metrics.registerMetric("errors", "errorCounter"); @@ -78,44 +76,43 @@ namespace SiliconTorch { add_binary_message_callback(this->genDeviceTopic("pwm/$all"), [&](qthing::multipart_message_t message) { - if (message.offset == 0) this->handleUnicast((const uint8_t*)message.payload, message.length); + if (message.offset == 0) this->handleUnicast((const u8*)message.payload, message.length); else ESP_LOGE(TAG, "Invalid message format: Fragmentation is unsupported"); }); - std::string header("fxCyanF"); - uint8_t headerLength = header.length(); + u8 headerLength = HEADER.length(); - qthing::addUDPPacketCallback(header, [&, headerLength](udpPacket packet) { - this->handleUnicast((const uint8_t*)packet.payload + headerLength, packet.length - headerLength); + qthing::addUDPPacketCallback(HEADER, [&, headerLength](udpPacket packet) { + this->handleUnicast((const u8*)packet.payload + headerLength, packet.length - headerLength); }); - std::function<void(const std::string&)> setCh = [&](const std::string& message) { + std::function<void(const str&)> setCh = [&](const str& message) { long int ch = strtol(message.c_str(), NULL, 0); this->setBaseChannel(ch); }; - std::function<void(const std::string&)> setFrq = [&](const std::string& message) { + std::function<void(const str&)> setFrq = [&](const str& message) { long int frq = strtol(message.c_str(), NULL, 0); this->setFrequency(frq); }; - std::function<void(const std::string&)> setRes = [&](const std::string& message) { + std::function<void(const str&)> setRes = [&](const str& message) { long int res = strtol(message.c_str(), NULL, 0); this->setResolution(res); }; - std::function<void(const std::string&)> setFrqRes = [&](const std::string& message) { - std::string::size_type found = message.find(delimiter); + std::function<void(const str&)> setFrqRes = [&](const str& message) { + str::size_type found = message.find(delimiter); - if (found == std::string::npos) { + if (found == str::npos) { ESP_LOGE(TAG, "Invalid message format[ %s ]", message.c_str()); return; } - std::string _frq = message.substr(0, found); - std::string _res = message.substr(found + delimiter.length()); + str _frq = message.substr(0, found); + str _res = message.substr(found + delimiter.length()); long int frq = strtol(_frq.c_str(), NULL, 0); long int res = strtol(_res.c_str(), NULL, 0); @@ -129,27 +126,27 @@ namespace SiliconTorch { }; - std::function<void(const std::string&)> getBCh = [&](const std::string& ignored) { + std::function<void(const str&)> getBCh = [&](const str& ignored) { this->publishBaseChannel(); }; - std::function<void(const std::string&)> getChs = [&](const std::string& ignored) { + std::function<void(const str&)> getChs = [&](const str& ignored) { this->publishChannelCount(); }; - std::function<void(const std::string&)> getFrq = [&](const std::string& ignored) { + std::function<void(const str&)> getFrq = [&](const str& ignored) { this->publishFrequency(); }; - std::function<void(const std::string&)> getRes = [&](const std::string& ignored) { + std::function<void(const str&)> getRes = [&](const str& ignored) { this->publishResolution(); }; - std::function<void(const std::string&)> getFrqRes = [&](const std::string& ignored) { + std::function<void(const str&)> getFrqRes = [&](const str& ignored) { this->publishFrqRes(); }; - std::function<void(const std::string&)> getListener = [&](const std::string& ignored) { + std::function<void(const str&)> getListener = [&](const str& ignored) { this->publishListenerInfo(); }; @@ -187,13 +184,13 @@ namespace SiliconTorch { } - bool FxCyanF::addChannel(uint8_t gpio) { + bool FxCyanF::addChannel(u8 gpio, float initialValue) { if (this->channelsConfigured >= MAX_CHANNELS) { ESP_LOGE(TAG, "Cannot create channel#[ %i ]! ESP32 hardware limit is #[ %i ]", this->channelsConfigured, MAX_CHANNELS); return false; } - uint8_t channel = this->channelsConfigured; + u8 channel = this->channelsConfigured; // TODO: catch channel creation errors from IDF (e.g. on input-only GPIO) this->channels[channel] = new Impl::PWMChannel(channel, gpio); @@ -201,20 +198,21 @@ namespace SiliconTorch { char topic[32]; snprintf(topic, sizeof(topic), "pwm/$%i", channel); - add_message_callback(this->genDeviceTopic(topic), [&, channel](const std::string& message) { + add_message_callback(this->genDeviceTopic(topic), [&, channel](const str& message) { this->setPWM(channel, strtof(message.c_str(), NULL)); this->callPacketCallback(); }); this->channelsConfigured++; + this->setPWM(channel, initialValue); return true; } - bool FxCyanF::handleUnicast(const uint8_t* data, std::size_t length) { + bool FxCyanF::handleUnicast(const u8* data, std::size_t length) { std::size_t size = this->getChannelCount() * sizeof(float); - int32_t diff = length - size; + i32 diff = length - size; if (diff < 0) { ESP_LOGE(TAG, "Invalid |data|[ %d ]: Received ΔB[ %d ] bytes too few", length, -diff); @@ -223,7 +221,7 @@ namespace SiliconTorch { return false; } - for (uint8_t ch = 0; ch < this->getChannelCount(); ch++) { + for (u8 ch = 0; ch < this->getChannelCount(); ch++) { float f = bytes2float(data + ch * sizeof(float)); this->setPWM(ch, f); } @@ -234,11 +232,11 @@ namespace SiliconTorch { return true; } - bool FxCyanF::handleBroadcast(const uint8_t* data, std::size_t length) { + bool FxCyanF::handleBroadcast(const u8* data, std::size_t length) { std::size_t size = this->getChannelCount() * sizeof(float); std::size_t offset = this->getBaseChannel() * sizeof(float); - int32_t diff = length - offset - size; + i32 diff = length - offset - size; if (diff < 0) { // TODO: test thoroughly! ESP_LOGE(TAG, "Invalid data length[ %i ]: Received ΔB = %i bytes too few", length, -diff); @@ -247,7 +245,7 @@ namespace SiliconTorch { return false; } - for (uint8_t ch = 0; ch < this->getChannelCount(); ch++) { + for (u8 ch = 0; ch < this->getChannelCount(); ch++) { float f = bytes2float(data + offset + ch * sizeof(float)); this->setPWM(ch, f); } @@ -259,7 +257,12 @@ namespace SiliconTorch { } - void FxCyanF::setPWM(uint8_t channel, float value) { + void FxCyanF::setPWM(u8 channel, float value) { + + if (std::isnan(value)) { + ESP_LOGW(TAG, "PWM[ NaN ] value for channel[ %i ] out of range", channel); + return; + } if (channel >= this->channelsConfigured) { ESP_LOGW(TAG, "ChannelID out of range: channel[ %i ]", channel); @@ -271,8 +274,8 @@ namespace SiliconTorch { if (value < 0.0f) value = 0.0f; if (value > 1.0f) value = 1.0f; - uint32_t maxPWM = 1 << (this->resolution - 1); - uint32_t pwm = (uint32_t)( value * (maxPWM - 1) ); + u32 maxPWM = 1 << (this->resolution - 1); + u32 pwm = (u32)( value * (maxPWM - 1) ); this->channels[channel]->setPWM(pwm); } @@ -283,7 +286,7 @@ namespace SiliconTorch { } - bool FxCyanF::setFrqRes(uint32_t frq_hz, uint8_t res_bits) { + bool FxCyanF::setFrqRes(u32 frq_hz, u8 res_bits) { this->timer_cfg.duty_resolution = (ledc_timer_bit_t)res_bits; this->timer_cfg.freq_hz = frq_hz; @@ -305,10 +308,10 @@ namespace SiliconTorch { void FxCyanF::registerAtCyanBus(CyanBus::CyanBus& cyanBus) { /* - uint8_t headerLength = HEADER.length(); + u8 headerLength = HEADER.length(); cyanBus.packetCallback.add(HEADER, [&, headerLength](const CyanBus::PacketData& packet) { - this->handlePacket((uint8_t*)(packet.payload + headerLength), packet.length - headerLength); + this->handlePacket((u8*)(packet.payload + headerLength), packet.length - headerLength); }); FxVSync::registerAtCyanBus(cyanBus, [&]() { @@ -317,31 +320,31 @@ namespace SiliconTorch { */ } - void FxCyanF::setBaseChannel(uint16_t baseChannel) { + void FxCyanF::setBaseChannel(u16 baseChannel) { this->baseChannel = baseChannel; } - uint16_t FxCyanF::getBaseChannel() { + u16 FxCyanF::getBaseChannel() { return this->baseChannel; } - uint8_t FxCyanF::getChannelCount() { + u8 FxCyanF::getChannelCount() { return this->channelsConfigured; } - bool FxCyanF::setFrequency(uint32_t frq_hz) { + bool FxCyanF::setFrequency(u32 frq_hz) { return this->setFrqRes(frq_hz, this->resolution); } - uint32_t FxCyanF::getFrequency() { + u32 FxCyanF::getFrequency() { return this->frequency; } - bool FxCyanF::setResolution(uint8_t res_bits) { + bool FxCyanF::setResolution(u8 res_bits) { return this->setFrqRes(this->frequency, res_bits); } - uint8_t FxCyanF::getResolution() { + u8 FxCyanF::getResolution() { return this->resolution; } @@ -350,12 +353,12 @@ namespace SiliconTorch { } - std::string FxCyanF::genDeviceTopic(const char *suffix) { - return std::string(DEVICE_NAMESPACE + "fxCyan/") + std::string(suffix); + str FxCyanF::genDeviceTopic(const char *suffix) { + return str(DEVICE_NAMESPACE + "fxCyan/") + str(suffix); } - std::string FxCyanF::genServiceTopic(const char *suffix) { - return std::string("service/fxCyan/") + std::string(suffix); + str FxCyanF::genServiceTopic(const char *suffix) { + return str("service/fxCyan/") + str(suffix); } @@ -417,5 +420,5 @@ namespace SiliconTorch { } } } -// } + } } diff --git a/CLC-qthing/SiliconTorch/FxCyanF-configureFromNVS.cpp b/CLC-qthing/SiliconTorch/FxCyanF-configureFromNVS.cpp index f5cd73e02095cfe79edc0f1c6c48260ffa0e912c..49e83fd52a7685847586fb3360b25381630633cc 100644 --- a/CLC-qthing/SiliconTorch/FxCyanF-configureFromNVS.cpp +++ b/CLC-qthing/SiliconTorch/FxCyanF-configureFromNVS.cpp @@ -1,15 +1,12 @@ #include "FxCyanF.hpp" // C++ system level -#include <string> -// #include <cstdio> +#include <cstdio> // snprintf // #include <cstdlib> // #include <algorithm> // #include <functional> // ESP32 specific -#include "nvs.h" -#include "nvs_flash.h" #include "esp_log.h" // misc @@ -20,31 +17,81 @@ // #include <qthing/mqtt_common.hpp> // project specific -// #include "FxVSync.hpp" -// #include "CyanBus.hpp" -// #include "Metrics.hpp" +#include "NVSExplorer.hpp" +#include <SpiderLib/NumberTypes.hpp> +#include <SpiderLib/ObjectTypes.hpp> +const char* TAG_nvs = "FxCyanF-NVS"; + namespace SiliconTorch { - // namespace FxCyanF { + namespace FxCyanF { + + + const str ServiceNamespace = "fxCyan"; + + + FxCyanF* configureFromNVS() { + + u8 state = 0; // disabled -> 0 enabled -> 1 + state = NVSExplorer::NVSExplorer::instance().getUnsignedInt(ServiceNamespace, "state", state); + + if (state == 0) { + ESP_LOGI(TAG_nvs, "Service[ FxCyanF ] disabled[âŒ]"); + return NULL; + } + + FxCyanF* target = new FxCyanF(); + + ESP_LOGI(TAG_nvs, "Service[ FxCyanF ] enabling[✅]…"); + + u32 frq = DefaultFrequency; + u8 res = DefaultResolution; + + frq = NVSExplorer::NVSExplorer::instance().getUnsignedInt(ServiceNamespace, "frequency", frq); + res = NVSExplorer::NVSExplorer::instance().getUnsignedInt(ServiceNamespace, "resolution", res); + + + ESP_LOGI(TAG_nvs, "Configuring: FxCyanF{ frequency[ %d Hz ] resolution[ %d Bit ] }", frq, res); + target->setFrqRes(frq, res); + + for (u8 ch = 0; ch < MAX_CHANNELS; ch++) { + + + char buffer[32]; + snprintf(buffer, 32, "ch%d_gpio", ch); + + u8 gpio = NVSExplorer::NVSExplorer::instance().getUnsignedInt(ServiceNamespace, buffer, 0xFF) & 0xFF; + snprintf(buffer, 32, "ch%d_pwm", ch); + f32 pwm = NVSExplorer::NVSExplorer::instance().getFloat(ServiceNamespace, buffer); - const std::string nameSpace = "FxCyanF"; + // NaN == "no value stored" or any other reading error + if (std::isnan(pwm)) pwm = 0.0f; + if (gpio != 0xFF) { // key exists - bool configureFromNVS(FxCyanF& target) { + if ( target->addChannel(gpio, pwm) ) { // channel creation successful + + ESP_LOGI(TAG_nvs, "Configuring: FxCyanF{ channel[ %d ] gpio[ %d ] pwm[ %f ] }", ch, gpio, pwm); - nvs_flash_init(); + target->setPWM(ch, pwm); - nvs_handle_t nvs; - nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs); + } else { + ESP_LOGW(TAG_nvs, "Configuring: FxCyanF{ channel[ %d ] gpio[ %d ] } FAILED[âŒ]", ch, gpio); + break; + } + } else { + break; + } + } - return false; + return target; } - // } + } } diff --git a/CLC-qthing/SiliconTorch/FxCyanF.hpp b/CLC-qthing/SiliconTorch/FxCyanF.hpp index a3fc5e0637b5857d71ecc894740d9ebb336ea4b6..0a7d19e39b619c0db12e4e0d14912f008d5f7d30 100644 --- a/CLC-qthing/SiliconTorch/FxCyanF.hpp +++ b/CLC-qthing/SiliconTorch/FxCyanF.hpp @@ -4,53 +4,64 @@ #include "driver/ledc.h" // C++ system level -#include <string> +#include <cmath> #include <functional> -#include <cinttypes> // project specific #include "CyanBus.hpp" #include "Metrics.hpp" #include "PWMChannel.hpp" +#include <SpiderLib/NumberTypes.hpp> +#include <SpiderLib/ObjectTypes.hpp> namespace SiliconTorch { - //namespace FxCyanF { + namespace FxCyanF { - extern const std::string HEADER; + extern const char* TAG; + extern const str nvsNameSpace; // "fxCyan" + extern const str HEADER; // "fxCyanF" + + constexpr u8 MAX_CHANNELS = 8; // vorerst 8 + + + constexpr u32 DefaultFrequency = 1337; // Hz + constexpr u8 DefaultResolution = 10; // Bits + + + using PacketHandledCallback = std::function<void()>; + using GammaCorrector = std::function<float(float)>; - typedef std::function<void()> PacketHandledCallback; - typedef std::function<float(float)> GammaCorrector; class FxCyanF { public: - FxCyanF(uint32_t baseChannel = 0); + FxCyanF(u32 baseChannel = 0); - bool addChannel(uint8_t gpio); + bool addChannel(u8 gpio, float initialValue = 0.0f); - void setPWM(uint8_t channel, float value); + void setPWM(u8 channel, float value); void setGammaCorrector(GammaCorrector gammaCorrector); - uint8_t getChannelCount(); + u8 getChannelCount(); - void setBaseChannel(uint16_t baseChannel); - uint16_t getBaseChannel(); + void setBaseChannel(u16 baseChannel); + u16 getBaseChannel(); - bool setFrequency(uint32_t frq_hz); - uint32_t getFrequency(); + bool setFrequency(u32 frq_hz); + u32 getFrequency(); - bool setResolution(uint8_t res_bits); - uint8_t getResolution(); + bool setResolution(u8 res_bits); + u8 getResolution(); - bool setFrqRes(uint32_t frq_hz, uint8_t res_bits); + bool setFrqRes(u32 frq_hz, u8 res_bits); void setPacketHandledCallback(PacketHandledCallback callback); - bool handleUnicast(const uint8_t* data, std::size_t length); - bool handleBroadcast(const uint8_t* data, std::size_t length); + bool handleUnicast(const u8* data, std::size_t length); + bool handleBroadcast(const u8* data, std::size_t length); void registerAtCyanBus(CyanBus::CyanBus& cyanBus); @@ -66,11 +77,11 @@ namespace SiliconTorch { private: - uint32_t frequency = 1000; // Hz - uint8_t resolution = 10; // bits + u32 frequency = 1000; // Hz + u8 resolution = 10; // bits - uint32_t baseChannel; - uint8_t channelsConfigured = 0; + u32 baseChannel; + u8 channelsConfigured = 0; Impl::PWMChannel** channels; @@ -87,7 +98,7 @@ namespace SiliconTorch { }; - bool configureFromNVS(FxCyanF& target); + FxCyanF* configureFromNVS(FxCyanF); - //} + } } diff --git a/CLC-qthing/SiliconTorch/FxCyanRGB8.cpp b/CLC-qthing/SiliconTorch/FxCyanRGB8.cpp index 24ba38e8568ea5af175ad13e85703de9cc1ecfdf..4351d6ba1060908e4e60e87313ea893f7c92d12a 100644 --- a/CLC-qthing/SiliconTorch/FxCyanRGB8.cpp +++ b/CLC-qthing/SiliconTorch/FxCyanRGB8.cpp @@ -3,7 +3,6 @@ // C++ system level #include <string> #include <cstring> // memset -#include <cinttypes> #include <algorithm> #include <functional> @@ -14,6 +13,7 @@ // project specific #include "FxVSync.hpp" #include "CyanBus.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include "" @@ -27,7 +27,7 @@ namespace SiliconTorch { const std::string HEADER("fxCyanRGB8"); - FxCyanRGB8::FxCyanRGB8(uint16_t leds, uint16_t startIdx) : leds(leds), startIdx(startIdx) { + FxCyanRGB8::FxCyanRGB8(u16 leds, u16 startIdx) : leds(leds), startIdx(startIdx) { buffer0 = new qthing::RGB[leds]; buffer1 = new qthing::RGB[leds]; @@ -39,7 +39,7 @@ namespace SiliconTorch { } - void FxCyanRGB8::handlePacket(uint8_t* buffer, std::size_t length) { + void FxCyanRGB8::handlePacket(u8* buffer, std::size_t length) { if (length < 3) { ESP_LOGE(HEADER.c_str(), "Wrong |buffer|[ %d ]: Must be greater than 2!", length); @@ -53,13 +53,13 @@ namespace SiliconTorch { Pixel* packetPx = reinterpret_cast<Pixel*>(buffer+2); - uint16_t packetPxs = (length - 2) / 3; - uint16_t packetStartIdx = (buffer[0] << 8) | buffer[1]; + u16 packetPxs = (length - 2) / 3; + u16 packetStartIdx = (buffer[0] << 8) | buffer[1]; if (packetStartIdx == startIdx) { - for (uint16_t px = 0; px < std::min(leds, packetPxs); px++) { + for (u16 px = 0; px < std::min(leds, packetPxs); px++) { buffer1[px].r = packetPx[px].r / 255.0f; buffer1[px].g = packetPx[px].g / 255.0f; buffer1[px].b = packetPx[px].b / 255.0f; @@ -67,9 +67,9 @@ namespace SiliconTorch { } else if(packetStartIdx > startIdx) { - uint16_t delta = packetStartIdx - startIdx; + u16 delta = packetStartIdx - startIdx; - for (uint16_t px = delta; px < std::min(leds, (uint16_t)(packetPxs + delta)); px++) { + for (u16 px = delta; px < std::min(leds, (u16)(packetPxs + delta)); px++) { buffer1[px].r = packetPx[px - delta].r / 255.0f; buffer1[px].g = packetPx[px - delta].g / 255.0f; buffer1[px].b = packetPx[px - delta].b / 255.0f; @@ -77,12 +77,12 @@ namespace SiliconTorch { } else if (packetStartIdx < startIdx) { - uint16_t delta = startIdx - packetStartIdx; + u16 delta = startIdx - packetStartIdx; // Packet does not contain any pixels for us if (packetPxs < delta) return; - for (uint16_t px = 0; px < std::min(leds, (uint16_t)(packetPxs - delta)); px++) { + for (u16 px = 0; px < std::min(leds, (u16)(packetPxs - delta)); px++) { buffer1[px].r = packetPx[px + delta].r / 255.0f; buffer1[px].g = packetPx[px + delta].g / 255.0f; buffer1[px].b = packetPx[px + delta].b / 255.0f; @@ -92,10 +92,10 @@ namespace SiliconTorch { void FxCyanRGB8::registerAtCyanBus(CyanBus::CyanBus& cyanBus) { - uint8_t headerLength = HEADER.length(); + u8 headerLength = HEADER.length(); cyanBus.packetCallback.add(HEADER, [&, headerLength](const SiliconTorch::CyanBus::PacketData& packet) { - this->handlePacket((uint8_t*)(packet.payload + headerLength), packet.length - headerLength); + this->handlePacket((u8*)(packet.payload + headerLength), packet.length - headerLength); }); FxVSync::registerAtCyanBus(cyanBus, [&]() { @@ -108,17 +108,17 @@ namespace SiliconTorch { if (!udpHandlerRegistered) { udpHandlerRegistered = true; - uint8_t headerLength = HEADER.length(); + u8 headerLength = HEADER.length(); qthing::addUDPPacketCallback(HEADER, [&, headerLength](qthing::udpPacket packet) { - this->handlePacket((uint8_t*)(packet.payload + headerLength), packet.length - headerLength); + this->handlePacket((u8*)(packet.payload + headerLength), packet.length - headerLength); requestBufferSwap(); }); } } // qthing::Animator - qthing::RGB FxCyanRGB8::render(uint16_t addr) { + qthing::RGB FxCyanRGB8::render(u16 addr) { if (addr < leds) { return buffer0[addr]; } else { @@ -142,7 +142,7 @@ namespace SiliconTorch { buffer0 = buffer1; buffer1 = tmp; - for (uint16_t px = 0; px < leds; px++){ + for (u16 px = 0; px < leds; px++){ buffer1[px].r = 0; buffer1[px].g = 0; buffer1[px].b = 0; diff --git a/CLC-qthing/SiliconTorch/FxCyanRGB8.hpp b/CLC-qthing/SiliconTorch/FxCyanRGB8.hpp index 4901f07a1d571ac3ecbb8729b8b87457ace88041..769543bdfc6bd0bcaf8b79d73332af2f7832f556 100644 --- a/CLC-qthing/SiliconTorch/FxCyanRGB8.hpp +++ b/CLC-qthing/SiliconTorch/FxCyanRGB8.hpp @@ -2,7 +2,6 @@ // C++ system level #include <string> -#include <cinttypes> #include <functional> // ESP32 specific @@ -11,6 +10,7 @@ // project specific #include "CyanBus.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff #include <qthing> @@ -22,16 +22,16 @@ namespace SiliconTorch { namespace FxCyanRGB8 { typedef struct __attribute__((__packed__)) { - uint8_t r; - uint8_t g; - uint8_t b; + u8 r; + u8 g; + u8 b; } Pixel; extern const std::string HEADER; class FxCyanRGB8 : public qthing::Animation<qthing::RGB> { public: - FxCyanRGB8(uint16_t leds, uint16_t startIdx = 0); + FxCyanRGB8(u16 leds, u16 startIdx = 0); void getAnimator(); @@ -42,11 +42,11 @@ namespace SiliconTorch { void registerUDPHandler(); // Strip the header before calling this function! - void handlePacket(uint8_t* buffer, std::size_t length); + void handlePacket(u8* buffer, std::size_t length); // qthing::Animator void step(); - qthing::RGB render(uint16_t addr); + qthing::RGB render(u16 addr); private: @@ -56,8 +56,8 @@ namespace SiliconTorch { bool swapRequested = false; bool udpHandlerRegistered = false; - uint16_t leds; - uint16_t startIdx; + u16 leds; + u16 startIdx; void swapBuffers(); diff --git a/CLC-qthing/SiliconTorch/FxPublish.cpp b/CLC-qthing/SiliconTorch/FxPublish.cpp index 99e8859c91cb1273e66db6eb4720eddc2f550b62..27680c1a9646878940969a45d291ceb11e052d63 100644 --- a/CLC-qthing/SiliconTorch/FxPublish.cpp +++ b/CLC-qthing/SiliconTorch/FxPublish.cpp @@ -4,7 +4,6 @@ #include <string> // #include <cstring> // memset, strncmp // #include <cstdlib> // TODO: is this for memcpy? -// #include <cinttypes> // #include <functional> // ESP32 specific @@ -12,6 +11,7 @@ // project specific #include "CyanBus.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff #include <qthing> diff --git a/CLC-qthing/SiliconTorch/FxVSync.cpp b/CLC-qthing/SiliconTorch/FxVSync.cpp index a536a6b0d2788eb2ab955e052cc004c9845d1e64..b1bb375041dbccb73faead3fd7fd7751f96cc62b 100644 --- a/CLC-qthing/SiliconTorch/FxVSync.cpp +++ b/CLC-qthing/SiliconTorch/FxVSync.cpp @@ -8,6 +8,8 @@ // project specific #include "CyanBus.hpp" +#include "SpiderLib/NumberTypes.hpp" + // qthing stuff // #include "" diff --git a/CLC-qthing/SiliconTorch/LambdaTask.cpp b/CLC-qthing/SiliconTorch/LambdaTask.cpp index 18a18f7a201ed1d79a86eee45ba37bd31a17da99..5d9fef945dd1380357ad3ed7cbe97bb3a89db1d9 100644 --- a/CLC-qthing/SiliconTorch/LambdaTask.cpp +++ b/CLC-qthing/SiliconTorch/LambdaTask.cpp @@ -1,8 +1,12 @@ #include "LambdaTask.hpp" +// ESP32 system level #include "freertos/FreeRTOS.h" #include "freertos/task.h" +// project specific +#include "SpiderLib/NumberTypes.hpp" + static void taskWrapper(void* body) { @@ -10,8 +14,8 @@ static void taskWrapper(void* body) { (*f)(); } -static uint16_t taskID = 0; -static uint16_t nextID() { +static u16 taskID = 0; +static u16 nextID() { return taskID++; // TODO: increment thread-safe! } @@ -23,7 +27,7 @@ SiliconTorch::Util::LambdaTask::LambdaTask(SiliconTorch::Util::Function0 body) : // TODO: allow other niceness than one // TODO: allow pinning to other cores than app CPU - uint8_t priority = 1; + u8 priority = 1; std::function<void()> _body = [&]() { this->body(); diff --git a/CLC-qthing/SiliconTorch/Metrics.cpp b/CLC-qthing/SiliconTorch/Metrics.cpp index 6372778c8d5e3d95a2cd3f8acc02b46e149c9e72..33ba042724047c73b6506e89d1148693c57c19be 100644 --- a/CLC-qthing/SiliconTorch/Metrics.cpp +++ b/CLC-qthing/SiliconTorch/Metrics.cpp @@ -1,5 +1,8 @@ #include "Metrics.hpp" +// C++ system level +#include <climits> + // ESP32 specific #include "freertos/FreeRTOS.h" // #include "freertos/semphr.h" @@ -14,12 +17,9 @@ // qthing stuff #include <qthing> -// C++ system level -#include <climits> -#include <cinttypes> - // project specific #include "../SpiderLib/SNTP.hpp" +#include "SpiderLib/NumberTypes.hpp" using namespace qthing; @@ -29,7 +29,7 @@ using json = nlohmann::json; static const char* TAG = "Metrics"; -static uint8_t nextTask = 0; +static u8 nextTask = 0; static void methodTaskWrapper(void* parameter) { std::function<void()>* f = (std::function<void()>*)parameter; (*f)(); @@ -40,8 +40,8 @@ namespace SiliconTorch { namespace Metrics { - uint32_t uptime_ms() { - return (uint32_t)(esp_timer_get_time() / 1000L); + u32 uptime_ms() { + return (u32)(esp_timer_get_time() / 1000L); } Metrics::Metrics(const std::string& nameSpace) : nameSpace(nameSpace) { @@ -63,7 +63,7 @@ namespace SiliconTorch { ESP_LOGI(TAG, "Found my birth timestamp[ %lld ]", this->birth); SpiderLib::SNTP::instance().registerTimeSyncHandler([&](){ - uint64_t now = (uint64_t)std::time(NULL); + u64 now = (u64)std::time(NULL); float age = (float)(now - this->birth); age /= 24.0f * 60.0f * 60.0f; @@ -73,7 +73,7 @@ namespace SiliconTorch { } else { SpiderLib::SNTP::instance().registerTimeSyncHandler([&](){ - this->birth = (uint64_t)std::time(NULL); + this->birth = (u64)std::time(NULL); esp_err_t err = nvs_set_u64(this->nvs, "birth", this->birth); @@ -149,7 +149,7 @@ namespace SiliconTorch { it->second->save(&this->nvs); - uint32_t now = uptime_ms(); + u32 now = uptime_ms(); lifeTime += now - lifeTimeSaved; lifeTimeSaved = now; @@ -172,7 +172,7 @@ namespace SiliconTorch { while (true) { - uint32_t now = uptime_ms(); + u32 now = uptime_ms(); if ((now - lastSaved ) / 1000 > saveInterval ) saveData(); if ((now - lastPublished) / 1000 > publishInterval) publishData(); @@ -194,7 +194,7 @@ namespace SiliconTorch { } - uint64_t Metrics::getCounterValue(const std::string& shortName) { + u64 Metrics::getCounterValue(const std::string& shortName) { auto result = counters.find(shortName); @@ -250,7 +250,7 @@ namespace SiliconTorch { } } - uint64_t CounterMetric::getValue() { + u64 CounterMetric::getValue() { return value; } @@ -272,23 +272,23 @@ namespace SiliconTorch { } // pre-increment - uint64_t& CounterMetric::CounterMetric::operator++() { + u64& CounterMetric::CounterMetric::operator++() { inc(); return value; } // pre-decrement - uint64_t& CounterMetric::CounterMetric::operator--() { + u64& CounterMetric::CounterMetric::operator--() { dec(); return value; } // post-increment - uint64_t CounterMetric::CounterMetric::operator++(int ignored) { - uint64_t out = value; inc(); return out; + u64 CounterMetric::CounterMetric::operator++(int ignored) { + u64 out = value; inc(); return out; } // post-decrement - uint64_t CounterMetric::CounterMetric::operator--(int ignored) { - uint64_t out = value; dec(); return out; + u64 CounterMetric::CounterMetric::operator--(int ignored) { + u64 out = value; dec(); return out; } } } diff --git a/CLC-qthing/SiliconTorch/Metrics.hpp b/CLC-qthing/SiliconTorch/Metrics.hpp index 7b00f4193445b81fcb6cca54e817a4578e43d792..e651959e65fe2d90f4fb27cf107b94669ed18715 100644 --- a/CLC-qthing/SiliconTorch/Metrics.hpp +++ b/CLC-qthing/SiliconTorch/Metrics.hpp @@ -9,6 +9,9 @@ // ESP32 specific #include "nvs.h" +// project specific +#include "SpiderLib/NumberTypes.hpp" + namespace SiliconTorch { @@ -17,7 +20,7 @@ namespace SiliconTorch { typedef std::function<void()> Incrementer; - uint32_t uptime_ms(); // rolls over after about 136 years + u32 uptime_ms(); // rolls over after about 136 years class CounterMetric { public: @@ -28,7 +31,7 @@ namespace SiliconTorch { bool dirty = false; - uint64_t getValue(); + u64 getValue(); void inc(); void dec(); @@ -37,15 +40,15 @@ namespace SiliconTorch { void save(nvs_handle_t* nvs); // saves only if enoughg time elapsed void forceSave(nvs_handle_t* nvs); // saves value immediately - uint64_t& operator++(); // pre-increment - uint64_t& operator--(); // pre-decrement + u64& operator++(); // pre-increment + u64& operator--(); // pre-decrement - uint64_t operator++(int); // post-increment - uint64_t operator--(int); // post-decrement + u64 operator++(int); // post-increment + u64 operator--(int); // post-decrement private: - uint64_t value = 0; + u64 value = 0; }; @@ -59,7 +62,7 @@ namespace SiliconTorch { * returns the actual value or 0 for unknown counters * also supports getting the special bootCnt, uptime and lifetime metrics */ - uint64_t getCounterValue(const std::string& shortName); + u64 getCounterValue(const std::string& shortName); Incrementer generateMetricIncrementer(const std::string& shortName); @@ -72,21 +75,21 @@ namespace SiliconTorch { private: - uint32_t saveInterval = 60*60; // seconds - uint32_t publishInterval = 60; // seconds + u32 saveInterval = 60*60; // seconds + u32 publishInterval = 60; // seconds - uint32_t lastSaved = uptime_ms(); // unix timestamp - uint32_t lastPublished = uptime_ms(); // unix timestamp + u32 lastSaved = uptime_ms(); // unix timestamp + u32 lastPublished = uptime_ms(); // unix timestamp - uint32_t tickPeriod = 3000; // milli seconds + u32 tickPeriod = 3000; // milli seconds - uint64_t lifeTime = 0; // milli seconds - uint64_t lifeTimeSaved = 0; // milli seconds + u64 lifeTime = 0; // milli seconds + u64 lifeTimeSaved = 0; // milli seconds - uint32_t bootCnt = 0; - uint32_t bootCntSaveUptime = 60; // seconds + u32 bootCnt = 0; + u32 bootCntSaveUptime = 60; // seconds - uint64_t birth = 0; // unix timestamp of first device activation + u64 birth = 0; // unix timestamp of first device activation void tickTask(); void saveBootCntTask(); diff --git a/CLC-qthing/SiliconTorch/NVSExplorer.cpp b/CLC-qthing/SiliconTorch/NVSExplorer.cpp index b3230b3989d1fb9154222539b228ec5371710ab7..65ffb10a1f00d89679333827d935cce78e2fcd32 100644 --- a/CLC-qthing/SiliconTorch/NVSExplorer.cpp +++ b/CLC-qthing/SiliconTorch/NVSExplorer.cpp @@ -1,23 +1,28 @@ -#include "CapMan.hpp" +#include "NVSExplorer.hpp" // C++ system level #include <set> -// #include <cstring> // memset, strncmp -// #include <cstdlib> // TODO: is this for memcpy? -#include <cinttypes> +#include <cmath> +#include <limits> // mix/max integer values; used for parsing network data +#include <vector> +#include <cstring> // memset, memcpy, strncmp +#include <cstdlib> // std::strtof and such… // #include <functional> // ESP32 specific #include "esp_log.h" #include "nvs_flash.h" -// #include "esp_err.h" +#include "esp_err.h" // #include "driver/uart.h" // project specific -// #include "" +#include <Types.hpp> +#include <SpiderLib/Util.hpp> // qthing stuff -// #include <qthing> +#include <qthing> +#include <qthing/mqtt_common.hpp> + @@ -26,12 +31,967 @@ namespace SiliconTorch { namespace NVSExplorer { - // NVSExplorer::NVSExplorer() { - void BullShit() { + const char* TAG = "NVSExplorer"; + + + NVSExplorer::NVSExplorer() { + + ESP_LOGI(TAG, "Starting NVSExplorer[📡]"); nvs_flash_init(); - ESP_LOGW("NVS", "Scanning 👀"); + + registerLambdas0(); + registerLambdas1(); + + } // end NVSExplorer()-ctor + + + + void NVSExplorer::registerLambdas0() { + + u16 deviceTopicLEN = requestTopic("").length(); + + auto wrapMessageHandler = [deviceTopicLEN](std::function<void(std::vector<str>&, qthing::multipart_message_t)> handler) { + return [handler, deviceTopicLEN](qthing::multipart_message_t msg) { + if (msg.length == msg.total_length && msg.offset == 0) { + + str localTopic(msg.topic.c_str() + deviceTopicLEN); + std::vector<str> topicParts = SpiderLib::Util::split(localTopic, '/'); + + handler(topicParts, msg); + } else { + ESP_LOGW(TAG, "Multipart messages are not supported atm. topic[ %s ]", msg.topic.c_str()); + } + }; + }; + + + + // TODO: publish error if NS not found…?! + qthing::add_binary_message_callback(requestTopic("ls/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + str delimiter = " "; + char* buffer = NULL; + + if (msg.length > 0) { + buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + delimiter = str(buffer); + } + + auto keys = listKeys(topic[1]); + str msgOut = SpiderLib::Util::join(keys, delimiter); + + qthing::publish_message(responseTopic(topic[1]), msgOut); + + if (buffer != NULL) delete buffer; + } )); + + + + qthing::add_binary_message_callback(requestTopic("ls"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + str delimiter = " "; + char* buffer = NULL; + + if (msg.length > 0) { + buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + delimiter = str(buffer); + } + + auto nameSpaces = listNamespaces(); + str msgOut = SpiderLib::Util::join(nameSpaces, delimiter); + + qthing::publish_message(responseTopic("ls"), msgOut); + + if (buffer != NULL) delete buffer; + } )); + + + + qthing::add_binary_message_callback(requestTopic("rm/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + this->rmKey(topic[1], topic[2]); + + // publish error…? + } )); + + + + qthing::add_binary_message_callback(requestTopic("get_float/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + float value = this->getFloat(topic[1], topic[2]); + + if (!std::isnan(value)) { + + char buffer[64]; + snprintf(buffer, 64, "%f", value); + + qthing::publish_message(responseTopic("get_float", topic[1], topic[2]), str(buffer)); + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving float[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + } )); + + + + qthing::add_binary_message_callback(requestTopic("get_double/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + double value = this->getDouble(topic[1], topic[2]); + + if (!std::isnan(value)) { + + char buffer[64]; + snprintf(buffer, 64, "%f", value); + + qthing::publish_message(responseTopic("get_double", topic[1], topic[2]), str(buffer)); + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving double[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + } )); + + + + qthing::add_binary_message_callback(requestTopic("set_float/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + float value = std::strtof(buffer, NULL); + + if ( this->setFloat(topic[1], topic[2], value) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to float[ %f ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to float[ %f ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + + // publish error…? + } )); + + + + qthing::add_binary_message_callback(requestTopic("set_double/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + double value = std::strtod(buffer, NULL); + + if ( this->setDouble(topic[1], topic[2], value) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to double[ %f ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to double[ %f ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + + // publish error…? + } )); + + + + qthing::add_binary_message_callback(requestTopic("get_u8/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + u8 value = 0; + if ( nvs_get_u8(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%d", value); + qthing::publish_message(responseTopic("get_u8", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving u8[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_u16/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + u16 value = 0; + if ( nvs_get_u16(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%d", value); + qthing::publish_message(responseTopic("get_u16", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving u16[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_u32/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + u32 value = 0; + if ( nvs_get_u32(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%d", value); + qthing::publish_message(responseTopic("get_u32", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving u32[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_u64/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + u64 value = 0; + if ( nvs_get_u64(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%lld", value); + qthing::publish_message(responseTopic("get_u64", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving u64[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_i8/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + i8 value = 0; + if ( nvs_get_i8(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%d", value); + qthing::publish_message(responseTopic("get_i8", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving i8[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_i16/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + i16 value = 0; + if ( nvs_get_i16(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%d", value); + qthing::publish_message(responseTopic("get_i16", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving i16[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_i32/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + i32 value = 0; + if ( nvs_get_i32(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%d", value); + qthing::publish_message(responseTopic("get_i32", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving i32[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_i64/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + nvs_handle_t nvs; + if ( nvs_open(topic[1].c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + i64 value = 0; + if ( nvs_get_i64(nvs, topic[2].c_str(), &value) == ESP_OK ) { + + char buffer[32]; + snprintf(buffer, 32, "%lld", value); + qthing::publish_message(responseTopic("get_i64", topic[1], topic[2]), str(buffer)); + + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving i64[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + nvs_close(nvs); + } + } )); + + + } + + + + void NVSExplorer::registerLambdas1() { + + u16 deviceTopicLEN = requestTopic("").length(); + + auto wrapMessageHandler = [deviceTopicLEN](std::function<void(std::vector<str>&, qthing::multipart_message_t)> handler) { + return [handler, deviceTopicLEN](qthing::multipart_message_t msg) { + if (msg.length == msg.total_length && msg.offset == 0) { + + str localTopic(msg.topic.c_str() + deviceTopicLEN); + std::vector<str> topicParts = SpiderLib::Util::split(localTopic, '/'); + + handler(topicParts, msg); + } else { + ESP_LOGW(TAG, "Multipart messages are not supported atm. topic[ %s ]", msg.topic.c_str()); + } + }; + }; + + + + qthing::add_binary_message_callback(requestTopic("set_u8/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + u64 value = std::strtoull(buffer, NULL, 10); + + const u8 u8_max = std::numeric_limits<u8>::max(); + if (value > u8_max) value = u8_max; + + if ( this->setU8(topic[1], topic[2], static_cast<u8>(value)) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to u8[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to u8[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("set_u16/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + u64 value = std::strtoull(buffer, NULL, 10); + + const u16 u16_max = std::numeric_limits<u16>::max(); + if (value > u16_max) value = u16_max; + + if ( this->setU16(topic[1], topic[2], static_cast<u16>(value)) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to u16[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to u16[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("set_u32/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + u64 value = std::strtoull(buffer, NULL, 10); + + const u32 u32_max = std::numeric_limits<u32>::max(); + if (value > u32_max) value = u32_max; + + if ( this->setU32(topic[1], topic[2], static_cast<u32>(value)) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to u32[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to u32[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("set_u64/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + u64 value = std::strtoull(buffer, NULL, 10); + + if ( this->setU64(topic[1], topic[2], value) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to u64[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to u64[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("set_i8/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + i64 value = std::strtoll(buffer, NULL, 10); + + const i8 i8_max = std::numeric_limits<i8>::max(); + const i8 i8_min = std::numeric_limits<i8>::lowest(); + + if (value > i8_max) value = i8_max; + if (value < i8_min) value = i8_min; + + if ( this->setI8(topic[1], topic[2], static_cast<i8>(value)) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to i8[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to i8[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("set_i16/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + i64 value = std::strtoll(buffer, NULL, 10); + + const i16 i16_max = std::numeric_limits<i16>::max(); + const i16 i16_min = std::numeric_limits<i16>::lowest(); + + if (value > i16_max) value = i16_max; + if (value < i16_min) value = i16_min; + + if ( this->setI16(topic[1], topic[2], static_cast<i16>(value)) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to i16[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to i16[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("set_i32/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + i64 value = std::strtoll(buffer, NULL, 10); + + const i32 i32_max = std::numeric_limits<i32>::max(); + const i32 i32_min = std::numeric_limits<i32>::lowest(); + + if (value > i32_max) value = i32_max; + if (value < i32_min) value = i32_min; + + if ( this->setI32(topic[1], topic[2], static_cast<i32>(value)) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to i32[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to i32[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("set_i64/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + + i64 value = std::strtoll(buffer, NULL, 10); + + if ( this->setI64(topic[1], topic[2], value) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to i64[ %lld ]", topic[1].c_str(), topic[2].c_str(), value); + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to i64[ %lld ] FAILED", topic[1].c_str(), topic[2].c_str(), value); + // publish error…? + } )); + + + + qthing::add_binary_message_callback(requestTopic("get_strLen/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + size_t testValue = 1337000; // way too big for NVS + size_t length = getStringLength(topic[1], topic[2], testValue); + + if (length < testValue) { // key exists and is of type string + + char buffer[32]; + std::snprintf(&buffer[0], 32, "%d", length); + + str value(&buffer[0]); + qthing::publish_message(responseTopic("get_strLen", topic[1], topic[2]), value); + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving |str|[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("get_str/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + size_t testValue = 1337000; // way too big for NVS + + if ( getStringLength(topic[1], topic[2], testValue) < testValue ) { // key exists and is of type string + + str value = getString(topic[1], topic[2]); + + qthing::publish_message(responseTopic("get_str", topic[1], topic[2]), value); + } else { + // publish error…? + + ESP_LOGW(TAG, "Retrieving str[] from namespace[ %s ] key[ %s ] FAILED", topic[1].c_str(), topic[2].c_str()); + } + } )); + + + qthing::add_binary_message_callback(requestTopic("set_str/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + + char* buffer = new char[msg.length + 1]; + snprintf(buffer, msg.length + 1, "%s", msg.payload); + str value(buffer); + + if ( this->setString(topic[1], topic[2], value) ) + ESP_LOGI(TAG, "Set namespace[ %s ] key[ %s ] to str[ %s ]", topic[1].c_str(), topic[2].c_str(), value.c_str()); // TODO: do we REALLY wanna log the payloads?! + else ESP_LOGW(TAG, "Setting namespace[ %s ] key[ %s ] to str[ %s ] FAILED", topic[1].c_str(), topic[2].c_str(), value.c_str()); // TODO: do we REALLY wanna log the payloads?! + // publish error…? + } )); + + + qthing::add_binary_message_callback(requestTopic("get_type/+/+"), wrapMessageHandler( + [&](std::vector<str>& topic, qthing::multipart_message_t msg) { + qthing::publish_message(responseTopic("get_type", topic[1], topic[2]), getTypeStr(topic[1], topic[2])); + } )); + + + } + + + + u8 NVSExplorer::getU8(const str& nameSpace, const str& key, u8 defaultValue) { + + u8 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_u8(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + u16 NVSExplorer::getU16(const str& nameSpace, const str& key, u16 defaultValue) { + + u16 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_u16(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + u32 NVSExplorer::getU32(const str& nameSpace, const str& key, u32 defaultValue) { + + u32 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_u32(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + u64 NVSExplorer::getU64(const str& nameSpace, const str& key, u64 defaultValue) { + + u64 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_u64(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + i8 NVSExplorer::getI8(const str& nameSpace, const str& key, i8 defaultValue) { + + i8 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_i8(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + i16 NVSExplorer::getI16(const str& nameSpace, const str& key, i16 defaultValue) { + + i16 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_i16(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + i32 NVSExplorer::getI32(const str& nameSpace, const str& key, i32 defaultValue) { + + i32 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_i32(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + i64 NVSExplorer::getI64(const str& nameSpace, const str& key, i64 defaultValue) { + + i64 value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_i64(nvs, key.c_str(), &value); + nvs_close(nvs); + } + + return value; + } + + + + bool NVSExplorer::setU8(const str& nameSpace, const str& key, u8 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_u8(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setU16(const str& nameSpace, const str& key, u16 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_u16(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setU32(const str& nameSpace, const str& key, u32 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_u32(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setU64(const str& nameSpace, const str& key, u64 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_u64(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setI8(const str& nameSpace, const str& key, i8 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_i8(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setI16(const str& nameSpace, const str& key, i16 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_i16(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setI32(const str& nameSpace, const str& key, i32 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_i32(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setI64(const str& nameSpace, const str& key, i64 value) { + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_i64(nvs, key.c_str(), value) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + + + float NVSExplorer::getFloat(const str& nameSpace, const str& key) { + + float value = std::nanf("1337"); + u32* valptr = reinterpret_cast<u32*>(&value); + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_u32(nvs, key.c_str(), valptr); + nvs_close(nvs); + } + + return value; + } + + double NVSExplorer::getDouble(const str& nameSpace, const str& key) { + + double value = std::nan("1337"); + u64* valptr = reinterpret_cast<u64*>(&value); + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_u64(nvs, key.c_str(), valptr); + nvs_close(nvs); + } + + return value; + } + + + bool NVSExplorer::setFloat(const str& nameSpace, const str& key, float value) { + + bool success = true; + u32 intval = reinterpret_cast<u32*>(&value)[0]; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_u32(nvs, key.c_str(), intval) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + bool NVSExplorer::setDouble(const str& nameSpace, const str& key, double value) { + + bool success = true; + u64 intval = reinterpret_cast<u64*>(&value)[0]; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_u64(nvs, key.c_str(), intval) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + + size_t NVSExplorer::getStringLength(const str& nameSpace, const str& key, size_t defaultValue) { + + size_t value = defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + nvs_get_str(nvs, key.c_str(), NULL, &value); + nvs_close(nvs); + } + + return value; + } + + + str NVSExplorer::getString(const str& nameSpace, const str& key, const str& defaultValue) { + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) == ESP_OK ) { + + size_t size; + if ( nvs_get_str(nvs, key.c_str(), NULL, &size) == ESP_OK ) { + + char buffer[size + 1]; + std::memset(&buffer[0], 0x00, size + 1); + + nvs_get_str(nvs, key.c_str(), &buffer[0], &size); + + nvs_close(nvs); + + str out(&buffer[0]); + return out; + } + } + + return defaultValue; + } + + + bool NVSExplorer::setString(const str& nameSpace, const str& key, const str& value) { + + bool success = true; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READWRITE, &nvs) == ESP_OK ) { + success &= nvs_set_str(nvs, key.c_str(), value.c_str()) == ESP_OK; + success &= nvs_commit(nvs) == ESP_OK; + nvs_close(nvs); + + return success; + } else { + return false; + } + } + + + + void NVSExplorer::rmKey(const str& nameSpace, const str& key) { + nvs_handle_t _nvs; + ESP_LOGW(TAG, "rmKey() -> %s / %s", nameSpace.c_str(), key.c_str()); + ESP_LOGW(TAG, "open() -> %s", esp_err_to_name( nvs_open(nameSpace.c_str(), NVS_READWRITE, &_nvs) )); + ESP_LOGW(TAG, "erase() -> %s", esp_err_to_name( nvs_erase_key(_nvs, key.c_str()) )); + ESP_LOGW(TAG, "commit() -> %s", esp_err_to_name( nvs_commit(_nvs) )); + ESP_LOGW(TAG, "erase²() -> %s", esp_err_to_name( nvs_erase_key(_nvs, key.c_str()) )); + } + + std::set<str> NVSExplorer::listKeys(const str& nameSpace) { + + std::set<str> keys; + + nvs_iterator_t it = nvs_entry_find("nvs", nameSpace.c_str(), NVS_TYPE_ANY); + + while (it != NULL) { + nvs_entry_info_t info; + nvs_entry_info(it, &info); + it = nvs_entry_next(it); + + ESP_LOGW(TAG, "namespace[ %s ] key[ %s ] type[ %d ]", info.namespace_name, info.key, info.type); // TODO: remove after dev! + + keys.insert(info.key); + } + + return keys; + } + + std::set<str> NVSExplorer::listNamespaces() { + + std::set<str> namespaces; nvs_iterator_t it = nvs_entry_find("nvs", NULL, NVS_TYPE_ANY); @@ -40,22 +1000,216 @@ namespace SiliconTorch { nvs_entry_info(it, &info); it = nvs_entry_next(it); - ESP_LOGW("NVS", "namespace[ %s ] key[ %s ] type[ %d ]", info.namespace_name, info.key, info.type); + ESP_LOGW(TAG, "namespace[ %s ] key[ %s ] type[ %d ]", info.namespace_name, info.key, info.type); // TODO: remove after dev! + + namespaces.insert(info.namespace_name); + } + + return namespaces; + } + + + i64 NVSExplorer::getSignedInt(const str& nameSpace, const str& key, i64 defaultValue) { + + // Lets first test & evaluate the other function before duplication……… + + return -1337LL; + } + + + u64 NVSExplorer::getUnsignedInt(const str& nameSpace, const str& key, u64 defaultValue) { + + u64 value = defaultValue; + nvs_type_t entryType = NVS_TYPE_ANY; + + // search for the key to get its type + nvs_iterator_t it = nvs_entry_find("nvs", nameSpace.c_str(), NVS_TYPE_ANY); + + while (it != NULL) { + nvs_entry_info_t entry; + nvs_entry_info(it, &entry); + + if (key.compare(entry.key) == 0) { + entryType = entry.type; + nvs_release_iterator(it); + break; + } + + it = nvs_entry_next(it); + } + + if (entryType == NVS_TYPE_ANY) // key not found + return defaultValue; + + nvs_handle_t nvs; + if ( nvs_open(nameSpace.c_str(), NVS_READONLY, &nvs) != ESP_OK ) // namespace not found + return defaultValue; + + u64* valptr = &value; + switch (entryType) { + case NVS_TYPE_U8: { nvs_get_u8(nvs, key.c_str(), ( u8*)valptr); break; } + case NVS_TYPE_I8: { nvs_get_i8(nvs, key.c_str(), ( i8*)valptr); break; } + case NVS_TYPE_U16: { nvs_get_u16(nvs, key.c_str(), (u16*)valptr); break; } + case NVS_TYPE_I16: { nvs_get_i16(nvs, key.c_str(), ( i16*)valptr); break; } + case NVS_TYPE_U32: { nvs_get_u32(nvs, key.c_str(), (u32*)valptr); break; } + case NVS_TYPE_I32: { nvs_get_i32(nvs, key.c_str(), ( i32*)valptr); break; } + case NVS_TYPE_U64: { nvs_get_u64(nvs, key.c_str(), (u64*)valptr); break; } + case NVS_TYPE_I64: { nvs_get_i64(nvs, key.c_str(), ( i64*)valptr); break; } + default: {} + } + + nvs_close(nvs); + return value; + } + + + bool NVSExplorer::setSignedInt(const str& nameSpace, const str& key, i64 value, nvs_type_t entryType) { + + // TODO: implementation! + + return false; + } + + bool NVSExplorer::setUnsignedInt(const str& nameSpace, const str& key, u64 value, nvs_type_t entryType) { + + bool result = false; + + if (entryType == NVS_TYPE_ANY) { + + // check if key exists and grab its type + nvs_iterator_t it = nvs_entry_find("nvs", nameSpace.c_str(), NVS_TYPE_ANY); + + while (it != NULL) { + nvs_entry_info_t entry; + nvs_entry_info(it, &entry); + + if (key.compare(entry.key) == 0) { + entryType = entry.type; + nvs_release_iterator(it); + break; + } + + it = nvs_entry_next(it); + } + + // TODO: further implementation……? + + } else { + + } + + return result; + } + + + /** + * Converts IDF NVS types to strings + */ + str NVSExplorer::type2str(nvs_type_t typ) { + switch (typ) { + case NVS_TYPE_U8: return "u8"; + case NVS_TYPE_U16: return "u16"; + case NVS_TYPE_U32: return "u32"; + case NVS_TYPE_U64: return "u64"; + case NVS_TYPE_I8: return "i8"; + case NVS_TYPE_I16: return "i16"; + case NVS_TYPE_I32: return "i32"; + case NVS_TYPE_I64: return "i64"; + case NVS_TYPE_STR: return "str"; + case NVS_TYPE_BLOB: return "blob"; + default: return "any"; + } + } + + + /** + * Get the type of the entry, NVS_TYPE_ANY if not found + */ + nvs_type_t NVSExplorer::getType(const str& nameSpace, const str& key) { + + nvs_type_t entryType = NVS_TYPE_ANY; + + nvs_iterator_t it = nvs_entry_find("nvs", nameSpace.c_str(), NVS_TYPE_ANY); + + while (it != NULL) { + nvs_entry_info_t entry; + nvs_entry_info(it, &entry); + + if (key.compare(entry.key) == 0) { + entryType = entry.type; + nvs_release_iterator(it); + return entryType; + } + + it = nvs_entry_next(it); + } + + return entryType; + } + + /** + * Like getType but converts them to string + * non-existing keys are converted to `void` instead of `any` + */ + str NVSExplorer::getTypeStr(const str& nameSpace, const str& key) { + + bool entryFound = false; + nvs_type_t entryType = NVS_TYPE_ANY; + + nvs_iterator_t it = nvs_entry_find("nvs", nameSpace.c_str(), NVS_TYPE_ANY); + + while (it != NULL) { + nvs_entry_info_t entry; + nvs_entry_info(it, &entry); + + if (key.compare(entry.key) == 0) { + entryFound = true; + entryType = entry.type; + nvs_release_iterator(it); + break; + } + + it = nvs_entry_next(it); } + str typ; + + if (entryFound) typ = type2str(entryType); + else typ = "void"; + return typ; } - /* std::set<std::string> listKeys(std::string& _namespace) { + str NVSExplorer::deviceTopic(const str& suffix) { + return str(DEVICE_NAMESPACE + "NVS/") + suffix; + } + + str NVSExplorer::requestTopic(const str& cmd) { + return deviceTopic( str("rq/") + cmd ); } - std::set<std::string> listNamespaces() { - std::string _namespace = NULL; - return listKeys(_namespace); - } */ + str NVSExplorer::requestTopic(const str& cmd, const str& nameSpace) { + return deviceTopic( str("rq/") + cmd + str("/") + nameSpace ); + } + + str NVSExplorer::requestTopic(const str& cmd, const str& nameSpace, const str& key) { + return deviceTopic( str("rq/") + cmd + str("/") + nameSpace + str("/") + key ); + } + str NVSExplorer::responseTopic(const str& cmd) { + return deviceTopic( str("rs/") + cmd ); + } + + str NVSExplorer::responseTopic(const str& cmd, const str& nameSpace) { + return deviceTopic( str("rs/") + cmd + str("/") + nameSpace ); + } + + str NVSExplorer::responseTopic(const str& cmd, const str& nameSpace, const str& key) { + return deviceTopic( str("rs/") + cmd + str("/") + nameSpace + str("/") + key ); + } + } } diff --git a/CLC-qthing/SiliconTorch/NVSExplorer.hpp b/CLC-qthing/SiliconTorch/NVSExplorer.hpp index 6f0a9e2a8361b6c00bb215205d59db411436c27a..44bf20f10f103515a7db12bd2c5364393c0e84e6 100644 --- a/CLC-qthing/SiliconTorch/NVSExplorer.hpp +++ b/CLC-qthing/SiliconTorch/NVSExplorer.hpp @@ -1,19 +1,22 @@ #pragma once // C++ system level -// #include <cstring> // memset, strncmp +#include <set> +#include <cstring> // memset, strncmp // #include <cstdlib> // TODO: is this for memcpy? #include <cinttypes> // #include <functional> // ESP32 specific // #include "esp_err.h" +#include "nvs_flash.h" #include "esp_log.h" // #include "driver/gpio.h" // #include "driver/uart.h" // project specific -// #include "" +#include <Types.hpp> +// #include "SpiderLib/ManagedMutex.hpp" // qthing stuff // #include <qthing> @@ -24,22 +27,85 @@ namespace SiliconTorch { namespace NVSExplorer { - //class NVSExplorer { + extern const char* TAG; - //public: - //NVSExplorer(); + class NVSExplorer { - static void BullShit(); + public: + std::set<str> listNamespaces(); + std::set<str> listKeys(const str& nameSpace); - // std::set<std::string> listNamespaces(); - // std::set<std::string> listKeys(std::string& _namespace); + void rmKey(const str& nameSpace, const str& key); + bool setU8(const str& nameSpace, const str& key, u8 value); + bool setI8(const str& nameSpace, const str& key, i8 value); + + bool setU16(const str& nameSpace, const str& key, u16 value); + bool setI16(const str& nameSpace, const str& key, i16 value); + + bool setU32(const str& nameSpace, const str& key, u32 value); + bool setI32(const str& nameSpace, const str& key, i32 value); + + bool setU64(const str& nameSpace, const str& key, u64 value); + bool setI64(const str& nameSpace, const str& key, i64 value); + + + u8 getU8(const str& nameSpace, const str& key, u8 defaultValue = 0); + i8 getI8(const str& nameSpace, const str& key, i8 defaultValue = 0); + + u16 getU16(const str& nameSpace, const str& key, u16 defaultValue = 0); + i16 getI16(const str& nameSpace, const str& key, i16 defaultValue = 0); + + u32 getU32(const str& nameSpace, const str& key, u32 defaultValue = 0); + i32 getI32(const str& nameSpace, const str& key, i32 defaultValue = 0); + + u64 getU64(const str& nameSpace, const str& key, u64 defaultValue = 0); + i64 getI64(const str& nameSpace, const str& key, i64 defaultValue = 0); + + + float getFloat(const str& nameSpace, const str& key); + double getDouble(const str& nameSpace, const str& key); + + bool setFloat(const str& nameSpace, const str& key, float value); + bool setDouble(const str& nameSpace, const str& key, double value); + + // Gets the key regardless of its type in flash + i64 getSignedInt(const str& nameSpace, const str& key, i64 defaultValue = 0); + u64 getUnsignedInt(const str& nameSpace, const str& key, u64 defaultValue = 0); + + // TODO: ⮦ Both unimplemented atm â®§ + bool setSignedInt(const str& nameSpace, const str& key, i64 value, nvs_type_t entryType = NVS_TYPE_ANY); + bool setUnsignedInt(const str& nameSpace, const str& key, u64 value, nvs_type_t entryType = NVS_TYPE_ANY); + + + size_t getStringLength(const str& nameSpace, const str& key, size_t defaultValue = 0); + str getString(const str& nameSpace, const str& key, const str& defaultValue = ""); + // size_t getLongString(const str& nameSpace, const str& key, char* const buffer); + + bool setString(const str& nameSpace, const str& key, const str& value); + + + str type2str(nvs_type_t typ); + nvs_type_t getType(const str& nameSpace, const str& key); + str getTypeStr(const str& nameSpace, const str& key); + + + str deviceTopic(const str& suffix); + + str requestTopic(const str& cmd); + str requestTopic(const str& cmd, const str& nameSpace); + str requestTopic(const str& cmd, const str& nameSpace, const str& key); + + str responseTopic(const str& cmd); + str responseTopic(const str& cmd, const str& nameSpace); + str responseTopic(const str& cmd, const str& nameSpace, const str& key); + // ⬇⬇ Singleton stuff ⬇⬇ -/* static NVSExplorer& instance() { + static NVSExplorer& instance() { static NVSExplorer _instance; return _instance; } @@ -48,12 +114,16 @@ namespace SiliconTorch { void operator=(NVSExplorer const&) = delete; // ⬆⬆ Singleton stuff ⬆⬆ -*/ - //private: + private: + + void registerLambdas0(); + void registerLambdas1(); + + NVSExplorer(); + }; - //}; } } diff --git a/CLC-qthing/SiliconTorch/NVSExplorer.md b/CLC-qthing/SiliconTorch/NVSExplorer.md new file mode 100644 index 0000000000000000000000000000000000000000..0cf3f1392f14395b191fcb4e3c0fb6add48b52ba --- /dev/null +++ b/CLC-qthing/SiliconTorch/NVSExplorer.md @@ -0,0 +1,91 @@ +NVSExplorer +=========== + +A simple tool for exploring the `NVS` on `ESP32` platform through a high-level `C++` API. + +All API endpoints are also mapped to `MQTT` topics to provide a some kind of a remote administration toolkit for `ESP32` devices. + + +`MQTT` API +---------- + +`NVSExplorer` has its topics living inside the local `qthing` topic scheme. + +The base-topic thus is `device/<NAME>/NVS` where `<NAME>` is the device name. +This topic will further be referred to just as `BASE`, like in `BASE/cmd`. + +The request/response scheme doesn't follow the usual property ones as this would lead to publish loops. +Therefore we establish distinct request/response topics. + +- `request` topic: + `BASE/rq` + +- `response` topic: + `BASE/rs` (the `response`-topic *may* change in the future as I'm certainly unclear about it) + +This topics will further on be referred to as `REQUEST` and `RESPONSE`, as in `REQUEST/ls`. + + +### Commands + +The following commands are or will be supported by `NVSExplorer`. +As for the topic convention just swap `REQUEST` and `RESPONSE` to get your result. +Not all commands will publish a result, but there may be an `ERROR`-topic in the future to indicate failure or success of such commands. + +In the following list, `argument` stands for the message content received on the topic, `NS` and `KEY` denote the used namespace and key. + +- `ls` - **list namespaces** + **topic**: `REQUEST/ls` + **argument**: used as delimiter for concatenating the list (default: `' '`) + **description**: returns a list of the namespaces found in `NVS` + +- `ls` - **list keys** + **topic**: `REQUEST/ls/NS` + **argument**: used as delimiter for concatenating the list (default: `' '`) + **description**: returns a list of the keys found in namespace `NS` + +- `get` - **get generic value** + **topic**: `REQUEST/get/NS/KEY` + **description**: reads the value and returns it in its natural form + +- `get_type` - **get type of key** + **topic**: `REQUEST/get_type/NS/KEY` + **description**: reads the type and converts it to `string` + returns `void` in case of non-existing `key` + possible return values: `u8`, `u16`, `u32`, `u64`, `i8`, `i16`, `i32`, `i64`, `str`, `blob`, `any`, `void` + +- `get_raw` - **get generic value** + **topic**: `REQUEST/get_raw/NS/KEY` + **description**: returns the value in its binary form, for example `2 bytes` in case of `u16` + +- `get_<float|double>` - **get floating point value** + **topic**: `REQUEST/get_<float|double>/NS/KEY` + **description**: reads the value, `reinterpret_cast`s it to `float` or `double` and returns it converted to `string` + +- `set_<float|double>` - **get floating point value** + **topic**: `REQUEST/get_<float|double>/NS/KEY` + **argument**: the value to set + **description**: converts the value from `string` to floating point; `reinterpret_cast`s it to `u32` or `u64` and write it to the `key` + +- `get_<u8|i8|u16|i16|u32|i32|u64|i64>` - **get integer value** (`signed` and `unsigned`) + **topic**: `REQUEST/get_<u8|i8|u16|i16|u32|i32|u64|i64>/NS/KEY` + **description**: reads the value, and returns it converted to `string` + +- `set_<u8|i8|u16|i16|u32|i32|u64|i64>` - **set integer value** (`signed` and `unsigned`) + **topic**: `REQUEST/set_<u8|i8|u16|i16|u32|i32|u64|i64>/NS/KEY` + **argument**: the value to set + **description**: converts the message from `string` to `int` and writes it into the `key`; the value is capped to the bounds of the specified type, e.g. `[0, 128]` in case of `set_u8` + +- `get_str` - **get string value** + **topic**: `REQUEST/get_str/NS/KEY` + **description**: returns the stored `string` value + +- `get_strlen` - **get string length** + **topic**: `REQUEST/get_strlen/NS/KEY` + **description**: returns the length of a stored `string` value + + + +### Types + +#### TODO diff --git a/CLC-qthing/SiliconTorch/PWMChannel.cpp b/CLC-qthing/SiliconTorch/PWMChannel.cpp index e00bf3353549d616183c739ca067d2060b488edf..bb25bacf8ec07bc20afb2346e0284ef7dd3d8b65 100644 --- a/CLC-qthing/SiliconTorch/PWMChannel.cpp +++ b/CLC-qthing/SiliconTorch/PWMChannel.cpp @@ -4,9 +4,13 @@ #include "driver/gpio.h" #include "driver/ledc.h" +// project specific +#include "SpiderLib/NumberTypes.hpp" -SiliconTorch::Impl::PWMChannel::PWMChannel(uint8_t channel, uint8_t gpio) : channel{(ledc_channel_t)channel} { + + +SiliconTorch::Impl::PWMChannel::PWMChannel(u8 channel, u8 gpio) : channel{(ledc_channel_t)channel} { gpio_config_t conf; @@ -35,13 +39,13 @@ SiliconTorch::Impl::PWMChannel::PWMChannel(uint8_t channel, uint8_t gpio) : chan this->setPWM(0); } -void SiliconTorch::Impl::PWMChannel::setPWM(uint32_t pwm) { +void SiliconTorch::Impl::PWMChannel::setPWM(u32 pwm) { ledc_set_duty(LEDC_HIGH_SPEED_MODE, this->channel, pwm); ledc_update_duty(LEDC_HIGH_SPEED_MODE, this->channel); this->pwm = pwm; } -uint32_t SiliconTorch::Impl::PWMChannel::getPWM() { +u32 SiliconTorch::Impl::PWMChannel::getPWM() { return this->pwm; } diff --git a/CLC-qthing/SiliconTorch/PWMChannel.hpp b/CLC-qthing/SiliconTorch/PWMChannel.hpp index 420213d312225e34da64f756dde9a18ac390f533..6154fa4dbe1777653befca19d2e07243c7b6d808 100644 --- a/CLC-qthing/SiliconTorch/PWMChannel.hpp +++ b/CLC-qthing/SiliconTorch/PWMChannel.hpp @@ -3,6 +3,9 @@ // ESP32 specific #include "driver/ledc.h" +// project specific +#include "SpiderLib/NumberTypes.hpp" + namespace SiliconTorch { @@ -10,13 +13,13 @@ namespace SiliconTorch { class PWMChannel { public: - PWMChannel(uint8_t channel, uint8_t gpio); + PWMChannel(u8 channel, u8 gpio); - uint32_t getPWM(); - void setPWM(uint32_t pwm); + u32 getPWM(); + void setPWM(u32 pwm); private: - uint32_t pwm = 0; + u32 pwm = 0; ledc_channel_t channel; }; diff --git a/CLC-qthing/SiliconTorch/RS485.cpp b/CLC-qthing/SiliconTorch/RS485.cpp index c4fd6e9c7353b24a8832bf7fc5e2af5065e02683..805b30a81eba4671df91982317e266ec9491cd26 100644 --- a/CLC-qthing/SiliconTorch/RS485.cpp +++ b/CLC-qthing/SiliconTorch/RS485.cpp @@ -1,7 +1,7 @@ #include "RS485.hpp" // C++ system level -#include <cinttypes> +// #include <functional> // ESP32 specific #include "esp_log.h" @@ -9,7 +9,7 @@ #include "driver/uart.h" // project specific -// #include "LambdaTask.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include "" @@ -21,7 +21,7 @@ static const char* TAG = "RS485"; // This leads to ~54 P/s @ 2 MBaud at 100% load // TODO: Make configurable?! -const uint32_t CyanBusMTU = 4096; +const u32 CyanBusMTU = 4096; namespace SiliconTorch { @@ -29,9 +29,9 @@ namespace SiliconTorch { namespace Impl { - RS485::RS485(uint8_t tx, uint8_t rx, uint8_t de, uint8_t re, uint32_t baudRate, uint8_t uartChannel) : tx(tx), rx(rx), de(de), re(re), uartChannel(uartChannel) { + RS485::RS485(u8 tx, u8 rx, u8 de, u8 re, u32 baudRate, u8 uartChannel) : tx(tx), rx(rx), de(de), re(re), uartChannel(uartChannel) { - uint64_t bitMask = 0; + u64 bitMask = 0; bitMask |= 1 << tx; bitMask |= 1 << de; @@ -82,8 +82,8 @@ namespace SiliconTorch { } - void RS485::write(const uint8_t* data, uint32_t length) { - uint32_t send = uart_write_bytes((uart_port_t)uartChannel, reinterpret_cast<const char*>(data), length); + void RS485::write(const u8* data, u32 length) { + u32 send = uart_write_bytes((uart_port_t)uartChannel, reinterpret_cast<const char*>(data), length); // TODO: remove after change! ESP_LOGE(TAG, "This class is receive-only atm! TX won't work!"); @@ -92,7 +92,7 @@ namespace SiliconTorch { } void RS485::write(std::string& data) { - uint32_t send = uart_write_bytes((uart_port_t)uartChannel, data.c_str(), data.length()); + u32 send = uart_write_bytes((uart_port_t)uartChannel, data.c_str(), data.length()); // TODO: remove after change! ESP_LOGE(TAG, "This class is receive-only atm! TX won't work!"); @@ -101,24 +101,24 @@ namespace SiliconTorch { } // returns the real amount of data read - uint32_t RS485::read(uint8_t* data, uint32_t length) { + u32 RS485::read(u8* data, u32 length) { return uart_read_bytes((uart_port_t)uartChannel, data, length, 0); // TODO: ticks…??? } - uint32_t RS485::available() { + u32 RS485::available() { size_t tmp; uart_get_buffered_data_len((uart_port_t)uartChannel, &tmp); - return (uint32_t)tmp; + return (u32)tmp; } - void RS485::setBaudRate(uint32_t baudRate) { + void RS485::setBaudRate(u32 baudRate) { uart_set_baudrate((uart_port_t)uartChannel, baudRate); } - uint32_t RS485::getBaudRate() { - uint32_t baudRate = 0; + u32 RS485::getBaudRate() { + u32 baudRate = 0; uart_get_baudrate((uart_port_t)uartChannel, &baudRate); return baudRate; } diff --git a/CLC-qthing/SiliconTorch/RS485.hpp b/CLC-qthing/SiliconTorch/RS485.hpp index 74a2918eb91a2e9ae7f108adaf736a5f3c14ed55..e691c2930cccb39a2461d2459ec48a3dd6327e86 100644 --- a/CLC-qthing/SiliconTorch/RS485.hpp +++ b/CLC-qthing/SiliconTorch/RS485.hpp @@ -2,9 +2,10 @@ // C++ system level #include <string> -#include <cinttypes> #include <functional> +// project specific +#include "SpiderLib/NumberTypes.hpp" namespace SiliconTorch { @@ -13,18 +14,18 @@ namespace SiliconTorch { class RS485 { public: - RS485(uint8_t tx, uint8_t rx, uint8_t de, uint8_t re, uint32_t baudRate = 115200, uint8_t uartChannel = 1); + RS485(u8 tx, u8 rx, u8 de, u8 re, u32 baudRate = 115200, u8 uartChannel = 1); - uint32_t getBaudRate(); - void setBaudRate(uint32_t baudRate); + u32 getBaudRate(); + void setBaudRate(u32 baudRate); - uint32_t available(); - uint32_t read(uint8_t* data, uint32_t length); + u32 available(); + u32 read(u8* data, u32 length); private: - uint8_t uartChannel; - uint8_t tx, rx, de, re; + u8 uartChannel; + u8 tx, rx, de, re; void txEN(bool state); void rxEN(bool state); @@ -32,7 +33,7 @@ namespace SiliconTorch { // Receive only ATM! void write(std::string& data); - void write(const uint8_t* data, uint32_t length); + void write(const u8* data, u32 length); }; } diff --git a/CLC-qthing/SiliconTorch/SiliconTorch.cpp b/CLC-qthing/SiliconTorch/SiliconTorch.cpp index 1b61ff1f22b7c5a6e32ab4dc3d5722c4def7eda2..857f2e190175c95fea726aa57061635b3b007711 100644 --- a/CLC-qthing/SiliconTorch/SiliconTorch.cpp +++ b/CLC-qthing/SiliconTorch/SiliconTorch.cpp @@ -3,7 +3,6 @@ // C++ system level #include <cstring> // memset, strncmp #include <cstdlib> // TODO: is this for memcpy? -#include <cinttypes> #include <functional> // ESP32 specific @@ -19,6 +18,7 @@ #include "LambdaTask.hpp" #include "SpiderLib/Callback.hpp" #include "SpiderLib/CallbackMap.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include "" diff --git a/CLC-qthing/SiliconTorch/SiliconTorch.hpp b/CLC-qthing/SiliconTorch/SiliconTorch.hpp index 866578a7f8639d12f1957dbeea63358f4fff23b2..65b693fd0ad3d55c257ab2866a2e9794a36bb052 100644 --- a/CLC-qthing/SiliconTorch/SiliconTorch.hpp +++ b/CLC-qthing/SiliconTorch/SiliconTorch.hpp @@ -2,7 +2,6 @@ // C++ system level #include <string> -#include <cinttypes> #include <functional> // ESP32 specific @@ -13,6 +12,7 @@ #include "LambdaTask.hpp" #include "SpiderLib/Callback.hpp" #include "SpiderLib/CallbackMap.hpp" +#include "SpiderLib/NumberTypes.hpp" // qthing stuff // #include "" diff --git a/CLC-qthing/SimpleUART.hpp b/CLC-qthing/SimpleUART.hpp index 8ffd2d851b9e26649534d22c9ec172e6351cc447..3d108cce211bc725d9499994e03b711091e3eec4 100644 --- a/CLC-qthing/SimpleUART.hpp +++ b/CLC-qthing/SimpleUART.hpp @@ -1,6 +1,6 @@ #pragma once -#include <cinttypes> +#include "SpiderLib/NumberTypes.hpp" diff --git a/CLC-qthing/SpiderLib/Callback.hpp b/CLC-qthing/SpiderLib/Callback.hpp index d637e17ebdbddbd71eebc99e4386a90cfddee855..561ec8f8bccb0ec80308ad704eec14637eba4413 100644 --- a/CLC-qthing/SpiderLib/Callback.hpp +++ b/CLC-qthing/SpiderLib/Callback.hpp @@ -3,7 +3,6 @@ // C++ system level // #include <cstring> // memset, strncmp // #include <cstdlib> // TODO: is this for memcpy? -// #include <cinttypes> #include <functional> // ESP32 specific diff --git a/CLC-qthing/SpiderLib/CallbackMap.hpp b/CLC-qthing/SpiderLib/CallbackMap.hpp index afe772858868f80d92412f630399989bf10cbbf0..6dfed5c3e4ef3f5786b698694eec9af64a22f3c5 100644 --- a/CLC-qthing/SpiderLib/CallbackMap.hpp +++ b/CLC-qthing/SpiderLib/CallbackMap.hpp @@ -10,7 +10,8 @@ // #include "esp_log.h" // project specific -// #include "CyanBusCRC.hpp" +#include "SpiderLib/NumberTypes.hpp" + // qthing stuff // #include "" @@ -29,26 +30,26 @@ namespace SpiderLib { public: typedef std::function<void(Args...)> CallbackF; - CallbackMap(uint32_t maxPrefixLength = 16) : maxPrefixLength(maxPrefixLength) {}; + CallbackMap(u32 maxPrefixLength = 16) : maxPrefixLength(maxPrefixLength) {}; // Doesn't work with zero-length prefixes (callback won't be called but no error occurs) - void operator()(const uint8_t* const buffer, uint32_t length, Args&&... args) const { + void operator()(const u8* const buffer, u32 length, Args&&... args) const { - uint32_t _len = std::min(maxPrefixLength, length); + u32 _len = std::min(maxPrefixLength, length); char _prefix[_len + 1]; _prefix[_len] = 0x00; std::memcpy(_prefix, buffer, _len); std::string prefix(_prefix); - uint32_t bestMatchLEN = 0; + u32 bestMatchLEN = 0; CallbackF callback = NULL; for (auto it = callbackMap.begin(); it != callbackMap.end(); ++it) { // input buffer is >= current iterators magic string length if (_len >= it->first.length() && prefix.find(it->first) == 0) { - uint32_t matchLEN = it->first.length(); + u32 matchLEN = it->first.length(); if (matchLEN > bestMatchLEN) { bestMatchLEN = it->first.length(); callback = it->second; @@ -81,7 +82,7 @@ namespace SpiderLib { } private: - uint32_t maxPrefixLength; + u32 maxPrefixLength; mutable std::map<std::string, CallbackF> callbackMap; }; diff --git a/CLC-qthing/SpiderLib/ManagedMutex.hpp b/CLC-qthing/SpiderLib/ManagedMutex.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c95160c98fc49e51f12edc5824889cf14c69a978 --- /dev/null +++ b/CLC-qthing/SpiderLib/ManagedMutex.hpp @@ -0,0 +1,55 @@ +#pragma once + +// C++ system level +#include <functional> + +// ESP32 specific +#include "esp_log.h" +#include "FreeRTOS.h" +#include "freertos/semphr.h" + +// project specific +// #include <SpiderLib/Util.hpp> + + +namespace SpiderLib { + + class ManagedMutex { + + public: + ManagedMutex() { + + semphr = xSemaphoreCreateBinary(); + + if (semphr == NULL) { + ESP_LOGE("ManagedMutex", "Memory allocation FAILED"); + abort(); + } + + xSemaphoreGive(semphr); + } + + void run(std::function<void()> body) { + + xSemaphoreTake(semphr, portMAX_DELAY); + body(); + xSemaphoreGive(semphr); + } + + template<typename T> + T runReturn(std::function<T()> body) { + + xSemaphoreTake(semphr, portMAX_DELAY); + T result = body(); + xSemaphoreGive(semphr); + + return result; + } + + private: + + SemaphoreHandle_t semphr; + + }; + +} diff --git a/CLC-qthing/SpiderLib/NumberTypes.hpp b/CLC-qthing/SpiderLib/NumberTypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0cd1cd713491b120ea1658d776dfc6527c2dc244 --- /dev/null +++ b/CLC-qthing/SpiderLib/NumberTypes.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include <cinttypes> + + +using u8 = uint8_t; +using i8 = int8_t; + +using u16 = uint16_t; +using i16 = int16_t; + +using u32 = uint32_t; +using i32 = int32_t; + +using u64 = uint64_t; +using i64 = int64_t; + +using f32 = float; +using f64 = double; +using f128 = long double; diff --git a/CLC-qthing/SpiderLib/ObjectTypes.hpp b/CLC-qthing/SpiderLib/ObjectTypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a9a2ddb4e7a831fed8ced69814260feb6242af31 --- /dev/null +++ b/CLC-qthing/SpiderLib/ObjectTypes.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include <string> + + + +using str = std::string; + + +// TODO: more useful types…? diff --git a/CLC-qthing/SpiderLib/SNTP.cpp b/CLC-qthing/SpiderLib/SNTP.cpp index 575ae2942ee59ab3c1b2df1ba6a58466ee46857d..9fa644f1ea5d4413f269819289c65c574ce01371 100644 --- a/CLC-qthing/SpiderLib/SNTP.cpp +++ b/CLC-qthing/SpiderLib/SNTP.cpp @@ -12,10 +12,9 @@ #include <ctime> #include <cstring> #include <functional> -#include <cinttypes> // project specific -// #include "Metrics.hpp" +#include "SpiderLib/NumberTypes.hpp" /*extern "C" { diff --git a/CLC-qthing/SpiderLib/SNTP.hpp b/CLC-qthing/SpiderLib/SNTP.hpp index 2dc7d0d075de3a0c5b370b71190b39a69fc3e6a9..517e6b88bcc9b350f4796d9162515156d8417557 100644 --- a/CLC-qthing/SpiderLib/SNTP.hpp +++ b/CLC-qthing/SpiderLib/SNTP.hpp @@ -4,11 +4,10 @@ // #include "driver/ledc.h" // C++ system level -// #include <cinttypes> #include <functional> // project specific -// #include "Metrics.hpp" +// #include "SpiderLib/NumberTypes.hpp" namespace SpiderLib { diff --git a/CLC-qthing/SpiderLib/SpiderLib.hpp b/CLC-qthing/SpiderLib/SpiderLib.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8aa62588f5002f01a8ef263cd12c562f1cbc6bae --- /dev/null +++ b/CLC-qthing/SpiderLib/SpiderLib.hpp @@ -0,0 +1,17 @@ +#pragma once + + +// â•”â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•— +// â•‘ Conglomerate-Header for SpiderLib â•‘ +// ╚â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• + + +#include <SpiderLib/UDP.hpp> +#include <SpiderLib/SNTP.hpp> +#include <SpiderLib/Time.hpp> +#include <SpiderLib/Util.hpp> +#include <SpiderLib/Callback.hpp> +#include <SpiderLib/CallbackMap.hpp> +#include <SpiderLib/NumberTypes.hpp> +#include <SpiderLib/ObjectTypes.hpp> +#include <SpiderLib/ManagedMutex.hpp> diff --git a/CLC-qthing/SpiderLib/Time.cpp b/CLC-qthing/SpiderLib/Time.cpp index f1785a6dfa00c0955dbaf64823572e7129e77f80..4b71702ce0b0b143a73664967b7e846d467cf783 100644 --- a/CLC-qthing/SpiderLib/Time.cpp +++ b/CLC-qthing/SpiderLib/Time.cpp @@ -4,17 +4,17 @@ #include "esp_timer.h" // C++ system level -#include <cinttypes> +// #include <functional> // project specific -// #include "MyHeader.hpp" +#include "SpiderLib/NumberTypes.hpp" namespace SpiderLib { - uint32_t Time::s() { return (uint32_t)(esp_timer_get_time() / 1000000ULL); } - uint64_t Time::ms() { return (uint64_t)(esp_timer_get_time() / 1000ULL); } - uint64_t Time::us() { return (uint64_t) esp_timer_get_time(); } + u32 Time::s() { return (u32)(esp_timer_get_time() / 1000000ULL); } + u64 Time::ms() { return (u64)(esp_timer_get_time() / 1000ULL); } + u64 Time::us() { return (u64) esp_timer_get_time(); } } diff --git a/CLC-qthing/SpiderLib/Time.hpp b/CLC-qthing/SpiderLib/Time.hpp index 9ada8dcbd1099552de1aaa1fd5ad28a0559fca5d..ae4f78f1bd1439695d8ac29a95d08274ff083063 100644 --- a/CLC-qthing/SpiderLib/Time.hpp +++ b/CLC-qthing/SpiderLib/Time.hpp @@ -4,10 +4,10 @@ // #include "MyHeader.h" // C++ system level -#include <cinttypes> +// #include <functional> // project specific -// #include "MyHeader.hpp" +#include "SpiderLib/NumberTypes.hpp" namespace SpiderLib { @@ -15,9 +15,9 @@ namespace SpiderLib { class Time { public: - static uint32_t s(); - static uint64_t ms(); - static uint64_t us(); + static u32 s(); + static u64 ms(); + static u64 us(); }; } diff --git a/CLC-qthing/SpiderLib/Types.hpp b/CLC-qthing/SpiderLib/Types.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f183fbf4fb5486e8a628d8579b964f7060fd6592 --- /dev/null +++ b/CLC-qthing/SpiderLib/Types.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include <NumberTypes.hpp> +#include <ObjectTypes.hpp> diff --git a/CLC-qthing/SpiderLib/UDP.cpp b/CLC-qthing/SpiderLib/UDP.cpp index 4f4e7f31cd6641161cdd8ce53f4449c0b3b6ed6f..e63be3d0a7b60eb388ac5341c11bab9be74108d3 100644 --- a/CLC-qthing/SpiderLib/UDP.cpp +++ b/CLC-qthing/SpiderLib/UDP.cpp @@ -11,13 +11,15 @@ #include "lwip/sockets.h" #include "lwip/sys.h" +#include "SpiderLib/NumberTypes.hpp" + static const char* TAG = "udp-server"; static const in_port_t PORT = 4213; // rate-limits positive udp log messages; time in milliseconds -static const uint16_t loggingTimeout = 500; // TODO: make configurable?! +static const u16 loggingTimeout = 500; // TODO: make configurable?! static std::map<std::string, qthing::udpPacketCallback> packetCallbackMap; @@ -66,9 +68,9 @@ static void udp_server_task(void* pvParameters) { ESP_LOGI(TAG, "Waiting for data"); // This is for the rate limited logging only - uint32_t loggingBytes = 0; - uint16_t loggingPackets = 0; - uint32_t loggingLastMillis = qthing::millis(); + u32 loggingBytes = 0; + u16 loggingPackets = 0; + u32 loggingLastMillis = qthing::millis(); while (true) { struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6 @@ -102,7 +104,7 @@ static void udp_server_task(void* pvParameters) { } std::string payload_str(rx_buffer); - int16_t lenBestMatch = -1; + i16 lenBestMatch = -1; qthing::udpPacketCallback callback = NULL; for (auto it = packetCallbackMap.begin(); it != packetCallbackMap.end(); ++it) { if (len >= it->first.length() && payload_str.find(it->first) == 0) { @@ -112,7 +114,7 @@ static void udp_server_task(void* pvParameters) { } if (lenBestMatch > -1) { - qthing::udpPacket packet = {.sourceAddr = sourceAddr, .payload = rx_buffer, .length = (uint16_t)len}; + qthing::udpPacket packet = {.sourceAddr = sourceAddr, .payload = rx_buffer, .length = (u16)len}; callback(packet); } else { diff --git a/CLC-qthing/SpiderLib/UDP.hpp b/CLC-qthing/SpiderLib/UDP.hpp index 40e3bb9e9c7c9c600b6be13761d8487c59c0f3cf..29ce42102127904b1c41bdf73dc7073eeb112a30 100644 --- a/CLC-qthing/SpiderLib/UDP.hpp +++ b/CLC-qthing/SpiderLib/UDP.hpp @@ -1,5 +1,7 @@ #pragma once +#include "SpiderLib/NumberTypes.hpp" + /* diff --git a/CLC-qthing/SpiderLib/Util.hpp b/CLC-qthing/SpiderLib/Util.hpp index 3acace6f7961a2dfbdb210e89c2a15b1f614b84e..050321ac5c0ef0aba5ae573a1a6bf862d6fbbf95 100644 --- a/CLC-qthing/SpiderLib/Util.hpp +++ b/CLC-qthing/SpiderLib/Util.hpp @@ -6,10 +6,10 @@ // C++ system level #include <vector> #include <string> -#include <cinttypes> +#include <cstring> // project specific -// #include "MyHeader.hpp" +#include "SpiderLib/NumberTypes.hpp" namespace SpiderLib { @@ -18,5 +18,43 @@ namespace SpiderLib { std::vector<std::string> split(const std::string& s, char delim); + + template< template<typename> typename T> + std::string join(T<std::string>& collection, const std::string& delimiter) { + + u32 length = 0; + + // caching this temporarily + // TODO: do we need this or would the compiler be smart enough to cache it itself? + // or couldn't he cache it itself because C++ is strict and it is a method-call? + // questions over questions……… + u32 delimiterLength = delimiter.length(); + + for (auto const& item : collection) length += item.length() + delimiterLength; // TODO: replace delimiterLength -> delimiter.length() ? + + + length++; + char str[length]; + char* ptr = str; + std::memset(str, 0x00, length); + + for (auto const& item : collection) { + + u32 len = item.length(); + + std::memcpy(ptr, item.c_str(), len); + ptr += len; + + std::memcpy(ptr, delimiter.c_str(), delimiterLength); + ptr += delimiterLength; + } + + ptr -= delimiterLength; + std::memset(ptr, 0x00, delimiterLength); // clear out the trailing delimiter + + return std::string(str); + } + + } } diff --git a/CLC-qthing/device_config.h b/CLC-qthing/device_config.h index c8ce0fb631620be58343d945e3bc64e0c47af617..41978b1eedd446b4fd95b93ffe764a51999bc075 100644 --- a/CLC-qthing/device_config.h +++ b/CLC-qthing/device_config.h @@ -1,5 +1,5 @@ // hostname and device namespace -#define DEVICE_NAME "CLC-Drucker" +#define DEVICE_NAME "CLC" #define NTP_SERVER "pool.ntp.org" diff --git a/CLC-qthing/device_main.cpp b/CLC-qthing/device_main.cpp index 0bd8b40b9222467b16a9530014b873b222618917..054ba95dad7b1787860166d66c231518e524db24 100644 --- a/CLC-qthing/device_main.cpp +++ b/CLC-qthing/device_main.cpp @@ -8,12 +8,15 @@ #include "CyanLight.hpp" +#include "SiliconTorch/FxCyanF.hpp" + +#include "SpiderLib/NumberTypes.hpp" // ### LIBS FOR TESTING ### #include <cstdlib> //#include "SpiderLib/SNTP.hpp" -// #include "SpiderLib/Util.hpp" +#include "SpiderLib/Util.hpp" #include "SiliconTorch/CyanBus.hpp" @@ -25,10 +28,16 @@ //#include "SiliconTorch/FxPublish.hpp" + +#include "SiliconTorch/NVSExplorer.hpp" +#include <set> // remove after NVSExplorer development! + // ### END LIBS ### +#include <algorithm> + SiliconTorch::CyanBus::CyanBus* cyanBus = NULL; @@ -40,16 +49,9 @@ CyanLight::CyanLightControl* ctrl; -#include "SiliconTorch/NVSExplorer.hpp" - void device_main() { - - //SiliconTorch::NVSExplorer::BullShit(); - -//return; - qthing::Config cfg; // Needed for packet parsing, animation rendering and stuff @@ -58,7 +60,6 @@ void device_main() { - //cyanBus = new SiliconTorch::CyanBus::CyanBus(13, 14, 12, 15, 2000000); // Pinout of CyanStripe @@ -79,22 +80,41 @@ void device_main() { // TODO: ??? + // Trigger singleton initialization + SiliconTorch::NVSExplorer::NVSExplorer::instance(); + + + //std::set<std::string> namespaces = SiliconTorch::NVSExplorer::NVSExplorer::instance().listNamespaces(); + + //std::string _ns = SiliconTorch::NVSExplorer::toString(namespaces, " ~=[]=~ "); + + //ESP_LOGW("__SET__", "Listing Namespaces: %s", _ns.c_str()); + + + + ctrl = new CyanLight::CyanLightControl(0); + + // auto fxCyanF = (SiliconTorch::FxCyanF::FxCyanF) *ctrl; + // SiliconTorch::FxCyanF::configureFromNVS(fxCyanF); + qthing::enable_wifi(); - cfg.apply(); + return; - //return; - - + + // ############################# + // ### CLC-Drucker init code ### + // ############################# + + +/* ctrl = new CyanLight::CyanLightControl(3); - //ctrl->addChannel(16); - //ctrl->addChannel(17); ctrl->setFrqRes(100, 19); - for (uint8_t i = 0; i < 100; i++) { + for (u8 i = 0; i < 100; i++) { bool _f = i % 2 == 0; @@ -111,7 +131,17 @@ void device_main() { qthing::enable_wifi(); + cfg.apply(); + return; +*/ + + + // ### end CLC-Drucker ### + // ############################# + + + @@ -119,13 +149,13 @@ void device_main() { float limit = 50.0f; while (true) { - for (uint8_t i = 0; i < limit; i++) { + for (u8 i = 0; i < limit; i++) { float pwm = i / limit; ctrl->setPWM(0, pwm*pwm); vTaskDelay(delay); } - for (uint8_t i = 0; i < limit; i++) { + for (u8 i = 0; i < limit; i++) { float pwm = i / limit; ctrl->setPWM(0, 1.0f - pwm*pwm); vTaskDelay(delay); diff --git a/README.md b/README.md index 82f8280dbf8b5e8662bb382c71c39b804b818c89..00616da77b71ef4b214554c3bd7cb96f2a17dc87 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,33 @@ CyanLight ========= -Simple `PT4115`-BreakoutBoard, initially designed for my special 490 nm LED but may also be used for generic projects +Evolved from a "Simple `PT4115`-BreakoutBoard" we now have a full blown electronics and software project! -If you want to know more about `CyanBus`, `CyanLight`'s new animation protocol suite on top of `RS485` just goto [the documentation of SiliconTorch](SiliconTorch/README.md) ! +`CyanLight` now stands for the complete light and animation system which I'm developing for my appartement. -Pinout ------- +It consists of multiple hardware and software layers with a possible full stack-up looking like this from the bottom upwards: -Pinout of the companion board `CyanLightControl`. All external general purpose IOs are protected against ESD and negative reverse voltage input. +- `CyanLight v[10W].1` - `PT4115` board (LED current control) +- `CyanLightControl` - `ESP32` board outputting some `PWM` signals +- `SiliconTorch[C++]` - `ESP32` firmware implementing protocols like `CyanBus` and `FxCyanF` +- `CyanBus` - `RS485` serial protocol for packetized data streaming +- `FxCyanF` - `LED` animation protocol +- `CyanBusInjector` - `Ethernet` to `CyanBus` bridging board +- `SiliconTorch[PY]` - High-Level device control via `Python` -| GPIO | Function | -|-----:|----------------:| -| 27 | `PT4115` DIM | -| 23 | IR recv | -| 25 | general purpose | -| 26 | general purpose | -| 32 | general purpose | -| 33 | general purpose | +The last mentioned layer would then run on some SBC in a drawer and do the animation rendering. But what if this is not the end? +Big things are on the way! Source-less animation building coming soonâ„¢! -Component selection -------------------- - -### Current sensing resistor `Rs` - -| I_LED | Rs | P | Min PKG | -|------:|:-------:|------:|--------:| -| 0.1 A | 1.000 Ω | 10 mW | 0201 | -| 0.2 A | 0.500 Ω | 20 mW | 0201 | -| 0.3A | 0.333 Ω | 30 mW | 0201 | -| 0.4 A | 0.250 Ω | 40 mW | 0201 | -| 0.5 A | 0.200 Ω | 50 mW | 0201 | -| 0.6 A | 0.167 Ω | 60 mW | 0402 | -| 0.7 A | 0.143 Ω | 70 mW | 0603 | -| 0.8 A | 0.125 Ω | 80 mW | 0603 | -| 0.9 A | 0.111 Ω | 90 mW | 0603 | -| 1.0 A | 0.100 Ω |100 mW | 0603 | -| 1.1 A | 0.091 Ω |110 mW | 0805 | -| 1.2 A | 0.083 Ω |120 mW | 0805 | - - -### Inductor `I` - -| I_LED | L | -|------------------:|------------:| -| I > 1 A | 27 - 47 µH | -| 0.8 A < I ≤ 1 A | 33 - 82 µH | -| 0.4 A < I ≤ 0.8 A | 47 - 100 µH | -| I ≤ 0.4 A | 68 - 220 µH | `CyanLight` PCBs ---------------- -### `10W` - -Designed for the quadratic standard 10W LED modules. Running from at least 12V input voltage. - - - - -### `HexPCB` - -Designed for the standard 3W single-chip high power LEDs. Running from 12V - 24V depending of LED's forward voltage. -May be populated with up to 6 individual LEDs and contains `0805` footprints to bridge unpopulated LEDs with 0Ω resistors. +Section moved to the [PCB README file](/pcb/README.md) - - -### `CyanLightControl` - -`ESP32` powered companion board for `CyanLight`. - -Contains 3.3 V buck regulator for effiecency and an experimental IR receiver. -Mates directly with the LED boards for power and PWM signal connection via `Micropart-4` connector. - - - - -`fxCyanF` aka `CyanLight`s network protocol ----------------------------------------------- +`FxCyanF` aka `CyanLight`s network protocol +-------------------------------------------- ### Introduction @@ -89,12 +37,13 @@ Both protocols share the same basic concept: Time critical animation data is sen ### General Architecture -`fxCyanF` constists of the following protocols: +`FxCyanF` constists of the following protocols: - `MQTT` for configuration als device status - animation data *may* be sent over `MQTT` too, but this is only recommended for very slow animations or setting of a constant mood in your living room - `UDP` for animation data -- `IrDA` for animation data (implementation pending!) +- `CyanBus` (`RS485`) for animation data +- ~~`IrDA` for animation data~~ ### The `MQTT` protocol @@ -107,6 +56,11 @@ Both protocols share the same basic concept: Time critical animation data is sen **[TODO!]** +### The `CyanBus` protocol stack + +**[TODO!]** + + ### ~~The `IrDA` protocol~~ There won't be any `IrDA` as R&D discovered the following problems: diff --git a/cad/CyanBusTransceiver/PCBSocket.scad b/cad/CyanBusTransceiver/PCBSocket.scad index ac4f6a39b5ad3c4e9f949062a6f9d158c7afe890..4ef1f76b51391daddbdccf4609d753ce3790bcbe 100644 --- a/cad/CyanBusTransceiver/PCBSocket.scad +++ b/cad/CyanBusTransceiver/PCBSocket.scad @@ -2,12 +2,118 @@ $fs = 0.35; $fa = 0.50; +$str = 3.0; // base strength +$str1 = 2.5; // strength for the smaller sides -nozzle = 0.4; +$eps = 0.01; // epsilon -pcb_w = 50.0 + nozzle; -pcb_h = 21.5 + nozzle; +tolerance = 0.4; -pcb_z_off = 11.6; // hieght of transceiver pcb above ground +pcb_w = 50.0 + tolerance; +pcb_h = 21.5 + tolerance; +pcb_str = 1.6; +pcb_z_off = 12.0; // height of transceiver pcb above ground +M2_outer = 6.5; // outer diameter for the M2 screw receptacles + + +// s = socket +s_h = 13; +s_w = pcb_w; + + +// sc = screw; here: the M2 holes of the PCB +sc_x = 8.25; +sc_y = 7.75; +sc_drill = 3.0; + + +// ph = PinHeader +ph_w = 7.5; // enough space for SMD PinHeaders +ph_led_x = 5.7; +ph_485_x = -1.9 - 1.27; +ph_led_l = 11.4 + 1.25; +ph_485_l = 16.5 + 1.25; + + + +module screwPlacement(tz=0) { + translate([ sc_x, -sc_y, tz]) children(); + translate([-sc_x, sc_y, tz]) children(); +} + + +module ph_led_placement() { + translate([ph_led_x, pcb_h/2 - $str/2, 0]) children(); +} + +module ph_485_placement() { + translate([ph_485_x, -pcb_h/2 + $str/2, 0]) children(); +} + + +module border(sy=pcb_z_off, sz=$str1, length=pcb_w, h=pcb_str) { + + translate([-length/2, 0, 0]) + rotate([0, 90, 0]) + linear_extrude(length) + polygon([ + [-h, 0], + [sy, 0], + [-h, sz], + ]); + +} + + + +module PCBSocket() { + + linear_extrude(pcb_z_off) difference() { + union() { + difference() { + square([pcb_w, pcb_h ], center=true); + square([pcb_w - 2*$str1, pcb_h - 2*$str], center=true); + } + + pll2 = ph_led_l + 2*$str; + translate([0, $str/2, 0]) + ph_led_placement() + translate([-pll2/2, -ph_w -0.2, 0]) + square([pll2, ph_w +0.2]); + + p4l2 = ph_485_l + 2*$str; + translate([0, -$str/2, 0]) + ph_485_placement() + translate([-p4l2/2, 0.2, 0]) + square([p4l2, ph_w +0.2]); + + screwPlacement() circle(d=M2_outer); + } + + ph_led_placement() square([ph_led_l, ph_w], center=true); + ph_485_placement() square([ph_485_l, ph_w], center=true); + + + screwPlacement() circle(d=sc_drill); + } + + + difference() { + union() { + translate([0, pcb_h/2 -$eps, pcb_z_off]) border(); + translate([0, -pcb_h/2 +$eps, pcb_z_off]) mirror([0, 1, 0]) border(); + } + + + ph_led_placement() cube([ph_led_l, 10, 100], center=true); + ph_485_placement() cube([ph_485_l, 10, 100], center=true); + + } + +} + + +PCBSocket(); + diff --git a/pcb/README.md b/pcb/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e65781db5e3ba927e21836fb72584173a4fecf5f --- /dev/null +++ b/pcb/README.md @@ -0,0 +1,84 @@ +CyanLight PCB Documentation +=========================== + +This `README` will give you a short introduction to the PCBs of this project + + +`CyanLightControl v1.1` +----------------------- + +`ESP32` powered companion board for `CyanLight`. + +Contains 3.3 V buck regulator for effiecency and an experimental IR receiver. +Mates directly with the LED boards for power and PWM signal connection via `Micropart-4` connector. + + + +There never was a `v1.0` of this board. + +### Pinout + +| GPIO | Function | +|-----:|----------------:| +| 27 | `PT4115` DIM | +| 23 | IR recv | +| 25 | general purpose | +| 26 | general purpose | +| 32 | general purpose | +| 33 | general purpose | + + +`CyanLight` LED PCBs +-------------------- + +Simple `PT4115`-BreakoutBoard, initially designed for my special 490 nm LED but may also be used for generic projects + +If you want to know more about `CyanBus`, `CyanLight`'s new animation protocol suite on top of `RS485` just goto [the documentation of SiliconTorch](/SiliconTorch/README.md) ! + + +### Component selection + +#### Current sensing resistor `Rs` + +| I_LED | Rs | P | Min PKG | +|------:|:-------:|------:|--------:| +| 0.1 A | 1.000 Ω | 10 mW | 0201 | +| 0.2 A | 0.500 Ω | 20 mW | 0201 | +| 0.3A | 0.333 Ω | 30 mW | 0201 | +| 0.4 A | 0.250 Ω | 40 mW | 0201 | +| 0.5 A | 0.200 Ω | 50 mW | 0201 | +| 0.6 A | 0.167 Ω | 60 mW | 0402 | +| 0.7 A | 0.143 Ω | 70 mW | 0603 | +| 0.8 A | 0.125 Ω | 80 mW | 0603 | +| 0.9 A | 0.111 Ω | 90 mW | 0603 | +| 1.0 A | 0.100 Ω |100 mW | 0603 | +| 1.1 A | 0.091 Ω |110 mW | 0805 | +| 1.2 A | 0.083 Ω |120 mW | 0805 | + + +#### Inductor `I` + +| I_LED | L | +|------------------:|------------:| +| I > 1 A | 27 - 47 µH | +| 0.8 A < I ≤ 1 A | 33 - 82 µH | +| 0.4 A < I ≤ 0.8 A | 47 - 100 µH | +| I ≤ 0.4 A | 68 - 220 µH | + +### `10W` + +Designed for the quadratic standard 10W LED modules. Running from at least 12V input voltage. + + + + +### `HexPCB` + +Designed for the standard 3W single-chip high power LEDs. Running from 12V - 24V depending of LED's forward voltage. +May be populated with up to 6 individual LEDs and contains `0805` footprints to bridge unpopulated LEDs with 0Ω resistors. + + + + + +## TODO: futher PCB doc!