From 2d0d38ecf3b42ef4de78017d5559aa6ca74626eb Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sat, 30 Dec 2023 22:50:19 +0700 Subject: [PATCH] oop output card display binding --- .../lib/ESPMegaPRO/ESPMegaDisplay.cpp | 297 ++++++++++++------ .../lib/ESPMegaPRO/ESPMegaDisplay.hpp | 20 +- .../lib/ESPMegaPRO/ESPMegaPRO_OOP.cpp | 8 +- .../lib/ESPMegaPRO/InternalDisplay.cpp | 118 ++++++- .../lib/ESPMegaPRO/InternalDisplay.hpp | 34 +- ESPMegaPRO-firmware/platformio.ini | 2 +- 6 files changed, 355 insertions(+), 124 deletions(-) diff --git a/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.cpp b/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.cpp index 37e00c8..97023f5 100644 --- a/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.cpp +++ b/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.cpp @@ -5,17 +5,21 @@ * @param process Flag indicating whether to process the received commands. * @return True if data is received, false otherwise. */ -bool ESPMegaDisplay::recieveSerialCommand(bool process){ +bool ESPMegaDisplay::recieveSerialCommand(bool process) +{ bool dataRecieved = false; // Read the serial buffer if available - while(displayAdapter->available()) { + while (displayAdapter->available()) + { rx_buffer[rx_buffer_index] = displayAdapter->read(); rx_buffer_index++; // Check for overflow - if(rx_buffer_index>=256){ + if (rx_buffer_index >= 256) + { rx_buffer_index = 0; } - if(process) this-> processSerialCommand(); + if (process) + this->processSerialCommand(); dataRecieved = true; } return dataRecieved; @@ -25,16 +29,19 @@ bool ESPMegaDisplay::recieveSerialCommand(bool process){ * @brief Receives and processes serial commands from the display adapter. * @return True if data is received, false otherwise. */ -bool ESPMegaDisplay::recieveSerialCommand(){ +bool ESPMegaDisplay::recieveSerialCommand() +{ return recieveSerialCommand(true); } /** * @brief Processes the received serial command. */ -void ESPMegaDisplay::processSerialCommand(){ +void ESPMegaDisplay::processSerialCommand() +{ // Check if the rx buffer ended with stop bytes (0xFF 0xFF 0xFF) - if(!payloadIsValid()) return; + if (!payloadIsValid()) + return; // The rx buffer ended with stop bytes // Check if the rx buffer is a push payload // The payload type is the first byte of the payload @@ -42,19 +49,24 @@ void ESPMegaDisplay::processSerialCommand(){ // 0x01 is success // 0x65 is a touch event // 0x66 is a page report event - if(rx_buffer[0]==0x65){ + if (rx_buffer[0] == 0x65) + { processTouchPayload(); } - else if(rx_buffer[0]==0x66){ + else if (rx_buffer[0] == 0x66) + { processPageReportPayload(); } + this->rx_buffer_index = 0; } /** * @brief Processes the touch event payload. */ -void ESPMegaDisplay::processTouchPayload() { - if (rx_buffer_index != 4) return; +void ESPMegaDisplay::processTouchPayload() +{ + if (rx_buffer_index != 7) + return; // The second byte of the payload is the page number uint8_t page = rx_buffer[1]; // The third byte of the payload is the component id @@ -63,25 +75,33 @@ void ESPMegaDisplay::processTouchPayload() { uint8_t event = rx_buffer[3]; // 0x01 is press, 0x00 is release ESP_LOGV("ESPMegaDisplay", "Touch event: page=%d, component=%d, event=%d", page, component, event); + for (auto const &callback : touch_callbacks) + { + callback.second(page, component, event); + } } /** * @brief Processes the page report event payload. */ -void ESPMegaDisplay::processPageReportPayload() { +void ESPMegaDisplay::processPageReportPayload() +{ + if (rx_buffer_index != 5) + return; // The second byte of the payload is the page number this->currentPage = rx_buffer[1]; - if(pageChangeCallback!=NULL){ - pageChangeCallback(this->currentPage); - } - rx_buffer_index = 0; ESP_LOGV("ESPMegaDisplay", "Page change event: page=%d", this->currentPage); + for (auto const &callback : page_change_callbacks) + { + callback.second(this->currentPage); + } } /** * @brief Sends stop bytes to the display adapter. */ -void ESPMegaDisplay::sendStopBytes() { +void ESPMegaDisplay::sendStopBytes() +{ displayAdapter->write(0xFF); displayAdapter->write(0xFF); displayAdapter->write(0xFF); @@ -91,7 +111,8 @@ void ESPMegaDisplay::sendStopBytes() { * @brief Sends a command to the display adapter. * @param command The command to send. */ -void ESPMegaDisplay::sendCommand(char* command) { +void ESPMegaDisplay::sendCommand(char *command) +{ displayAdapter->print(command); sendStopBytes(); } @@ -100,7 +121,8 @@ void ESPMegaDisplay::sendCommand(char* command) { * @brief Jumps to the specified page on the display. * @param page The page number to jump to. */ -void ESPMegaDisplay::jumpToPage(int page) { +void ESPMegaDisplay::jumpToPage(int page) +{ this->displayAdapter->print("page "); this->displayAdapter->print(page); sendStopBytes(); @@ -111,7 +133,8 @@ void ESPMegaDisplay::jumpToPage(int page) { * @param component The component name. * @param value The value to set. */ -void ESPMegaDisplay::setNumber(const char* component, int value) { +void ESPMegaDisplay::setNumber(const char *component, int value) +{ this->displayAdapter->print(component); this->displayAdapter->print("="); this->displayAdapter->print(value); @@ -123,7 +146,8 @@ void ESPMegaDisplay::setNumber(const char* component, int value) { * @param component The component name. * @param value The value to set. */ -void ESPMegaDisplay::setString(const char* component, const char* value) { +void ESPMegaDisplay::setString(const char *component, const char *value) +{ this->displayAdapter->print(component); this->displayAdapter->print("=\""); this->displayAdapter->print(value); @@ -136,25 +160,53 @@ void ESPMegaDisplay::setString(const char* component, const char* value) { * @param component The component name. * @return The value of the number component. */ -uint32_t ESPMegaDisplay::getNumber(const char* component) { +uint32_t ESPMegaDisplay::getNumber(const char *component) +{ + // We might be in the middle of a serial command + // We reset the rx buffer index to 0 to ensure that we don't read the wrong data + this->rx_buffer_index = 0; uint32_t start = millis(); // Send the get command this->displayAdapter->print("get "); this->displayAdapter->print(component); sendStopBytes(); + // Try to get a valid payload DISPLAY_FETCH_RETRY_COUNT times // Wait for the response - if(!waitForValidPayload(DISPLAY_FETCH_TIMEOUT)) return 0; + bool validPayload = false; + for (int i = 0; i < DISPLAY_FETCH_RETRY_COUNT; i++) + { + if (!waitForValidPayload(DISPLAY_FETCH_TIMEOUT)) + { + ESP_LOGE("ESPMegaDisplay", "Timeout while waiting for display response"); + return 0; + } + if (rx_buffer[0] != 0x71) + { + ESP_LOGI("ESPMegaDisplay", "Invalid payload type: %d, retrying.", rx_buffer[0]); + // The rx buffer is invalid, reset the rx buffer index + rx_buffer_index = 0; + continue; + } else { + validPayload = true; + break; + } + } + if (!validPayload) { + ESP_LOGE("ESPMegaDisplay", "Invalid payload type: %d, max retry excceded.", rx_buffer[0]); + return 0; + } + // The rx buffer is valid // The expected payload is type 0x71 - if(rx_buffer[0]!=0x71) return 0; + // The 2nd to 5th byte of the payload is the value // It's a 4 byte 32-bit value in little endian order. // Convert the 4 bytes to a 32-bit value uint32_t value = 0; value |= rx_buffer[1]; - value |= rx_buffer[2]<<8; - value |= rx_buffer[3]<<16; - value |= rx_buffer[4]<<24; + value |= rx_buffer[2] << 8; + value |= rx_buffer[3] << 16; + value |= rx_buffer[4] << 24; return value; } @@ -164,48 +216,77 @@ uint32_t ESPMegaDisplay::getNumber(const char* component) { * @return The value of the string component. * @note The returned char array must be freed after use. */ -const char* ESPMegaDisplay::getString(const char* component) { +const char *ESPMegaDisplay::getString(const char *component) +{ + // We might be in the middle of a serial command + // We reset the rx buffer index to 0 to ensure that we don't read the wrong data + this->rx_buffer_index = 0; uint32_t start = millis(); // Send the get command this->displayAdapter->print("get "); this->displayAdapter->print(component); sendStopBytes(); // Wait for the response - if(!waitForValidPayload(DISPLAY_FETCH_TIMEOUT)) return ""; - // The rx buffer is valid - // The expected payload is type 0x70 - if(rx_buffer[0]!=0x70) return ""; + // Try to get a valid payload DISPLAY_FETCH_RETRY_COUNT times + // Wait for the response + bool validPayload = false; + for (int i = 0; i < DISPLAY_FETCH_RETRY_COUNT; i++) + { + if (!waitForValidPayload(DISPLAY_FETCH_TIMEOUT)) + { + ESP_LOGE("ESPMegaDisplay", "Timeout while waiting for display response"); + return 0; + } + if (rx_buffer[0] != 0x70) + { + ESP_LOGI("ESPMegaDisplay", "Invalid payload type: %d, retrying.", rx_buffer[0]); + // The rx buffer is invalid, reset the rx buffer index + rx_buffer_index = 0; + continue; + } else { + validPayload = true; + break; + } + } + if (!validPayload) { + ESP_LOGE("ESPMegaDisplay", "Invalid payload type: %d, max retry excceded.", rx_buffer[0]); + return 0; + } // The 2nd bytes onwards before the stop bytes is the string // The length of the string is the length of the payload minus 4 - uint8_t length = rx_buffer_index-4; + uint8_t length = rx_buffer_index - 4; // First we malloc a char array with the length of the string - char* value = (char*)malloc(length+1); + char *value = (char *)malloc(length + 1); // Copy the string from the rx buffer to the char array - memcpy(value, rx_buffer+1, length); + memcpy(value, rx_buffer + 1, length); // Add the null terminator value[length] = '\0'; // Return the char array return value; } -bool ESPMegaDisplay::getStringToBuffer(const char* component, char* buffer, uint8_t buffer_size) { +bool ESPMegaDisplay::getStringToBuffer(const char *component, char *buffer, uint8_t buffer_size) +{ uint32_t start = millis(); // Send the get command this->displayAdapter->print("get "); this->displayAdapter->print(component); sendStopBytes(); // Wait for the response - if(!waitForValidPayload(DISPLAY_FETCH_TIMEOUT)) return false; + if (!waitForValidPayload(DISPLAY_FETCH_TIMEOUT)) + return false; // The rx buffer is valid // The expected payload is type 0x70 - if(rx_buffer[0]!=0x70) return false; + if (rx_buffer[0] != 0x70) + return false; // The 2nd bytes onwards before the stop bytes is the string // The length of the string is the length of the payload minus 4 - uint8_t length = rx_buffer_index-4; + uint8_t length = rx_buffer_index - 4; // Check if the buffer is large enough to hold the string - if(length>buffer_size) return false; + if (length > buffer_size) + return false; // Copy the string from the rx buffer to the char array - memcpy(buffer, rx_buffer+1, length); + memcpy(buffer, rx_buffer + 1, length); // Add the null terminator buffer[length] = '\0'; return true; @@ -216,11 +297,14 @@ bool ESPMegaDisplay::getStringToBuffer(const char* component, char* buffer, uint * @param timeout The timeout value in milliseconds. * @return True if a valid payload is received, false otherwise. */ -bool ESPMegaDisplay::waitForValidPayload(uint32_t timeout) { +bool ESPMegaDisplay::waitForValidPayload(uint32_t timeout) +{ uint32_t start = millis(); // If the payload is not valid, keep reading the serial buffer until timeout - while(!this->payloadIsValid()){ - if(millis()-start>timeout){ + while (!this->payloadIsValid()) + { + if (millis() - start > timeout) + { return false; } recieveSerialCommand(false); @@ -232,12 +316,17 @@ bool ESPMegaDisplay::waitForValidPayload(uint32_t timeout) { * @brief Checks if the received payload is valid. * @return True if the payload is valid, false otherwise. */ -bool ESPMegaDisplay::payloadIsValid() { +bool ESPMegaDisplay::payloadIsValid() +{ // Check if the rx buffer ended with stop bytes (0xFF 0xFF 0xFF) - if(rx_buffer_index<3) return false; - if(rx_buffer[rx_buffer_index-1]!=0xFF) return false; - if(rx_buffer[rx_buffer_index-2]!=0xFF) return false; - if(rx_buffer[rx_buffer_index-3]!=0xFF) return false; + if (rx_buffer_index < 3) + return false; + if (rx_buffer[rx_buffer_index - 1] != 0xFF) + return false; + if (rx_buffer[rx_buffer_index - 2] != 0xFF) + return false; + if (rx_buffer[rx_buffer_index - 3] != 0xFF) + return false; return true; } @@ -245,7 +334,8 @@ bool ESPMegaDisplay::payloadIsValid() { * @brief Sets the brightness of the display. * @param value The brightness value. */ -void ESPMegaDisplay::setBrightness(int value) { +void ESPMegaDisplay::setBrightness(int value) +{ this->displayAdapter->print("dim="); this->displayAdapter->print(value); sendStopBytes(); @@ -255,7 +345,8 @@ void ESPMegaDisplay::setBrightness(int value) { * @brief Sets the volume of the display. * @param value The volume value. */ -void ESPMegaDisplay::setVolume(int value) { +void ESPMegaDisplay::setVolume(int value) +{ this->displayAdapter->print("vol="); this->displayAdapter->print(value); sendStopBytes(); @@ -264,7 +355,8 @@ void ESPMegaDisplay::setVolume(int value) { /** * @brief Restarts the display. */ -void ESPMegaDisplay::reset() { +void ESPMegaDisplay::reset() +{ // First we send a stop bytes to clear the serial buffer // This ensures that the display is ready to receive the reset command sendStopBytes(); @@ -272,68 +364,22 @@ void ESPMegaDisplay::reset() { sendStopBytes(); } -/** - * @brief Registers a callback function that will be called when a push event is received. - * @param callback The callback function. - */ -void ESPMegaDisplay::registerPushCallback(std::function callback) { - this->pushCallback = callback; -} - -/** - * @brief Registers a callback function that will be called when a pop event is received. - * @param callback The callback function. - */ -void ESPMegaDisplay::registerPopCallback(std::function callback) { - this->popCallback = callback; -} - -/** - * @brief Registers a callback function that will be called when a page change event is received. - * @param callback The callback function. - */ -void ESPMegaDisplay::registerPageChangeCallback(std::function callback) { - this->pageChangeCallback = callback; -} - -/** - * @brief Unregisters the push callback function. - */ -void ESPMegaDisplay::unregisterPushCallback() { - this->pushCallback = NULL; -} - -/** - * @brief Unregisters the pop callback function. - */ -void ESPMegaDisplay::unregisterPopCallback() { - this->popCallback = NULL; -} - -/** - * @brief Unregisters the page change callback function. - */ -void ESPMegaDisplay::unregisterPageChangeCallback() { - this->pageChangeCallback = NULL; -} - /** * @brief Constructor for the ESPMegaDisplay class. * @param displayAdapter The serial adapter connected to the display. */ -ESPMegaDisplay::ESPMegaDisplay(HardwareSerial *displayAdapter) { +ESPMegaDisplay::ESPMegaDisplay(HardwareSerial *displayAdapter) +{ this->displayAdapter = displayAdapter; this->currentPage = 0; this->rx_buffer_index = 0; - this->pushCallback = NULL; - this->popCallback = NULL; - this->pageChangeCallback = NULL; } /** * @brief Initializes the display. */ -void ESPMegaDisplay::begin() { +void ESPMegaDisplay::begin() +{ this->displayAdapter->begin(115200); this->displayAdapter->setTimeout(100); this->displayAdapter->flush(); @@ -343,8 +389,51 @@ void ESPMegaDisplay::begin() { /** * @brief The main loop function of the display. */ -void ESPMegaDisplay::loop() { +void ESPMegaDisplay::loop() +{ // Check if there is data in the serial buffer // If there is data, process the data recieveSerialCommand(); -} \ No newline at end of file +} + +/** + * @brief Registers a callback function for touch events. + * @param callback The callback function. + * @return The handle of the callback function. + */ +uint16_t ESPMegaDisplay::registerTouchCallback(std::function callback) +{ + uint16_t handle = touch_callbacks.size(); + touch_callbacks[handle] = callback; + return handle; +} + +/** + * @brief Deregisters a callback function for touch events. + * @param handle The handle of the callback function. + */ +void ESPMegaDisplay::deregisterTouchCallback(uint16_t handle) +{ + touch_callbacks.erase(handle); +} + +/** + * @brief Registers a callback function for page change events. + * @param callback The callback function. + * @return The handle of the callback function. + */ +uint16_t ESPMegaDisplay::registerPageChangeCallback(std::function callback) +{ + uint16_t handle = page_change_callbacks.size(); + page_change_callbacks[handle] = callback; + return handle; +} + +/** + * @brief Deregisters a callback function for page change events. + * @param handle The handle of the callback function. + */ +void ESPMegaDisplay::deregisterPageChangeCallback(uint16_t handle) +{ + page_change_callbacks.erase(handle); +} diff --git a/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.hpp b/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.hpp index 9c754ec..9735c60 100644 --- a/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.hpp +++ b/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaDisplay.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #define DISPLAY_FETCH_TIMEOUT 100 // ms +#define DISPLAY_FETCH_RETRY_COUNT 5 class ESPMegaDisplay { @@ -18,14 +20,11 @@ class ESPMegaDisplay const char* getString(const char* component); bool getStringToBuffer(const char* component, char* buffer, uint8_t buffer_size); uint32_t getNumber(const char* component); - void handlePwmStateChange(uint8_t pin, uint16_t value); - void handleInputStateChange(uint8_t pin, bool state); - void registerPushCallback(std::function callback); - void registerPopCallback(std::function callback); - void registerPageChangeCallback(std::function callback); - void unregisterPushCallback(); - void unregisterPopCallback(); - void unregisterPageChangeCallback(); + uint16_t registerTouchCallback(std::function callback); + void deregisterTouchCallback(uint16_t handle); + uint16_t registerPageChangeCallback(std::function callback); + void deregisterPageChangeCallback(uint16_t handle); + protected: uint8_t currentPage; uint8_t rx_buffer_index; @@ -41,7 +40,6 @@ class ESPMegaDisplay bool payloadIsValid(); bool waitForValidPayload(uint32_t timeout); HardwareSerial *displayAdapter; - std::function pushCallback; - std::function popCallback; - std::function pageChangeCallback; + std::map> touch_callbacks; + std::map> page_change_callbacks; }; \ No newline at end of file diff --git a/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaPRO_OOP.cpp b/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaPRO_OOP.cpp index 3a05463..b11830f 100644 --- a/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaPRO_OOP.cpp +++ b/ESPMegaPRO-firmware/lib/ESPMegaPRO/ESPMegaPRO_OOP.cpp @@ -9,6 +9,7 @@ bool ESPMegaPRO::begin() { this->installCard(1, &outputs); outputs.bindFRAM(&fram,0); outputs.loadFromFRAM(); + outputs.setAutoSaveToFRAM(true); if(!this->installCard(0, &inputs)) { ESP_LOGE("ESPMegaPRO", "Failed to initialize inputs"); ESP_LOGE("ESPMegaPRO", "Is this an ESPMegaPRO device?"); @@ -26,7 +27,12 @@ void ESPMegaPRO::loop() { cards[i]->loop(); } } - iot->loop(); + if(iotEnabled) { + iot->loop(); + } + if(internalDisplayEnabled) { + display->loop(); + } } bool ESPMegaPRO::installCard(uint8_t slot, ExpansionCard* card) { if (slot > 255) return false; diff --git a/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.cpp b/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.cpp index 7b321f7..cdbc3d1 100644 --- a/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.cpp +++ b/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.cpp @@ -10,6 +10,10 @@ void InternalDisplay::begin(ESPMegaIoT *iot, std::function getRtcTi this->networkConfig = this->iot->getNetworkConfig(); // Register callbacks ESP_LOGD("InternalDisplay", "Registering Callbacks"); + auto bindedPageChangeCallback = std::bind(&InternalDisplay::handlePageChange, this, std::placeholders::_1); + this->registerPageChangeCallback(bindedPageChangeCallback); + auto bindedTouchCallback = std::bind(&InternalDisplay::handleTouch, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + this->registerTouchCallback(bindedTouchCallback); ESP_LOGD("InternalDisplay", "Binding Page Change Callback"); auto bindedInputStateChangeCallback = std::bind(&InternalDisplay::handleInputStateChange, this, std::placeholders::_1, std::placeholders::_2); ESP_LOGD("InternalDisplay", "Binding Input State Change Callback"); @@ -37,6 +41,7 @@ void InternalDisplay::begin(ESPMegaIoT *iot, std::function getRtcTi void InternalDisplay::loop() { // Keep reading the Serial Adapter this->recieveSerialCommand(); + // Refresh the top bar every 5 seconds static uint32_t lastTopBarRefresh; if (millis() - lastTopBarRefresh > INTERNAL_DISPLAY_TOP_BAR_REFRESH_INTERVAL) { @@ -118,6 +123,11 @@ void InternalDisplay::refreshPage(uint8_t page) { case INTERNAL_DISPLAY_AC_PAGE: this->refreshAC(); break; + case INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE: + this->refreshPWMAdjustment(); + break; + default: + break; } } @@ -133,10 +143,11 @@ void InternalDisplay::refreshDashboard() { sprintf(ip_address, "%d.%d.%d.%d", this->networkConfig->ip[0], this->networkConfig->ip[1], this->networkConfig->ip[2], this->networkConfig->ip[3]); this->setString("ip_address.txt", ip_address); // Send the MQTT server and port - this->displayAdapter->print("server_address.txt="); + this->displayAdapter->print("server_address.txt=\""); this->displayAdapter->print(this->mqttConfig->mqtt_server); this->displayAdapter->print(":"); this->displayAdapter->print(this->mqttConfig->mqtt_port); + this->displayAdapter->print("\""); this->sendStopBytes(); // Send the MQTT connection status this->setString("status_txt.txt", this->iot->mqttConnected() ? MSG_MQTT_CONNECTED : MSG_MQTT_DISCONNECTED); @@ -144,7 +155,7 @@ void InternalDisplay::refreshDashboard() { void InternalDisplay::refreshInput() { for (uint8_t i=0; i<16; i++) { - this->setInputMarker(i, this->inputCard->digitalRead(i)); + this->setInputMarker(i, this->inputCard->digitalRead(i, false)); } } @@ -159,7 +170,6 @@ void InternalDisplay::refreshAC() { // TODO: implementation } - void InternalDisplay::setPWMAdjustmentSlider(uint16_t value) { // TODO: implementation } @@ -200,6 +210,11 @@ void InternalDisplay::setInputMarker(uint8_t pin, bool state) { InternalDisplay::InternalDisplay(HardwareSerial *displayAdapter) : ESPMegaDisplay(displayAdapter) { this->currentPage = INTERNAL_DISPLAY_DASHBOARD_PAGE; + this->iot = nullptr; + this->inputCard = nullptr; + this->outputCard = nullptr; + this->climateCard = nullptr; + this->pmwAdjustmentPin = 0; } void InternalDisplay::bindInputCard(DigitalInputCard *inputCard) { @@ -208,4 +223,101 @@ void InternalDisplay::bindInputCard(DigitalInputCard *inputCard) { void InternalDisplay::bindOutputCard(DigitalOutputCard *outputCard) { this->outputCard = outputCard; +} + +void InternalDisplay::bindClimateCard(ClimateCard *climateCard) { + this->climateCard = climateCard; +} + +void InternalDisplay::refreshPWMAdjustment() { + // The PWM Adjustment page have the following components: + // pwm_value -> a slider to adjust the PWM value + // pwm_state -> a button to toggle the PWM state + // pwm_id -> a text to show the PWM pin + + // Refresh the PWM pin + this->refreshPWMAdjustmentId(); + // Refresh the PWM value + this->refreshPWMAdjustmentSlider(); + // Refresh the PWM state + this->refreshPWMAdjustmentState(); +} + +void InternalDisplay::refreshPWMAdjustmentId() { + // Send the PWM pin + this->displayAdapter->print("pwm_id.txt=\"P"); + this->displayAdapter->print(pmwAdjustmentPin); + this->displayAdapter->print("\""); + this->sendStopBytes(); +} + +void InternalDisplay::refreshPWMAdjustmentSlider() { + // Send the PWM value + this->displayAdapter->print("pwm_value.val="); + this->displayAdapter->print(this->outputCard->getValue(this->pmwAdjustmentPin)); + this->sendStopBytes(); +} + +void InternalDisplay::refreshPWMAdjustmentState() { + // Send the PWM state + this->displayAdapter->print("pwm_state.txt=\""); + this->displayAdapter->print(this->outputCard->getState(this->pmwAdjustmentPin) ? MSG_PWM_ADJUSTMENT_STATE_ON : MSG_PWM_ADJUSTMENT_STATE_OFF); + this->displayAdapter->print("\""); + this->sendStopBytes(); +} + +void InternalDisplay::handleTouch(uint8_t page, uint8_t component, uint8_t type) { + // Switch based on the page + switch (page) { + case INTERNAL_DISPLAY_AC_PAGE: + this->handleACTouch(type, component); + break; + case INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE: + this->handlePWMAdjustmentTouch(type, component); + break; + default: + break; + } +} + +void InternalDisplay::handleACTouch(uint8_t type, uint8_t component) { + +} + +void InternalDisplay::handlePWMAdjustmentTouch(uint8_t type, uint8_t component) { + // b0 [component 5] -> decrement the PWM id if its greater than 0, else set it to 15 + // b1 [component 6] -> increment the PWM id if its less than 15, else set it to 0 + // pwm_state [component 4] -> toggle the PWM state + // pwm_value [component 1] -> set the PWM value based on the slider value + // If the type is not release then return + if (type != TOUCH_TYPE_RELEASE) return; + uint16_t val = 0; + // switch based on the component + switch (component) { + case 5: + // Decrement the PWM id + this->pmwAdjustmentPin = this->pmwAdjustmentPin > 0 ? this->pmwAdjustmentPin - 1 : 15; + this->refreshPWMAdjustment(); + break; + case 6: + // Increment the PWM id + this->pmwAdjustmentPin = this->pmwAdjustmentPin < 15 ? this->pmwAdjustmentPin + 1 : 0; + this->refreshPWMAdjustment(); + break; + case 4: + // Toggle the PWM state + this->outputCard->setState(this->pmwAdjustmentPin, !this->outputCard->getState(this->pmwAdjustmentPin)); + this->refreshPWMAdjustmentState(); + break; + case 1: + // Set the PWM value + val = (uint16_t)this -> getNumber("pwm_value.val"); + this->outputCard->setValue(this->pmwAdjustmentPin, val); + break; + default: + break; + } + + + } \ No newline at end of file diff --git a/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.hpp b/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.hpp index 476894f..5640ed2 100644 --- a/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.hpp +++ b/ESPMegaPRO-firmware/lib/ESPMegaPRO/InternalDisplay.hpp @@ -4,12 +4,21 @@ #include #include #include +#include // Page IDs -#define INTERNAL_DISPLAY_DASHBOARD_PAGE 0 -#define INTERNAL_DISPLAY_INPUT_PAGE 1 -#define INTERNAL_DISPLAY_OUTPUT_PAGE 2 -#define INTERNAL_DISPLAY_AC_PAGE 3 +#define INTERNAL_DISPLAY_BOOT_PAGE 0 +#define INTERNAL_DISPLAY_DASHBOARD_PAGE 1 +#define INTERNAL_DISPLAY_INPUT_PAGE 2 +#define INTERNAL_DISPLAY_OUTPUT_PAGE 3 +#define INTERNAL_DISPLAY_AC_PAGE 4 +#define INTERNAL_DISPLAY_PWM_ADJUSTMENT_PAGE 5 +#define INTERNAL_DISPLAY_NETWORK_CONFIG_PAGE 6 +#define INTERNAL_DISPLAY_OTA_PAGE 9 +#define INTERNAL_DISPLAY_CLIMATE_NULL_PTR_PAGE 10 +#define INTERNAL_DISPLAY_MQTT_CONFIG_PAGE 11 +#define INTERNAL_DISPLAY_INPUT_NULL_PTR_PAGE 12 +#define INTERNAL_DISPLAY_OUTPUT_NULL_PTR_PAGE 13 // Picture IDs #define PIC_LAN_DISCONNECTED 2 @@ -22,11 +31,17 @@ // Messages #define MSG_MQTT_CONNECTED "BMS Managed" #define MSG_MQTT_DISCONNECTED "Standalone" +#define MSG_PWM_ADJUSTMENT_STATE_ON "ON" +#define MSG_PWM_ADJUSTMENT_STATE_OFF "OFF" // Refresh Interval #define INTERNAL_DISPLAY_CLOCK_REFRESH_INTERVAL 15000 #define INTERNAL_DISPLAY_TOP_BAR_REFRESH_INTERVAL 5000 +// Touch Types +#define TOUCH_TYPE_PRESS 0x01 +#define TOUCH_TYPE_RELEASE 0x0 + class InternalDisplay : public ESPMegaDisplay { public: InternalDisplay(HardwareSerial *displayAdapter); @@ -34,10 +49,12 @@ class InternalDisplay : public ESPMegaDisplay { void loop(); void bindInputCard(DigitalInputCard *inputCard); void bindOutputCard(DigitalOutputCard *outputCard); + void bindClimateCard(ClimateCard *climateCard); private: DigitalInputCard *inputCard; DigitalOutputCard *outputCard; + ClimateCard *climateCard; void handleInputStateChange(uint8_t pin, bool state); void handlePwmStateChange(uint8_t pin, bool state, uint16_t value); void handlePageChange(uint8_t page); @@ -57,6 +74,15 @@ class InternalDisplay : public ESPMegaDisplay { void refreshInput(); void refreshOutput(); void refreshAC(); + void refreshPWMAdjustment(); + void refreshPWMAdjustmentSlider(); + void refreshPWMAdjustmentState(); + void refreshPWMAdjustmentId(); + uint8_t pmwAdjustmentPin; + // Touch handlers + void handleTouch(uint8_t page, uint8_t component, uint8_t type); + void handlePWMAdjustmentTouch(uint8_t component, uint8_t type); + void handleACTouch(uint8_t component, uint8_t type); MqttConfig *mqttConfig; NetworkConfig *networkConfig; // Pointers to various data diff --git a/ESPMegaPRO-firmware/platformio.ini b/ESPMegaPRO-firmware/platformio.ini index ebbab18..ffb1631 100644 --- a/ESPMegaPRO-firmware/platformio.ini +++ b/ESPMegaPRO-firmware/platformio.ini @@ -30,4 +30,4 @@ lib_deps = adafruit/Adafruit PWM Servo Driver Library@^2.4.1 robtillaart/DHTNEW@^0.4.18 #esphome/ESPAsyncWebServer-esphome@^3.1.0 monitor_speed = 115200 - +build_flags = -DCORE_DEBUG_LEVEL=1 \ No newline at end of file