From ec7b7f2510a9746daebe399bfb89177a93440c6e Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Fri, 29 Dec 2023 00:39:11 +0700 Subject: [PATCH] initial analog card OOP draft --- .../lib/ESPMegaPRO/AnalogCard.cpp | 51 ++++++ .../lib/ESPMegaPRO/AnalogCard.hpp | 10 + Template Project/lib/ESPMegaPRO/AnalogIoT.cpp | 172 ++++++++++++++++++ Template Project/lib/ESPMegaPRO/AnalogIoT.hpp | 45 ++++- .../lib/ESPMegaPRO/DigitalOutputIoT.cpp | 1 - 5 files changed, 273 insertions(+), 6 deletions(-) create mode 100644 Template Project/lib/ESPMegaPRO/AnalogIoT.cpp diff --git a/Template Project/lib/ESPMegaPRO/AnalogCard.cpp b/Template Project/lib/ESPMegaPRO/AnalogCard.cpp index 1569592..c22288b 100644 --- a/Template Project/lib/ESPMegaPRO/AnalogCard.cpp +++ b/Template Project/lib/ESPMegaPRO/AnalogCard.cpp @@ -10,6 +10,47 @@ AnalogCard::AnalogCard() : dac0(DAC0_ADDRESS), } void AnalogCard::dacWrite(uint8_t pin, uint16_t value) +{ + this->setDACState(pin, value > 0); + this->setDACValue(pin, value); +} + +void AnalogCard::setDACState(uint8_t pin, bool state) +{ + this->dac_state[pin] = state; + this->sendDataToDAC(pin, this->dac_value[pin]*state); + if (this->dac_change_callback != NULL) + { + this->dac_change_callback(pin, state, this->dac_value[pin]); + } +} + +void AnalogCard::setDACValue(uint8_t pin, uint16_t value) +{ + this->dac_value[pin] = value; + this->sendDataToDAC(pin, value*this->dac_state[pin]); + if (this->dac_change_callback != NULL) + { + this->dac_change_callback(pin, this->dac_state[pin], value); + } +} + +uint16_t AnalogCard::getDACValue(uint8_t pin) +{ + return this->dac_value[pin]; +} + +bool AnalogCard::getDACState(uint8_t pin) +{ + return this->dac_state[pin]; +} + +uint16_t AnalogCard::getDACValue(uint8_t pin) +{ + return this->dac_value[pin]; +} + +void AnalogCard::sendDataToDAC(uint8_t pin, uint16_t value) { switch (pin) { @@ -85,4 +126,14 @@ void AnalogCard::loop() uint8_t AnalogCard::getType() { return CARD_TYPE_ANALOG; +} + +void AnalogCard::registerDACChangeCallback(std::function callback) +{ + this->dac_change_callback = callback; +} + +void AnalogCard::deregisterDACChangeCallback() +{ + this->dac_change_callback = NULL; } \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/AnalogCard.hpp b/Template Project/lib/ESPMegaPRO/AnalogCard.hpp index d913326..6c38a35 100644 --- a/Template Project/lib/ESPMegaPRO/AnalogCard.hpp +++ b/Template Project/lib/ESPMegaPRO/AnalogCard.hpp @@ -16,11 +16,21 @@ class AnalogCard : public ExpansionCard { public: AnalogCard(); void dacWrite(uint8_t pin, uint16_t value); + void sendDataToDAC(uint8_t pin, uint16_t value); uint16_t analogRead(uint8_t pin); bool begin(); void loop(); + bool getDACState(uint8_t pin); + uint16_t getDACValue(uint8_t pin); + void setDACState(uint8_t pin, bool state); + void setDACValue(uint8_t pin, uint16_t value); + void registerDACChangeCallback(std::function callback); + void deregisterDACChangeCallback(); uint8_t getType(); private: + std::function dac_change_callback; + bool dac_state[4]; + uint16_t dac_value[4]; MCP4725 dac0; MCP4725 dac1; MCP4725 dac2; diff --git a/Template Project/lib/ESPMegaPRO/AnalogIoT.cpp b/Template Project/lib/ESPMegaPRO/AnalogIoT.cpp new file mode 100644 index 0000000..00aad78 --- /dev/null +++ b/Template Project/lib/ESPMegaPRO/AnalogIoT.cpp @@ -0,0 +1,172 @@ +#include + +AnalogIoT::AnalogIoT() { + for (uint8_t i = 0; i < 8; i++) { + adc_publish_enabled[i] = false; + adc_conversion_interval[i] = 1000; + } +} + +AnalogIoT::~AnalogIoT() { +} +bool AnalogIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) { + this->mqtt = mqtt; + this->base_topic = base_topic; + this->card = (AnalogCard*)card; + this-> card_id = card_id; + this->dac_set_state_length = strlen(DAC_SET_STATE_TOPIC); + this->dac_set_value_length = strlen(DAC_SET_VALUE_TOPIC); + this->dac_state_length = strlen(DAC_STATE_TOPIC); + this->dac_value_length = strlen(DAC_VALUE_TOPIC); + this->request_state_length = strlen(REQUEST_STATE_TOPIC); + this->dac_publish_enable_length = strlen(DAC_PUBLISH_ENABLE_TOPIC); + // Register callbacks + auto bindedCallback = std::bind(&AnalogIoT::handleDACChange, this, std::placeholders::_1, std::placeholders::_2); + this->card->registerDACChangeCallback(bindedCallback); + return true; +} +void AnalogIoT::handleMqttMessage(char *topic, char *payload){ + uint8_t topic_length = strlen(topic); + if(this-> processDACSetStateMessage(topic, payload, topic_length)) return; + if(this-> processDACSetValueMessage(topic, payload, topic_length)) return; + if(this-> processRequestStateMessage(topic, payload, topic_length)) return; + if(this-> processADCSetConversionIntervalMessage(topic, payload, topic_length)) return; + if(this-> processADCSetConversionEnabledMessage(topic, payload, topic_length)) return; +} +void AnalogIoT::publishADCs() { + for (uint8_t i = 0; i < 8; i++) { + this->publishADC(i); + } +} +void AnalogIoT::publishADC(uint8_t pin) { + if (this->adc_publish_enabled[pin]) { + uint16_t value = this->card->analogRead(pin); + char *topic = new char[15]; + sprintf(topic, "adc/%02d/value", pin); + char *payload = new char[10]; + sprintf(payload, "%d", value); + this->publishRelative(topic, payload); + delete[] topic; + delete[] payload; + } +} +void AnalogIoT::setADCsPublishInterval(uint32_t interval) { + for (uint8_t i = 0; i < 8; i++) { + adc_conversion_interval[i] = interval; + } +} +void AnalogIoT::setADCsPublishEnabled(bool enabled) { + for (uint8_t i = 0; i < 8; i++) { + adc_publish_enabled[i] = enabled; + } +} +void AnalogIoT::registerDACChangeCallback(std::function callback) { + dac_change_callback = callback; +} +void AnalogIoT::deregisterDACChangeCallback() { + dac_change_callback = NULL; +} +void AnalogIoT::registerADCConversionCallback(std::function callback) { + adc_conversion_callback = callback; +} +void AnalogIoT::deregisterADCConversionCallback() { + adc_conversion_callback = NULL; +} +void AnalogIoT::setADCConversionInterval(uint8_t pin, uint16_t interval) { + adc_conversion_interval[pin] = interval; +} +void AnalogIoT::setADCConversionEnabled(uint8_t pin, bool enabled) { + adc_publish_enabled[pin] = enabled; +} +bool AnalogIoT::processADCSetConversionIntervalMessage(char *topic, char *payload, uint8_t topic_length) { + // TODO: publish all DACs and ADCs +} +bool AnalogIoT::processADCSetConversionEnabledMessage(char *topic, char *payload, uint8_t topic_length) { + // TODO: publish all DACs and ADCs +} +bool AnalogIoT::processDACSetStateMessage(char *topic, char *payload, uint8_t topic_length) { + // TODO: publish all DACs and ADCs +} +bool AnalogIoT::processDACSetValueMessage(char *topic, char *payload, uint8_t topic_length) { + // TODO: publish all DACs and ADCs +} +bool AnalogIoT::processRequestStateMessage(char *topic, char *payload, uint8_t topic_length) { + // TODO: publish all DACs and ADCs +} +void AnalogIoT::publishReport() { + // TODO: publish all DACs and ADCs +} +void AnalogIoT::subscribe() { + // There are 4 DACs and 8 ADCs + // DACs: dac/<%02d>/set/state, dac/<%02d>/set/value, dac/publish_enable + // ADCs: adc/<%02d>/set/conversion_interval, adc/<%02d>/set/conversion_enabled + + // Subscribe to all set state topics + char topic[20]; + for (uint8_t i = 0; i < 4; i++) { + sprintf(topic, "dac/%02d/set/state", i); + this->subscribeRelative(topic); + } + // Subscribe to all set value topics + for (uint8_t i = 0; i < 4; i++) { + sprintf(topic, "dac/%02d/set/value", i); + this->subscribeRelative(topic); + } + // Subscribe to all set conversion interval topics + for (uint8_t i = 0; i < 8; i++) { + sprintf(topic, "adc/%02d/set/conversion_interval", i); + this->subscribeRelative(topic); + } + // Subscribe to all set conversion enabled topics + for (uint8_t i = 0; i < 8; i++) { + sprintf(topic, "adc/%02d/set/conversion_enabled", i); + this->subscribeRelative(topic); + } + // Subscribe to publish enable topic + this->subscribeRelative("dac/publish_enable"); +} +void AnalogIoT::loop() { + // Iterate over all ADCs and publish if enabled and interval has passed + uint32_t now = millis(); + for (uint8_t i = 0; i < 8; i++) { + if (this->adc_publish_enabled[i] && now - this->last_adc_publish > this->adc_conversion_interval[i]) { + this->publishADC(i); + this->last_adc_publish = now; + } + } +} +void AnalogIoT::publishReport() { + publishADCs(); + publishDACs(); +} + +uint8_t AnalogIoT::getType() { + return CARD_TYPE_ANALOG; +} +void AnalogIoT::publishDACs() { + for (uint8_t i = 0; i < 4; i++) { + this->publishDAC(i); + } +} +void AnalogIoT::publishDAC(uint8_t pin) { + this->publishDACState(pin); + this->publishDACValue(pin); +} +void AnalogIoT::publishDACState(uint8_t pin) { + char *topic = new char[15]; + sprintf(topic, "dac/%02d/state", pin); + char *payload = new char[2]; + sprintf(payload, "%d", this->card->getDACState(pin)); + this->publishRelative(topic, payload); + delete[] topic; + delete[] payload; +} +void AnalogIoT::publishDACValue(uint8_t pin) { + char *topic = new char[15]; + sprintf(topic, "dac/%02d/value", pin); + char *payload = new char[5]; + sprintf(payload, "%d", this->card->getDACValue(pin)); + this->publishRelative(topic, payload); + delete[] topic; + delete[] payload; +} diff --git a/Template Project/lib/ESPMegaPRO/AnalogIoT.hpp b/Template Project/lib/ESPMegaPRO/AnalogIoT.hpp index 79fe92e..59d3501 100644 --- a/Template Project/lib/ESPMegaPRO/AnalogIoT.hpp +++ b/Template Project/lib/ESPMegaPRO/AnalogIoT.hpp @@ -1,23 +1,58 @@ #pragma once #include #include + +#define DAC_SET_STATE_TOPIC "/set/state" +#define DAC_SET_VALUE_TOPIC "/set/value" +#define DAC_STATE_TOPIC "/dac/00/state" +#define DAC_VALUE_TOPIC "/dac/00/value" +#define DAC_PUBLISH_ENABLE_TOPIC "/publish_enable" +#define REQUEST_STATE_TOPIC "requeststate" + class AnalogIoT : public IoTComponent { public: AnalogIoT(); ~AnalogIoT(); - bool begin(uint8_t card_id, AnalogCard *card, PubSubClient *mqtt, char *base_topic); + bool begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic); void handleMqttMessage(char *topic, char *payload); + void handleDACChange(uint8_t pin, uint16_t value); void publishADCs(); + void publishADC(uint8_t pin); + void publishDACs(); + void publishDAC(uint8_t pin); + void publishDACState(uint8_t pin); + void publishDACValue(uint8_t pin); void setADCsPublishInterval(uint32_t interval); void setADCsPublishEnabled(bool enabled); + void registerDACChangeCallback(std::function callback); + void deregisterDACChangeCallback(); + void registerADCConversionCallback(std::function callback); + void deregisterADCConversionCallback(); + void setADCConversionInterval(uint8_t pin, uint16_t interval); + void setADCConversionEnabled(uint8_t pin, bool enabled); + bool processADCSetConversionIntervalMessage(char *topic, char *payload, uint8_t topic_length); + bool processADCSetConversionEnabledMessage(char *topic, char *payload, uint8_t topic_length); + bool processDACSetStateMessage(char *topic, char *payload, uint8_t topic_length); + bool processDACSetValueMessage(char *topic, char *payload, uint8_t topic_length); + bool processRequestStateMessage(char *topic, char *payload, uint8_t topic_length); + void publishReport(); + void subscribe(); + void loop(); void publishReport(); void subscribe(); uint8_t getType(); private: - char *adc_topic; - char *dac_topic; - uint32_t adc_publish_interval = 1000; + uint8_t dac_set_state_length; + uint8_t dac_set_value_length; + uint8_t dac_state_length; + uint8_t dac_value_length; + uint8_t request_state_length; + uint8_t dac_publish_enable_length; uint32_t last_adc_publish = 0; - bool adc_publish_enabled = false; AnalogCard *card; + bool adc_publish_enabled[8]; + uint16_t adc_conversion_interval[8]; + uint32_t last_adc_conversion[8]; + std::function dac_change_callback; + std::function adc_conversion_callback; }; \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp b/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp index 0b120fa..f74eb61 100644 --- a/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp +++ b/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp @@ -15,7 +15,6 @@ bool DigitalOutputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient this->mqtt = mqtt; this->base_topic = base_topic; this->card = (DigitalOutputCard *) card; - if(!card->begin()) return false; this-> card_id = card_id; this->set_state_length = strlen(SET_STATE_TOPIC); this->set_value_length = strlen(SET_VALUE_TOPIC);