diff --git a/Config.cpp b/Config.cpp index 977c116..f69cea2 100644 --- a/Config.cpp +++ b/Config.cpp @@ -24,7 +24,7 @@ void CONFIG_TYPE::init() { bNightControl = false; bControlTemperature = true; bControlHumidity = true; - bEnableIO = true; + bCheckAC = true; bAC2_OnOff = false; nNightStartHour = 18; @@ -32,18 +32,25 @@ void CONFIG_TYPE::init() { nNightEndHour = 6; nNightEndMin = 0; + ac1ControlMode = PHASE_CONTROL; + ac2ControlMode = ZCD_CONTROL; + // Block 2 - Sensor and Temperature/Humidity Settings nTempTarget = 260; nTempTargetNight = 260; nTemp1Offset = 0; nTemp2Offset = 0; nTemp3Offset = 0; - nHumidTarget = 880; - nHumidTargetNight = 880; + nHumidTarget = 800; + nHumidTargetNight = 800; nHumid1Offset = 0; nHumid2Offset = 0; nTemp1SensorType = TEMP_SENSOR_TYPE::BLE_TUYA; nTemp2SensorType = TEMP_SENSOR_TYPE::AHT20; + nTempSafety = 290; + bNTCNegativePolarity = true; + nBLEScanInterval = 143; + bBLETest = false; Kp_Temp1 = 3.0f; // Load Kp for Temperature control Kd_Temp1 = 750.0f; // Load Kd for Temperature control @@ -52,27 +59,43 @@ void CONFIG_TYPE::init() { Kp_Humidity = 2.0f; // Load Kp for Humidity control Kd_Humidity = 150.0f; // Load Kd for Humidity control LR_Humidity = 0.08f; // Load learning rate for Humidity + + Kp_Temp2 = 3.0f; // Load Kp for Temperature control + Kd_Temp2 = 750.0f; // Load Kd for Temperature control + LR_Temp2 = 0.05f; // Load learning rate for Temperature + + Kp_Humid2 = 2.0f; // Load Kp for Humidity control + Kd_Humid2 = 150.0f; // Load Kd for Humidity control + LR_Humid2 = 0.08f; // Load learning rate for Humidity + + Kp_Temp3 = 3.0f; // Load Kp for Temperature control + Kd_Temp3 = 750.0f; // Load Kd for Temperature control + LR_Temp3 = 0.05f; // Load learning rate for Temperature + + Kp_Humid3 = 2.0f; // Load Kp for Humidity control + Kd_Humid3 = 150.0f; // Load Kd for Humidity control + LR_Humid3 = 0.08f; // Load learning rate for Humidity // Block 3 - AC1 and AC2 // Day/Night Min/Max/Start On/Off THigh/Low Time B/E Period Hum H/L - config.ac1 = {CONTROL_TEMP_HEAT_PID, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,24*60-1, 60, 5, 920,880 }; - config.ac2 = {CONTROL_TEMP_HEAT, 0, 0,0, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 920,880 }; + config.ac1 = {CONTROL_TEMP_HEAT_PID, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,24*60-1, 60, 5, 820,780 }; + config.ac2 = {CONTROL_TEMP_HEAT, 0, 0,0, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 820,780 }; // Block 4 = Mist and Fan // Day/Night Min/Max/Start On/Off THigh/Low Time B/E Period Hum H/L - config.mist = {CONTROL_HUMIDITY_INC_PID, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 920,880 }; - config.fan = {CONTROL_TEMP_COOL, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 920,880 }; + config.mist = {CONTROL_HUMIDITY_INC_PID, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 820,780 }; + config.fan = {CONTROL_TEMP_COOL, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 820,780 }; // Block 5 - Motor and Light // Day/Night Min/Max/Start On/Off THigh/Low Time B/E Period Hum H/L - config.motor = {CONTROL_PERIOD, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 920,880 }; - config.light = {CONTROL_DAY_NIGHT, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 920,880 }; + config.motor = {CONTROL_PERIOD, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 820,780 }; + config.light = {CONTROL_DAY_NIGHT, 0, 1,1, 0, 1000, 0, 250,0, 920,880, 0,25*60-1, 60, 5, 820,780 }; // Block 6 - Environment and Operations - bSendStatusSerial = false; bConfigSaved = false; bStatusSaved = false; + bSendStatusSerial = false; // // Reserved @@ -81,8 +104,8 @@ void CONFIG_TYPE::init() { for (int i = 0; i < 17; i = i + 8) { m_nChipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; } - m_nPublicPort = 3939; m_nDeviceType = THIS_DEVICE_TYPE; + m_nPublicPort = 3939; // // WiFi Client Only @@ -90,19 +113,26 @@ void CONFIG_TYPE::init() { m_nDisplayTime = 1800; m_nDisplayTempHigh = 40; m_nDisplayTempLow = 20; - m_nTempHigh = 20; + m_nTempHigh = 25; m_fShowRealTime = 0x000F; - - // Names - strcpy(m_sDeviceName, "Beta X"); - strcpy(m_sMake, "VisionSoft"); - strcpy(m_sModel, "HermitCrab"); - strncpy(m_sVersion, HC__VERSION, 11); - + m_fShowHistory = 0x000F; + m_nEpochTime = 0; + m_nTimeOffset = 9 * 60 * 60; + m_bFahrenheit = false; // WiFi - SSID and Password strcpy(ssid, "RECALL"); strcpy(pw, "BBBB9999"); + + //Block 10 + strcpy(m_sDeviceName, "Beta X"); + strcpy(m_sMake, "VisionSoft"); + + // Block 11 + strcpy(m_sModel, "HermitCrab"); + strncpy(m_sVersion, HC__VERSION, 11); + + ESP_LOGI(TAG,"Config Initialized"); } diff --git a/Config.h b/Config.h index 5c6e3ea..08fbefb 100644 --- a/Config.h +++ b/Config.h @@ -70,17 +70,14 @@ enum TEMP_SENSOR_TYPE { typedef struct CONFIG_STRUCT { uint16_t m_nSignature1; - // Block 1 - Control and EnvironMent // Offset 2 bool bSmartControl; bool bNightControl; bool bControlTemperature; bool bControlHumidity; - bool bEnableIO; bool bCheckAC; bool bAC2_OnOff; - bool bdummy; uint8_t nNightStartHour, nNightStartMin, nNightEndHour, nNightEndMin; float Kp_Temp2; // Load Kp for Temperature control float Kd_Temp2; // Load Kd for Temperature control @@ -88,28 +85,33 @@ typedef struct CONFIG_STRUCT { float Kp_Temp3; // Load Kp for Temperature control float Kd_Temp3; // Load Kd for Temperature control float LR_Temp3; // Load learning rate for Temperature + uint8_t ac1ControlMode, ac2ControlMode; // ZCD_CONTROL || PHASE_CONTROL + uint8_t bPadding1[2]; union { uint64_t nBLESensorAddr2; uint8_t nBLESensorAddrBytes2[8]; }; - uint8_t ac1ControlMode, ac2ControlMode; // ZCD_CONTROL || PHASE_CONTROL - char bExtra[64 - 8 * sizeof(bool) - 4 * sizeof(uint8_t) - 6 * sizeof(float) - sizeof(uint64_t) - 2 * sizeof(uint8_t)]; - + float Kp_Humid2; + float Kd_Humid2; + float LR_Humid2; + char bExtra[64 - 6 * sizeof(bool) - 8 * sizeof(uint8_t) - 9 * sizeof(float) - sizeof(uint64_t)]; + // Block 2 - Sensor and TargetTemperature and Himidity // Offset 64 + 2 int16_t nTempTarget, nTempTargetNight; // Target Temperature int16_t nTemp1Offset, nTemp2Offset, nTemp3Offset; uint16_t nHumidTarget, nHumidTargetNight; int16_t nHumid1Offset, nHumid2Offset; - uint8_t nTemp1SensorType; // TempSensor Type enum - uint8_t nTemp2SensorType; // TempSensor Type enum - float Kp_Temp1; // Load Kp for Temperature control - float Kd_Temp1; // Load Kd for Temperature control - float LR_Temp1; // Load learning rate for Temperature - float Kp_Humidity; // Load Kp for humidity control - float Kd_Humidity; // Load Kd for humidity control - float LR_Humidity; // Load learning rate for humidity + uint8_t nTemp1SensorType; // TempSensor Type enum + uint8_t nTemp2SensorType; // TempSensor Type enum int16_t nTempSafety; + + float Kp_Temp1; // Load Kp for Temperature control + float Kd_Temp1; // Load Kd for Temperature control + float LR_Temp1; // Load learning rate for Temperature + float Kp_Humidity; // Load Kp for humidity control + float Kd_Humidity; // Load Kd for humidity control + float LR_Humidity; // Load learning rate for humidity union { uint64_t nBLESensorAddr; uint8_t nBLESensorAddrBytes[8]; @@ -118,28 +120,36 @@ typedef struct CONFIG_STRUCT { uint8_t nBLEScanInterval; uint8_t bBLETest; char nTempExtra[64 - 10 * sizeof(int16_t) - 6 * sizeof(float) - 5 * sizeof(uint8_t) - sizeof(uint64_t)]; + + union { + struct { + // Block 3 - AC1 and AC2 + // Offset 128 + 2 + DEVICE_PARAM_TYPE ac1; + DEVICE_PARAM_TYPE ac2; + + // Block 4 - Mist and Fan + // Offset 192 + 2 + DEVICE_PARAM_TYPE mist; + DEVICE_PARAM_TYPE fan; + + // Block 5 - Motor and Light + // Offset 256 + 2 + DEVICE_PARAM_TYPE motor; + DEVICE_PARAM_TYPE light; + }; + DEVICE_PARAM_TYPE deviceParamArray[6]; + }; - // Block 3 - AC1 and AC2 - // Offset 128 + 2 - DEVICE_PARAM_TYPE ac1; - DEVICE_PARAM_TYPE ac2; - - // Block 4 - Mist and Fan - // Offset 192 + 2 - DEVICE_PARAM_TYPE mist; - DEVICE_PARAM_TYPE fan; - - // Block 5 - Motor and Light - // Offset 256 + 2 - DEVICE_PARAM_TYPE motor; - DEVICE_PARAM_TYPE light; - // Block 6 - Environment and Operations // Offset 320 + 2 - bool bSendStatusSerial; bool bConfigSaved; bool bStatusSaved; - char nEnvExtra[32 - 3 * sizeof(bool)]; + float Kp_Humid3; // Load Kd for humidity control + float Kd_Humid3; // Load Kp for humidity control + float LR_Humid3; // Load learning rate for humidity + bool bSendStatusSerial; + char nEnvExtra[32 - 3 * sizeof(bool) - 3*sizeof(float)]; // Offset 352 + 2 STATUS_TYPE statusSave; @@ -177,17 +187,18 @@ typedef struct CONFIG_STRUCT { char nModelExtra[64 - 44]; // Offset 704 + 2 + char padAlign8[4]; uint16_t m_nSignature2; #ifdef ESP32 - // ConfigStruct Size: 708 + // ConfigStruct Size: 712 public: void init(); bool load(); void save(); //bool saveToServer(); #endif -} CONFIG_TYPE; +} __attribute__((aligned(8))) CONFIG_TYPE; #pragma pack(pop) // Restore previous alignment setting extern class Preferences preferences; diff --git a/ConnectWiFi.cpp b/ConnectWiFi.cpp index eb76983..dacf7cf 100644 --- a/ConnectWiFi.cpp +++ b/ConnectWiFi.cpp @@ -4,6 +4,7 @@ extern bool g_bWiFiSetupExecuted; extern bool g_bWiFiHasBeenConnected; void setupPostWiFi(bool bBoot = false); +void reconnectWiFi(unsigned long tickMillis, bool bConnecting, wl_status_t status); void WiFiEvent(WiFiEvent_t event) { switch (event) { @@ -40,20 +41,24 @@ void checkAndUpdateWiFiCredentials() { } } -IRAM_ATTR -void checkWiFi(unsigned long tickMillis) { - static unsigned long lastAttempt = 0; +IRAM_ATTR void checkWiFi(unsigned long tickMillis) { static bool bConnecting = false; - wl_status_t status = WiFi.status(); // Connected if (status == WL_CONNECTED) { - bConnecting = false; - g_bWiFiHasBeenConnected = true; - return; // Already connected, no need to proceed further + bConnecting = false; + g_bWiFiHasBeenConnected = true; + return; // Already connected, no need to proceed further } + // Not Connected + reconnectWiFi(tickMillis, bConnecting, status); +} + +void reconnectWiFi(unsigned long tickMillis, bool bConnecting, wl_status_t status) { + static unsigned long lastAttempt = 0; + checkAndUpdateWiFiCredentials(); // Connecting diff --git a/HermitCrab.h b/HermitCrab.h index b14c517..00259d9 100644 --- a/HermitCrab.h +++ b/HermitCrab.h @@ -20,7 +20,7 @@ #ifndef DEBUG #define DEBUG 1 // Set to 0 to disable debug output #endif -//#undef DEBUG +#undef DEBUG //#define BLE_DEBUG @@ -152,6 +152,8 @@ enum EVENT_TYPE { #define FLAG_BLE_NODATA (0x0800) #define FLAG_BLE_LOST (0x1000) +#define PHASE_CONTROL 0 +#define ZCD_CONTROL 1 #pragma pack(push) /* push current alignment to stack */ #pragma pack(1) /* set alignment to 1 byte boundary */ @@ -200,14 +202,15 @@ typedef struct STATUS_STRUCT { uint16_t nLightDuty; uint16_t nLightTargetDuty; // 24 + + uint16_t nFlags; + // 26 // Current Time uint32_t now; - // 28 - - uint16_t nFlags; // 30 + // AC status uint8_t zcdAC; uint8_t zcdLoad; diff --git a/HermitCrab.ino b/HermitCrab.ino index 8a89a8e..5ca5ed5 100644 --- a/HermitCrab.ino +++ b/HermitCrab.ino @@ -22,6 +22,11 @@ STATUS_TYPE status; +// 코어 버전이 3.0.2가 아니면 컴파일 중단 +#include +static_assert(ESP_ARDUINO_VERSION == ESP_ARDUINO_VERSION_VAL(3, 0, 2), + "This project requires ESP32 Arduino Core 3.0.2"); + // Time volatile unsigned short g_nYear, g_nMonth, g_nDay, g_nHour, g_nMinute, g_nSecond; volatile uint32_t g_millis = 0l; @@ -584,9 +589,6 @@ MY_IRAM_ATTR char *printStatus(unsigned long tick, bool bLong) { printTime(bLong), strHeat1, strMist, strLight1, history.getKpTemperature(), history.getKdTemperature(), history.getKpHumidity(), history.getKdHumidity()); - - // Send out to clients - // ESP_LOGI(TAG_MAIN,"%s\n", szStatus); } return szStatus; } diff --git a/NTC_10K.cpp b/NTC_10K.cpp index fb2d515..6d08986 100644 --- a/NTC_10K.cpp +++ b/NTC_10K.cpp @@ -1,11 +1,8 @@ -#include "Arduino.h" - +#include #include "HermitCrab.h" -#include "NTC_10K.h" #include "Config.h" +#include "NTC_10K.h" -#include "driver/gpio.h" -#include "driver/adc.h" const float resistance[] = { 3360850.37, // -40°C @@ -74,6 +71,23 @@ void NTC_10K::setup(bool bNegativePolarity) { m_nTemp = -9999; m_fTemp = -9999.0f; m_fLastTemp = 0.0f; + + + // ========================= + // 1. NTC (ADC 설정) + // ========================= + // 1.1. 핸들 및 설정 변수 선언 + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = ADC_UNIT_1, + }; + adc_oneshot_new_unit(&init_config, &adc1_handle); + + // 1.2. 채널 설정 (감쇠비 포함) + adc_oneshot_chan_cfg_t config = { + .atten = ADC_ATTEN_DB_12, // 11 대신 12 사용 (이전 답변 참고) + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_3, &config); } /** @@ -90,7 +104,9 @@ void NTC_10K::readSensor() { float currentInstantTemp; // High-precision intermediate // 1. Hardware Acquisition - int adcValue = constrain(adc1_get_raw(ADC1_CHANNEL_3), 1, 4094); + //int adcValue = constrain(adc1_get_raw(ADC1_CHANNEL_3), 1, 4094); + int adcValue; + adc_oneshot_read(adc1_handle, ADC_CHANNEL_3, &adcValue); // 2. Voltage and Resistance Calculation Vin = (float)adcValue * _vRef / _RESO; diff --git a/NTC_10K.h b/NTC_10K.h index 0ac3404..7e0dd77 100644 --- a/NTC_10K.h +++ b/NTC_10K.h @@ -7,6 +7,7 @@ #define NTC_COUNT 32 #define NTC_MASK (NTC_COUNT - 1) +#include class NTC_10K { private: @@ -24,6 +25,8 @@ private: float m_fTemp; float m_fLastTemp; + adc_oneshot_unit_handle_t adc1_handle; + public: void setup(bool bNegativePolarity); void readSensor(); diff --git a/OTA.cpp b/OTA.cpp index b6f8584..2ccceaa 100644 --- a/OTA.cpp +++ b/OTA.cpp @@ -17,7 +17,7 @@ // OTA // // ============================================================== -const char *HC__VERSION = "20260419022"; +const char *HC__VERSION = "20260424001"; #define UPDATE_PORT ((uint16_t) 443) const char *url = "visionsoft.kr"; const char *uri = "/sc/pages/firmware_download.php"; diff --git a/Setup.cpp b/Setup.cpp index f4e9dda..c55390f 100644 --- a/Setup.cpp +++ b/Setup.cpp @@ -14,12 +14,9 @@ #include "esp_coexist.h" // GPIO Headers -#include "driver/gpio.h" -#include "driver/timer.h" -#include "driver/adc.h" +#include +#include - -#define TAG_SETUP "TAG_SETUP" // Task handle TaskHandle_t TaskHandle_0; @@ -68,17 +65,23 @@ void setup() { bShowSensor = false; - // Hardware - setupPWM(); + // Basic settings before wifi/OTA + setupPWM(); // Required for LED blinking setupGPIO1(); - setupConfig(); - setupStatus(); - scanI2C(); - setupSensor(); - ui.setup(); - setupWiFi(); + + setupConfig(); // Wifi SSID/PW + scanI2C(); // Wire init + setupSensor(); // Wire Scan + ui.setup(); // ui for OLED Display + // Wifi and Update Check + setupWiFi(); // Wifi AP, OTA, Time Service + setupStatus(); // Requires Time Service from WiFi Setup. + + // Pins + + // Temp/Humod Sensor if (aht25.sensor() || aht10_0x39.sensor()) { ui.message(4, (char *) "Sensor... OK!"); } else { @@ -124,9 +127,6 @@ void setupGPIO1() { // ========================= // 1. NTC (ADC 설정) // ========================= - // adc1_config_channel_atten에서 내부적으로 핀 설정을 하므로 방향 설정은 생략 가능합니다. - adc1_config_width(ADC_WIDTH_BIT_12); // 0~4095 - adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11); // ========================= // 2. UI Buttons 설정 diff --git a/UI.cpp b/UI.cpp index 10f8b7e..c8ef58f 100644 --- a/UI.cpp +++ b/UI.cpp @@ -222,7 +222,7 @@ CUI::CUI() void CUI::setup() { // Initialize the display - ESP_LOGI(TAG_UI," UI - setup()"); + DPRINTLN("[UI] setup()"); bOK = false; bDot = false; bButtonChanged = false; @@ -249,18 +249,19 @@ void CUI::setup() { lastpDUnit = nullptr; // Check if device exists + // Wire.begin(); for (int i = 0; i < 5; i++) { Wire.beginTransmission(i2caddr); if (Wire.endTransmission() == 0) { bOK = true; - ESP_LOGI(TAG_UI," UI - device Found at 0x%02X\n", i2caddr); + DPRINTF("[UI] Setup - device Found at 0x%02X\n", i2caddr); break; } delay(50); } if (!bOK) { - ESP_LOGI(TAG_UI," UI - device NOT found at 0x%02X\n", i2caddr); + DPRINTF("[UI] Setup - device NOT found at 0x%02X\n", i2caddr); return; } diff --git a/UI.h b/UI.h index 0738f45..056e19f 100644 --- a/UI.h +++ b/UI.h @@ -102,9 +102,9 @@ private: // // Button ISR's // -void IRAM_ATTR buttonSetISR(void *); -void IRAM_ATTR buttonUpISR(void *); -void IRAM_ATTR buttonDownISR(void *); +void buttonSetISR(void *); +void buttonUpISR(void *); +void buttonDownISR(void *); extern CUI ui; #endif diff --git a/WiFiHost.cpp b/WiFiHost.cpp index aa01806..367afa2 100644 --- a/WiFiHost.cpp +++ b/WiFiHost.cpp @@ -164,8 +164,7 @@ void CWiFiHost::CloseConnection() m_nMode = MODE_WAITING; } -IRAM_ATTR -void CWiFiHost::Loop(unsigned long clock) +IRAM_ATTR void CWiFiHost::Loop(unsigned long clock) { if (!isWiFiConnected()) return; @@ -251,8 +250,7 @@ void CWiFiHost::Loop(unsigned long clock) } } -MY_IRAM_ATTR -void CWiFiHost::SendHeartBeat(unsigned long clock) { +MY_IRAM_ATTR void CWiFiHost::SendHeartBeat(unsigned long clock) { if (!isWiFiConnected()) { //ESP_LOGI(TAG_WIFI_HOST,"WiFiHost - SendHeartBeat() called while not connected!"); return; @@ -304,8 +302,7 @@ void CWiFiHost::SendHeartBeat(unsigned long clock) { } } -MY_IRAM_ATTR -void CWiFiHost::MonitorUDP() { +MY_IRAM_ATTR void CWiFiHost::MonitorUDP() { // Listen for UDP External port IPAddress ip; int size = udpExternal.parsePacket(); @@ -358,8 +355,42 @@ void CWiFiHost::MonitorUDP() { } } -IRAM_ATTR -void CWiFiHost::CheckClient(unsigned long clock) +typedef union { + float f; + uint32_t u; +} float_bits; + +// Optimized for range +/- 0.0001 to +/- 3000 +IRAM_ATTR uint16_t f32tof16(float f32) { + float_bits fb; + fb.f = f32; + + // Extract sign, move to bit 15 + uint32_t sign = (fb.u >> 16) & 0x8000; + // Shift exponent from 8-bit (bias 127) to 5-bit (bias 15) + // 0x7f800000 masks the exponent + uint32_t exp = ((((fb.u & 0x7f800000) >> 23) - 127 + 15) & 0x1f) << 10; + // Truncate 23-bit mantissa to 10-bit + uint32_t mant = (fb.u >> 13) & 0x03ff; + + return (uint16_t)(sign | exp | mant); +} + +IRAM_ATTR float f16tof32(uint16_t f16) { + float_bits fb; + + // Shift sign to bit 31 + uint32_t sign = (uint32_t)(f16 & 0x8000) << 16; + // Shift exponent from 5-bit (bias 15) back to 8-bit (bias 127) + uint32_t exp = (((f16 >> 10) & 0x1f) - 15 + 127) << 23; + // Shift 10-bit mantissa back to 23-bit + uint32_t mant = (f16 & 0x03ff) << 13; + + fb.u = sign | exp | mant; + return fb.f; +} + +IRAM_ATTR void CWiFiHost::CheckClient(unsigned long clock) { // 1. Quick exit if no data is ready to be read int available = wifiClient.available(); @@ -370,7 +401,6 @@ void CWiFiHost::CheckClient(unsigned long clock) // 2. Peek or Read the packet // We use readBytes because we already verified 'available' >= size int count = wifiClient.readBytes((uint8_t*)&cpkt, sizeof(TCP_PACKET)); - if (count == sizeof(TCP_PACKET)) { // 3. Validation Logic bool sigMatch = (cpkt.sig1 == SIGNATURE1 && cpkt.sig2 == SIGNATURE2); @@ -382,7 +412,7 @@ void CWiFiHost::CheckClient(unsigned long clock) } else { // 4. Recovery Logic: Instead of a blocking while-loop, // clear the socket buffer and wait for the next loop cycle. - ESP_LOGW(TAG_WIFI_HOST, "Protocol out of sync. Flushing %d bytes", available); + DPRINTF("[Host] ErrPacket CMD(%d) OP(%d) len(%d) sig(%s)\n", cpkt.cmd, cpkt.op, cpkt.len, sigMatch ? "OK" : "fail"); while(wifiClient.available() > 0) { wifiClient.read(); // Efficiently dump the garbage } @@ -390,327 +420,333 @@ void CWiFiHost::CheckClient(unsigned long clock) } } -IRAM_ATTR -void CWiFiHost::ProcessPacket(TCP_PACKET& pkt) +IRAM_ATTR void CWiFiHost::ProcessPacket(TCP_PACKET& pkt) { - switch (pkt.cmd) - { - // System - case CMD_HEARTBEAT: - m_nLastReceivedTime = millis(); - //ESP_LOGI(TAG_WIFI_HOST,"H"); - break; - case CMD_HELLO: - case CMD_HELLO_DEBUG: - { - // Send the Config Data to PC - // Send Packet Back - ESP_LOGI(TAG_WIFI_HOST,"WiFi - HELLO received"); - pkt.u16[0] = SIGNATURE1; - pkt.n16[1] = sizeof(CONFIG_TYPE); - pkt.u16[2] = SIGNATURE2; - config.m_nChipId; - SendPacket(pkt); - - // Send Data Packets - ESP_LOGI(TAG_WIFI_HOST,"WiFi - Config Send pending..."); - int sent = SendData((uint8_t*)&config, sizeof(CONFIG_TYPE)); - m_bHelloSent = true; - } - break; - case CMD_DROP_CONNECTION: - wifiClient.stop(); - m_bClientConnected = false; - m_nMode = MODE_WAITING; - ESP_LOGI(TAG_WIFI_HOST,"WiFI - Client requets to DROP CONNECTION"); - break; - case CMD_RESET_REASON: - pkt.n16[0] = esp_reset_reason(); - SendPacket(pkt); - break; - case CMD_SAVE_RESTART: - if (pkt.u16[0] == SIGNATURE1 && - pkt.u16[1] == SIGNATURE2) { - yield(); - Restart(); - } - break; - case CMD_RESET_RESTART: - if (pkt.u16[0] == SIGNATURE1 && - pkt.u16[1] == SIGNATURE2) { - pkt.cmd = CMD_DROP_CONNECTION; - SendPacket(pkt); - yield(); - Restart(); - } - break; - case CMD_SEND_HISTORY: - if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == SIGNATURE2) { - int16_t count = history.getRingCount(); - if (count > 0 ) { - // inform client the count of history - pkt.op = count; - SendPacket(pkt); - int16_t size = history.getRingSize(); - if (count < size) { - ESP_LOGI(TAG_WIFI_HOST,"WfFi Host - SendData - Whold part of History (%d)\n", count); - SendData(history.getRingData1()/* &ring[tail] */, sizeof(STATUS_TYPE) * count); - } else { - int count1st = size - history.getRingTail(); - ESP_LOGI(TAG_WIFI_HOST,"WfFi Host - SendData - 1st part of History Total(%d), 1st(%d) H(%d) T(%d)\n", - count, count1st, history.getRingHead(), history.getRingTail()); - SendData(history.getRingData1(), sizeof(STATUS_TYPE) * count1st), - // Mark pending to send the second part: from the start to head-1 - //SendData(history.getRingData2() /* &ring[0] */, sizeof(STATUS_TYPE) * head); - m_bSendHistoryPending = true; - m_nPendingHistoryCount = history.getRingHead(); - } - } - } - break; - case CMD_RESET_SENSOR: - aht25.setScanFlag(true); - aht10_0x39.setScanFlag(true); - break; - + // Jump Table definition (GCC Labels-as-values) + static const void* jump_table[] = { + [0] = &&L_DEFAULT, + // Connection & Control + [CMD_HEARTBEAT] = &&L_CMD_HEARTBEAT, + [CMD_HELLO] = &&L_CMD_HELLO, + [CMD_DROP_CONNECTION] = &&L_CMD_DROP_CONNECTION, + [CMD_RESET_REASON] = &&L_CMD_RESET_REASON, + [CMD_RESTART] = &&L_CMD_RESTART, + [CMD_SEND_HISTORY] = &&L_CMD_SEND_HISTORY, + [CMD_RESET_SENSOR] = &&L_CMD_RESET_SENSOR, + [CMD_RESET_DISPLAY] = &&L_CMD_RESET_DISPLAY, + // Config - case CMD_INIT_CONFIG: - if (pkt.u16[0] == SIGNATURE1 && - pkt.u16[1] == sizeof(CONFIG_STRUCT) && - pkt.u16[2] == SIGNATURE2) { - config.init(); - config.save(); - } - break; - case CMD_LOAD_CONFIG: - if (pkt.u16[0] == SIGNATURE1 && - pkt.u16[1] == sizeof(CONFIG_STRUCT) && - pkt.u16[2] == SIGNATURE2) { - config.load(); - history.loadPID(); - } - break; - case CMD_SAVE_CONFIG: - if (pkt.u16[0] == SIGNATURE1 && - pkt.u16[1] == sizeof(CONFIG_STRUCT) && - pkt.u16[2] == SIGNATURE2) { - config.save(); - } - break; - case CMD_RECV_CONFIG: - // Receive Confif Data from PC - if (pkt.u16[0] == SIGNATURE1 && - pkt.u16[1] == sizeof(CONFIG_STRUCT) && - pkt.u16[2] == SIGNATURE2) { - ReceiveData((uint8_t *)&configCopy, sizeof(CONFIG_TYPE)); - m_bReceiveConfigPending = true; - ESP_LOGI(TAG_WIFI_HOST,"WiFi - Receive Config initiated..."); - } - break; - case CMD_SEND_CONFIG: - if (pkt.u16[0] == SIGNATURE1 && - pkt.u16[1] == sizeof(CONFIG_STRUCT) && - pkt.u16[2] == SIGNATURE2) { - SendPacket(pkt); - SendData((const uint8_t *)&config, (unsigned int) sizeof(config)); - ESP_LOGI(TAG_WIFI_HOST,"WiFi - Send Config initiated..."); - } - break; - // PID - case CMD_INIT_PID_PARAM: - history.savePID(); - break; - case CMD_LOAD_PID_PARAM: - history.loadPID(); - break; - case CMD_SAVE_PID_PARAM: - history.savePID(); - break; - case CMD_SET_PID: - config.Kp_Temp1 = pkt.f[0]; - config.Kd_Temp1 = pkt.f[1]; - config.LR_Temp1 = pkt.f[2]; - config.Kp_Humidity = pkt.f[3]; - config.Kd_Humidity = pkt.f[4]; - config.LR_Humidity = pkt.f[5]; - history.loadPID(); - break; - case CMD_GET_PID: - pkt.f[0] = config.Kp_Temp1; - pkt.f[1] = config.Kd_Temp1; - pkt.f[2] = config.LR_Temp1; - pkt.f[3] = config.Kp_Humidity; - pkt.f[4] = config.Kd_Humidity; - pkt.f[5] = config.LR_Humidity; - SendPacket(pkt); - break; + [CMD_INIT_CONFIG] = &&L_CMD_INIT_CONFIG, + [CMD_LOAD_CONFIG] = &&L_CMD_LOAD_CONFIG, + [CMD_SAVE_CONFIG] = &&L_CMD_SAVE_CONFIG, + [CMD_SEND_CONFIG] = &&L_CMD_SEND_CONFIG, + [CMD_RECV_CONFIG] = &&L_CMD_RECV_CONFIG, + [CMD_SET_DEVICE_PARAM] = &&L_CMD_SET_DEVICE_PARAM, + [CMD_GET_DEVICE_PARAM] = &&L_CMD_GET_DEVICE_PARAM, // Control - case CMD_SET_CONTROL: - config.bSmartControl = pkt.by[0] ? true : false; - config.bNightControl = pkt.by[1] ? true : false; - config.bControlTemperature = pkt.by[2] ? true : false; - config.bControlHumidity = pkt.by[3] ? true : false; - break; - case CMD_GET_CONTROL: - pkt.by[0] = config.bSmartControl ? 0xFF : 0; - pkt.by[1] = config.bNightControl ? 0xFF : 0; - pkt.by[2] = config.bControlTemperature ? 0xFF : 0; - pkt.by[3] = config.bControlHumidity ? 0xFF : 0; - SendPacket(pkt); - break; + [CMD_SET_CONTROL] = &&L_CMD_SET_CONTROL, + [CMD_GET_CONTROL] = &&L_CMD_GET_CONTROL, - // Operation - case CMD_SET_TEMP_TARGET: - config.nTempTarget = pkt.u16[0]; - ESP_LOGI(TAG_WIFI_HOST,"WiFi - TempTarget changed to: %d\n", pkt.u16[0]); - break; - case CMD_SET_TEMP_TARGET_NIGHT: - config.nTempTargetNight = pkt.u16[0]; - ESP_LOGI(TAG_WIFI_HOST,"WiFi - TempTargetNight changed to: %d\n", pkt.u16[0]); - break; - case CMD_SET_HUMID_TARGET: - config.nHumidTarget = pkt.u16[0]; - ESP_LOGI(TAG_WIFI_HOST,"WiFi - HumidTarget changed to: %d\n", pkt.u16[0]); - break; - case CMD_SET_SENSOR_OFFSET: - config.nTemp1Offset = pkt.n16[0]; - config.nHumid1Offset = pkt.n16[1]; - if (pkt.n16[2] > 1) { - config.nTemp2Offset = pkt.n16[2]; - config.nHumid2Offset = pkt.n16[3]; - if (pkt.n16[2] > 2) - config.nTemp3Offset = pkt.n16[4]; - } - ESP_LOGI(TAG_WIFI_HOST,"WiFi - SensorOffset changed to: %d, %d\n", pkt.n16[0], pkt.n16[1]); - break; + // Set + [CMD_SET_TEMP_TARGET] = &&L_CMD_SET_TEMP_TARGET, + [CMD_SET_TEMP_TARGET_NIGHT] = &&L_CMD_SET_TEMP_TARGET_NIGHT, + [CMD_SET_HUMID_TARGET] = &&L_CMD_SET_HUMID_TARGET, + [CMD_SET_SENSOR_OFFSET] = &&L_CMD_SET_SENSOR_OFFSET, + [CMD_SET_HEATER1_DUTY] = &&L_CMD_SET_HEATER1_DUTY, + [CMD_SET_MANUAL_HEATER1] = &&L_CMD_SET_MANUAL_HEATER1, + [CMD_SET_HEATER2_DUTY] = &&L_CMD_SET_HEATER2_DUTY, + [CMD_SET_MANUAL_HEATER2] = &&L_CMD_SET_MANUAL_HEATER2, + [CMD_SET_MIST_DUTY] = &&L_CMD_SET_MIST_DUTY, + [CMD_SET_MANUAL_MIST] = &&L_CMD_SET_MANUAL_MIST, + [CMD_SET_FAN_DUTY] = &&L_CMD_SET_FAN_DUTY, + [CMD_SET_MANUAL_FAN] = &&L_CMD_SET_MANUAL_FAN, + [CMD_SET_MOTOR_DUTY] = &&L_CMD_SET_MOTOR_DUTY, + [CMD_SET_MANUAL_MOTOR] = &&L_CMD_SET_MANUAL_MOTOR, + [CMD_SET_LIGHT_DUTY] = &&L_CMD_SET_LIGHT_DUTY, + [CMD_SET_MANUAL_LIGHT] = &&L_CMD_SET_MANUAL_LIGHT, + [CMD_SET_TIME_NIGHT] = &&L_CMD_SET_TIME_NIGHT, + [CMD_SET_WIFI_CLIENT_DISPLAY] = &&L_CMD_SET_WIFI_CLIENT_DISPLAY, - case CMD_SET_AC1_PARAM: - config.ac1 = pkt.device; - break; - case CMD_SET_AC2_PARAM: - config.ac2 = pkt.device; - break; - case CMD_SET_MIST_PARAM: - config.mist = pkt.device; - break; - case CMD_SET_FAN_PARAM: - config.fan = pkt.device; - break; - case CMD_SET_MOTOR_PARAM: - config.motor = pkt.device; - break; - case CMD_SET_LIGHT_PARAM: - config.light = pkt.device; - break; + // PID + [CMD_INIT_PID_PARAM] = &&L_CMD_INIT_PID_PARAM, + [CMD_LOAD_PID_PARAM] = &&L_CMD_LOAD_PID_PARAM, + [CMD_SAVE_PID_PARAM] = &&L_CMD_SAVE_PID_PARAM, + [CMD_SET_PID] = &&L_CMD_SET_PID, + [CMD_GET_PID] = &&L_CMD_GET_PID + }; - // Status - case CMD_SET_HEATER1_DUTY: - status.nHeater1Duty = pkt.u16[0]; - if (pkt.u16[1]) - status.nFlags |= FLAG_MANUAL_HEATER1; - else - status.nFlags &= ~FLAG_MANUAL_HEATER1; - if (status.nHeater1Duty == 0) { - setHeater1Duty(0); - } - break; - case CMD_SET_HEATER2_DUTY: - status.nHeater2Duty = pkt.u16[0]; - if (pkt.u16[1]) - status.nFlags |= FLAG_MANUAL_HEATER2; - else - status.nFlags &= ~FLAG_MANUAL_HEATER2; - if (status.nHeater2Duty == 0) { - setHeater2Duty(0); - } - break; - case CMD_SET_MIST_DUTY: - status.nMistDuty = pkt.u16[0]; - if (pkt.u16[1]) - status.nFlags |= FLAG_MANUAL_MIST; - else - status.nFlags &= ~FLAG_MANUAL_MIST; - break; - case CMD_SET_FAN_DUTY: - status.nFanDuty = pkt.u16[0]; - if (pkt.u16[1]) - status.nFlags |= FLAG_MANUAL_FAN; - else - status.nFlags &= ~FLAG_MANUAL_FAN; + // Bounds check to prevent illegal memory access + if (pkt.cmd >= CMD_COUNT || pkt.cmd <= 0) goto L_DEFAULT; + DPRINTF("[HOST] CMD(%d) OP(%d) LEN(%d) U[%d][%d][%d][%d]\n", + pkt.cmd, pkt.op, pkt.len, pkt.u16[0], pkt.u16[1], pkt.u16[2], pkt.u16[3]); - break; - case CMD_SET_MOTOR_DUTY: - status.nMotorDuty = pkt.u16[0]; - if (pkt.u16[1]) - status.nFlags |= FLAG_MANUAL_MOTOR; - else - status.nFlags &= ~FLAG_MANUAL_MOTOR; - break; - case CMD_SET_LIGHT_DUTY: - status.nLightTargetDuty = pkt.u16[0]; - if (pkt.u16[1]) - status.nFlags |= FLAG_MANUAL_LIGHT; - else - status.nFlags &= ~FLAG_MANUAL_LIGHT; - break; + // Direct jump + goto *jump_table[pkt.cmd]; - // Manual Operation - case CMD_SET_MANUAL_HEATER1: - if (pkt.u16[0]) - status.nFlags |= FLAG_MANUAL_HEATER1; - else - status.nFlags &= ~FLAG_MANUAL_HEATER1; - break; - case CMD_SET_MANUAL_HEATER2: - if (pkt.u16[0]) - status.nFlags |= FLAG_MANUAL_HEATER2; - else - status.nFlags &= ~FLAG_MANUAL_HEATER2; - break; - case CMD_SET_MANUAL_MIST: - if (pkt.u16[0]) - status.nFlags |= FLAG_MANUAL_MIST; - else - status.nFlags &= ~FLAG_MANUAL_MIST; - break; - case CMD_SET_MANUAL_FAN: - if (pkt.u16[0]) - status.nFlags |= FLAG_MANUAL_FAN; - else - status.nFlags &= ~FLAG_MANUAL_FAN; - break; - case CMD_SET_MANUAL_LIGHT: - if (pkt.u16[0]) - status.nFlags |= FLAG_MANUAL_LIGHT; - else - status.nFlags &= ~FLAG_MANUAL_LIGHT; - break; +L_CMD_HEARTBEAT: + m_nLastReceivedTime = millis(); + return; - // Time - case CMD_SET_TIME_NIGHT: - config.nNightStartHour = pkt.u16[0]; - config.nNightStartMin = pkt.u16[1]; - config.nNightEndHour = pkt.u16[2]; - config.nNightEndMin = pkt.u16[3]; - break; - case CMD_SET_WIFI_CLIENT_DISPLAY: - config.m_nDisplayTempHigh = pkt.n16[0]; - config.m_nDisplayTempLow = pkt.n16[1]; - config.m_nDisplayTime = pkt.n16[2]; - config.m_fShowRealTime = pkt.n16[3]; - config.m_fShowHistory = pkt.n16[4]; - ESP_LOGI(TAG_WIFI_HOST,"WiFi - Client Display Settings changed."); - break; +L_CMD_HELLO: + DPRINTLN("[WiFi] HELLO received"); + pkt.u16[0] = SIGNATURE1; + pkt.n16[1] = (int16_t)sizeof(CONFIG_TYPE); + pkt.u16[2] = SIGNATURE2; + SendPacket(pkt); + SendData((uint8_t*)&config, sizeof(CONFIG_TYPE)); + m_bHelloSent = true; + return; - default: - ESP_LOGI(TAG_WIFI_HOST,"WiFi - Packet Received Type: %d\n", pkt.cmd); - break; +L_CMD_DROP_CONNECTION: + wifiClient.stop(); + m_bClientConnected = false; + m_nMode = MODE_WAITING; + DPRINTLN("[WiFI] Host - Client requests to DROP CONNECTION"); + return; + +L_CMD_RESET_REASON: + pkt.n16[0] = (int16_t)esp_reset_reason(); + SendPacket(pkt); + return; + +L_CMD_RESTART: + if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == SIGNATURE2) { + if (pkt.op) + config.save(); + pkt.cmd = CMD_DROP_CONNECTION; + SendPacket(pkt); + Restart(); } + return; + +L_CMD_SEND_HISTORY: + if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == SIGNATURE2) { + int16_t count = history.getRingCount(); + if (count > 0 ) { + pkt.op = count; + SendPacket(pkt); + int16_t size = history.getRingSize(); + if (count < size) { + SendData(history.getRingData1(), sizeof(STATUS_TYPE) * count); + } else { + int count1st = size - history.getRingTail(); + SendData(history.getRingData1(), sizeof(STATUS_TYPE) * count1st); + m_bSendHistoryPending = true; + m_nPendingHistoryCount = history.getRingHead(); + } + } + } + return; + +L_CMD_RESET_SENSOR: + aht25.setScanFlag(true); + aht10_0x39.setScanFlag(true); + return; + +L_CMD_RESET_DISPLAY: + return; + +L_CMD_INIT_CONFIG: + if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { + config.init(); + config.save(); + } + return; + +L_CMD_LOAD_CONFIG: + if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { + config.load(); + history.loadPID(); + } + return; + +L_CMD_SAVE_CONFIG: + if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { + config.save(); + } + return; + +L_CMD_RECV_CONFIG: + if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { + ReceiveData((uint8_t *)&configCopy, sizeof(CONFIG_TYPE)); + m_bReceiveConfigPending = true; + m_bSaveReceivedConfig = pkt.op ? true : false; + DPRINTLN("[WiFi] Host - Receive Config initiated..."); + } + return; + +L_CMD_SEND_CONFIG: + if (pkt.u16[0] == SIGNATURE1 && pkt.u16[1] == sizeof(CONFIG_STRUCT) && pkt.u16[2] == SIGNATURE2) { + SendPacket(pkt); + SendData((const uint8_t *)&config, sizeof(config)); + DPRINTLN("[WiFi] Host - Send Config initiated..."); + } + return; + +L_CMD_SET_DEVICE_PARAM: + config.deviceParamArray[pkt.op] = pkt.device; + return; + +L_CMD_GET_DEVICE_PARAM: + pkt.device = config.deviceParamArray[pkt.op]; + return; + +L_CMD_GET_CONTROL: + pkt.by[0] = config.bSmartControl ? 0xFF : 0x00; + pkt.by[1] = config.bNightControl ? 0xFF : 0x00; + pkt.by[2] = config.bControlTemperature ? 0xFF : 0x00; + pkt.by[3] = config.bControlHumidity ? 0xFF : 0x00; + SendPacket(pkt); + return; + +L_CMD_SET_CONTROL: + config.bSmartControl = pkt.by[0] ? true : false; + config.bNightControl = pkt.by[1] ? true : false; + config.bControlTemperature = pkt.by[2] ? true : false; + config.bControlHumidity = pkt.by[3] ? true : false; + return; + +L_CMD_SET_TEMP_TARGET: + config.nTempTarget = pkt.u16[0]; + config.nTempTargetNight = pkt.u16[1]; + return; + +L_CMD_SET_TEMP_TARGET_NIGHT: + config.nTempTargetNight = pkt.u16[0]; + return; + +L_CMD_SET_HUMID_TARGET: + config.nHumidTarget = pkt.u16[0]; + return; + +L_CMD_SET_SENSOR_OFFSET: + config.nTemp1Offset = pkt.n16[0]; + config.nTemp2Offset = pkt.n16[1]; + config.nTemp3Offset = pkt.n16[2]; + config.nHumid1Offset = pkt.n16[3]; + config.nHumid2Offset = pkt.n16[4]; + //config.nHumid3Offset = pkt.n16[5]; T3 = NTC No Humidity + return; + +L_CMD_SET_HEATER1_DUTY: + status.nHeater1Duty = pkt.u16[0]; +L_CMD_SET_MANUAL_HEATER1: + if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_HEATER1; + else status.nFlags &= ~FLAG_MANUAL_HEATER1; + if (status.nHeater1Duty == 0) setHeater1Duty(0); + return; + +L_CMD_SET_HEATER2_DUTY: + status.nHeater2Duty = pkt.u16[0]; +L_CMD_SET_MANUAL_HEATER2: + if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_HEATER2; + else status.nFlags &= ~FLAG_MANUAL_HEATER2; + if (status.nHeater2Duty == 0) setHeater2Duty(0); + return; + +L_CMD_SET_MIST_DUTY: + status.nMistDuty = pkt.u16[0]; +L_CMD_SET_MANUAL_MIST: + if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_MIST; + else status.nFlags &= ~FLAG_MANUAL_MIST; + return; + +L_CMD_SET_FAN_DUTY: + status.nFanDuty = pkt.u16[0]; +L_CMD_SET_MANUAL_FAN: + if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_FAN; + else status.nFlags &= ~FLAG_MANUAL_FAN; + return; + +L_CMD_SET_MOTOR_DUTY: + status.nMotorDuty = pkt.u16[0]; +L_CMD_SET_MANUAL_MOTOR: + if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_MOTOR; + else status.nFlags &= ~FLAG_MANUAL_MOTOR; + return; + +L_CMD_SET_LIGHT_DUTY: + status.nLightTargetDuty = pkt.u16[0]; +L_CMD_SET_MANUAL_LIGHT: + if (pkt.u16[1]) status.nFlags |= FLAG_MANUAL_LIGHT; + else status.nFlags &= ~FLAG_MANUAL_LIGHT; + return; + +L_CMD_SET_TIME_NIGHT: + config.nNightStartHour = pkt.u16[0]; + config.nNightStartMin = pkt.u16[1]; + config.nNightEndHour = pkt.u16[2]; + config.nNightEndMin = pkt.u16[3]; + return; + +L_CMD_SET_WIFI_CLIENT_DISPLAY: + config.m_nDisplayTempHigh = pkt.n16[0]; + config.m_nDisplayTempLow = pkt.n16[1]; + config.m_nDisplayTime = pkt.n16[2]; + config.m_fShowRealTime = pkt.n16[3]; + config.m_fShowHistory = pkt.n16[4]; + return; + +L_CMD_INIT_PID_PARAM: +L_CMD_SAVE_PID_PARAM: + history.savePID(); + return; + +L_CMD_LOAD_PID_PARAM: + history.loadPID(); + return; + +L_CMD_SET_PID: + config.Kp_Temp1 = f16tof32(pkt.u16[0]); + config.Kd_Temp1 = f16tof32(pkt.u16[1]); + config.LR_Temp1 = f16tof32(pkt.u16[2]); + config.Kp_Temp2 = f16tof32(pkt.u16[3]); + config.Kd_Temp2 = f16tof32(pkt.u16[4]); + config.LR_Temp2 = f16tof32(pkt.u16[5]); + config.Kp_Temp3 = f16tof32(pkt.u16[6]); + config.Kd_Temp3 = f16tof32(pkt.u16[7]); + config.LR_Temp3 = f16tof32(pkt.u16[8]); + config.Kp_Humidity = f16tof32(pkt.u16[9]); + config.Kd_Humidity = f16tof32(pkt.u16[10]); + config.LR_Humidity = f16tof32(pkt.u16[11]); + config.Kp_Humid2 = f16tof32(pkt.u16[12]); + config.Kd_Humid2 = f16tof32(pkt.u16[13]); + config.LR_Humid2 = f16tof32(pkt.u16[14]); + config.Kp_Humid3 = f16tof32(pkt.u16[15]); + config.Kd_Humid3 = f16tof32(pkt.u16[16]); + config.LR_Humid3 = f16tof32(pkt.u16[17]); + history.loadPID(); + return; + +L_CMD_GET_PID: + pkt.u16[0] = f32tof16(config.Kp_Temp1); + pkt.u16[1] = f32tof16(config.Kd_Temp1); + pkt.u16[2] = f32tof16(config.LR_Temp1); + pkt.u16[3] = f32tof16(config.Kp_Temp2); + pkt.u16[4] = f32tof16(config.Kd_Temp2); + pkt.u16[5] = f32tof16(config.LR_Temp2); + pkt.u16[6] = f32tof16(config.Kp_Temp3); + pkt.u16[7] = f32tof16(config.Kd_Temp3); + pkt.u16[8] = f32tof16(config.LR_Temp3); + pkt.u16[9] = f32tof16(config.Kp_Humidity); + pkt.u16[10] = f32tof16(config.Kd_Humidity); + pkt.u16[11] = f32tof16(config.LR_Humidity); + pkt.u16[12] = f32tof16(config.Kp_Humid2); + pkt.u16[13] = f32tof16(config.Kd_Humid2); + pkt.u16[14] = f32tof16(config.LR_Humid2); + pkt.u16[15] = f32tof16(config.Kp_Humid3); + pkt.u16[16] = f32tof16(config.Kd_Humid3); + pkt.u16[17] = f32tof16(config.LR_Humid3); + SendPacket(pkt); + return; + +L_DEFAULT: + DPRINTF("[WiFi] Host - Unknown Packet: %d\n", pkt.cmd); + return; } -IRAM_ATTR -int CWiFiHost::SendPacket(TCP_PACKET& pkt) +IRAM_ATTR int CWiFiHost::SendPacket(TCP_PACKET& pkt) { size_t sent = 0; if (m_bClientConnected && wifiClient && wifiClient.connected()) @@ -720,23 +756,21 @@ int CWiFiHost::SendPacket(TCP_PACKET& pkt) return sent; } -IRAM_ATTR -size_t CWiFiHost::SendData(const uint8_t* data, size_t size) { +IRAM_ATTR size_t CWiFiHost::SendData(const uint8_t* data, size_t size) { if (data != nullptr) { m_nMode = MODE_SEND; m_pDataSend_data = (char *) data; m_nDataSend_size = size; m_nDataSend_sent = 0; - ESP_LOGI(TAG_WIFI_HOST,"WfFi Host - SendData(size: %d)\n", size); + DPRINTF("[HOST] Host - SendData(size: %d)\n", size); return size; } return 0; } -IRAM_ATTR // This function sends a small "chunk" then returns false. // It returns true ONLY when the entire buffer is finished. -bool CWiFiHost::SendData(unsigned long clock) +IRAM_ATTR bool CWiFiHost::SendData(unsigned long clock) { if (!m_pDataSend_data || m_nDataSend_size == 0) return true; @@ -766,8 +800,7 @@ bool CWiFiHost::SendData(unsigned long clock) return true; } -IRAM_ATTR -size_t CWiFiHost::ReceiveData(uint8_t* data, size_t size) +IRAM_ATTR size_t CWiFiHost::ReceiveData(uint8_t* data, size_t size) { m_nMode = MODE_RECV; m_pDataReceive_data = (char *) data; @@ -776,8 +809,7 @@ size_t CWiFiHost::ReceiveData(uint8_t* data, size_t size) return size; } -IRAM_ATTR -bool CWiFiHost::ReceiveData(unsigned long clock) +MY_IRAM_ATTR bool CWiFiHost::ReceiveData(unsigned long clock) { // Receive Data size_t nSize = 0; @@ -806,22 +838,25 @@ bool CWiFiHost::ReceiveData(unsigned long clock) if (m_bReceiveConfigPending && m_pDataReceive_data == (char *)&configCopy) { config = configCopy; history.loadPID(); - ESP_LOGI(TAG_WIFI_HOST,"WiFi - Config Received"); + DPRINTLN("[WiFi] Host - Config Received"); m_bReceiveConfigPending = false; + if (m_bSaveReceivedConfig) { + config.save(); + m_bSaveReceivedConfig = false; + } } - ESP_LOGI(TAG_WIFI_HOST," ReceiveData: Data Receive Completed!"); + DPRINTLN("[WIFI] Host - ReceiveData: Data Receive Completed!"); return true; } if (nSize <= 0 && clock - m_nLastReceivedTime > 5000) { - ESP_LOGI(TAG_WIFI_HOST," ReceiveData: TimeOut Abort!"); + DPRINTLN("[WIFI] Host - ReceiveData: TimeOut Abort!"); return true; } return false; } -IRAM_ATTR -void CWiFiHost::SendHeartBeat() { +IRAM_ATTR void CWiFiHost::SendHeartBeat() { if (m_bHelloSent) { hostPacket.cmd = CMD_HEARTBEAT; time_t now = time(NULL); // Get current time in seconds diff --git a/WiFiHost.h b/WiFiHost.h index 0dd96e8..0f3daa1 100644 --- a/WiFiHost.h +++ b/WiFiHost.h @@ -46,97 +46,58 @@ enum OPERATION_MODE { enum ENUM_COMMAND { - // Command + // Connection & control CMD_HEARTBEAT = 1, // 1 HeartBeat - prevents disconnect from the host - - // Connection - CMD_HELLO = 101, // 0 Hello + CMD_HELLO, // 0 Hello CMD_DROP_CONNECTION, CMD_RESET_REASON, - - // Device Command - CMD_SAVE_RESTART = 201, - CMD_RESET_RESTART, + CMD_RESTART, CMD_SEND_HISTORY, - CMD_PAUSE, - CMD_RESUME, CMD_RESET_SENSOR, CMD_RESET_DISPLAY, - - // OTA Update - CMD_UPDATE_CHECK = 301, - CMD_UPDATE_AVAILABLE, - CMD_UPDATE_FORCED, // Config - CMD_INIT_CONFIG = 1201, + CMD_INIT_CONFIG, CMD_LOAD_CONFIG, CMD_SAVE_CONFIG, CMD_SEND_CONFIG, CMD_RECV_CONFIG, - CMD_SEND_CONFIG_SERVER, - CMD_LOAD_CONFIG_SERVER, + CMD_SET_DEVICE_PARAM, + CMD_GET_DEVICE_PARAM, + + // control + CMD_SET_CONTROL, + CMD_GET_CONTROL, + // Set + CMD_SET_TEMP_TARGET, + CMD_SET_TEMP_TARGET_NIGHT, + CMD_SET_HUMID_TARGET, + CMD_SET_SENSOR_OFFSET, + CMD_SET_HEATER1_DUTY, + CMD_SET_MANUAL_HEATER1, + CMD_SET_HEATER2_DUTY, + CMD_SET_MANUAL_HEATER2, + CMD_SET_MIST_DUTY, + CMD_SET_MANUAL_MIST, + CMD_SET_FAN_DUTY, + CMD_SET_MANUAL_FAN, + CMD_SET_MOTOR_DUTY, + CMD_SET_MANUAL_MOTOR, + CMD_SET_LIGHT_DUTY, + CMD_SET_MANUAL_LIGHT, + CMD_SET_TIME_NIGHT, + CMD_SET_WIFI_CLIENT_DISPLAY, // Graph TempHigh, TempLow, TimeScale etc. + // PID - CMD_INIT_PID_PARAM = 1301, + CMD_INIT_PID_PARAM, CMD_LOAD_PID_PARAM, CMD_SAVE_PID_PARAM, CMD_SET_PID, CMD_GET_PID, - - // Control - CMD_SET_CONTROL = 1401, - CMD_GET_CONTROL, - - // Operation - CMD_SET_TEMP_TARGET = 1501, - CMD_SET_TEMP_TARGET_NIGHT, - CMD_SET_HUMID_TARGET, - CMD_SET_SENSOR_OFFSET, - CMD_SET_AC1_PARAM, - CMD_SET_AC2_PARAM, - CMD_SET_MIST_PARAM, - CMD_SET_FAN_PARAM, - CMD_SET_MOTOR_PARAM, - CMD_SET_LIGHT_PARAM, - - // Status - CMD_SET_HEATER1_DUTY = 2101, - CMD_SET_HEATER2_DUTY, - CMD_SET_MIST_DUTY, - CMD_SET_FAN_DUTY, - CMD_SET_FAN_DUTY_AUTO, - CMD_SET_MOTOR_DUTY, - CMD_SET_MOTOR_DUTY_AUTO, - CMD_SET_LIGHT_DUTY, - - // Manual Operations - CMD_SET_MANUAL_HEATER1 = 2201, - CMD_SET_MANUAL_HEATER2, - CMD_SET_MANUAL_MIST, - CMD_SET_MANUAL_FAN, - CMD_SET_MANUAL_MOTOR, - CMD_SET_MANUAL_LIGHT, - - // Time - CMD_SET_TIME_HEATER1 = 2301, - CMD_SET_TIME_HEATER2, - CMD_SET_TIME_MIST, - CMD_SET_TIME_FAN, - CMD_SET_TIME_MOTOR, - CMD_SET_TIME_LIGHT, - CMD_SET_TIME_NIGHT, - - // UI - CMD_SET_WIFI_CLIENT_DISPLAY = 2401, // Graph TempHigh, TempLow, TimeScale etc. - CMD_SET_OLED_CONTRAST, - CMD_SET_OLED_DISPLAY_CHECKAC, - - // Debugging - CMD_HELLO_DEBUG = 9101, - CMD_SHOW_CODE, - COMPUTE_TIME_MAX, - CMD_INVALID = 9999 + + // End of valid command + CMD_COUNT }; #pragma pack(push) /* push current alignment to stack */ @@ -157,6 +118,7 @@ typedef struct TCP_PACKET_STRUCT int32_t n32[10]; uint32_t u32[10]; float f[10]; + float f16[20]; STATUS_TYPE status; DEVICE_PARAM_TYPE device; }; //40 : 52 @@ -250,6 +212,7 @@ private: size_t m_nDataReceive_received; bool m_bReceiveConfigPending; + bool m_bSaveReceivedConfig; bool m_bSendHistoryPending; int16_t m_nPendingHistoryCount; diff --git a/zcd.cpp b/zcd.cpp index e1d4d4d..d46b2ec 100644 --- a/zcd.cpp +++ b/zcd.cpp @@ -26,9 +26,6 @@ #define EFFECTIVE_POWER 0.86 #define LEADING_TIME_RATIO 0.06 -#define PHASE_CONTROL 0 -#define ZCD_CONTROL 1 - // ESP32 Clock Constants const uint32_t AC_CYCLE_TIME_CLOCKS = 8333; // Half cycle of 60Hz AC in clock cycles const uint32_t EFFECTIVE_HALF_CYCLE = EFFECTIVE_POWER * AC_CYCLE_TIME_CLOCKS; // Effective half cycle in clock cycles @@ -103,7 +100,7 @@ short getHeater2Duty() { } // Function to set the duty based on percentage (0 to 10000) -void IRAM_ATTR setHeater1Duty(short duty) { +MY_IRAM_ATTR void setHeater1Duty(short duty) { if (ac1ControlMode == ZCD_CONTROL) { if (duty > 10000) duty = 10000; dutyAC1TableIndex = (uint8_t)((duty + 10000/32)/625); @@ -130,11 +127,11 @@ void IRAM_ATTR setHeater1Duty(short duty) { uint32_t nDuty = duty * PWM_FULL / 10000; ledcWrite(PIN_LED_HEATER1, PWM_FULL - nDuty); - ESP_LOGD(TAG_ZCD,"Set Duty: %.2f%%, Timer Count: %u clock cycles", duty, dutyHeater1); + //DPRINTF("[ZCD] Set Duty: %.2f%%, Timer Count: %u clock cycles", duty, dutyHeater1); } // Function to set the duty based on percentage (0 to 10000) -void IRAM_ATTR setHeater2Duty(short duty) { +MY_IRAM_ATTR void setHeater2Duty(short duty) { if (config.bAC2_OnOff) { if (duty >= 10000) { duty = 10000; @@ -171,19 +168,9 @@ void IRAM_ATTR setHeater2Duty(short duty) { uint32_t nDuty = duty * PWM_FULL / 10000; ledcWrite(PIN_LED_HEATER2, PWM_FULL - nDuty); - ESP_LOGD(TAG_ZCD,"Set Duty: %.2f%%, Timer Count: %u clock cycles\n", duty, dutyHeater2); + //DPRINTF("[ZCD] Set Duty: %.2f%%, Timer Count: %u clock cycles\n", duty, dutyHeater2); } -#define SET_TIMER_0_SAFE(duty) do { \ - timerWrite(timerHeater1, 0); \ - timerAlarm(timerHeater1, duty, false, 0); \ -} while(0) - -#define SET_TIMER_1_SAFE(duty) do { \ - timerWrite(timerHeater2, 0); \ - timerAlarm(timerHeater2, duty, false, 0); \ -} while(0) - void IRAM_ATTR timer0ISR(void *) { #ifdef DEBUG_ZCD zcdLoadISRCount++; @@ -233,7 +220,7 @@ void IRAM_ATTR timer1ISR(void *) // Zero-Cross Detection Interrupt Service Routine void IRAM_ATTR zcdACISR(void *) { // 1. Power side AC ZCD Count - zcdACISRCount++; + zcdACISRCount = zcdACISRCount + 1; fireStatusTimer0 = 0; fireStatusTimer1 = 0; @@ -267,13 +254,13 @@ void IRAM_ATTR zcdACISR(void *) { timer_set_alarm(TIMER_GROUP_1, TIMER_1, TIMER_ALARM_EN); fire_enable_2 = true; } - seqStep = ++seqStep & 0x0F; + seqStep = (seqStep + 1) & 0x0F; } void IRAM_ATTR zcdLoadISR(void *) { // Load side AC ZCD Count #ifndef DEBUG_ZCD - zcdLoadISRCount++; + zcdLoadISRCount = zcdLoadISRCount + 1; #endif } diff --git a/zcd.h b/zcd.h index 0ce9847..222dedc 100644 --- a/zcd.h +++ b/zcd.h @@ -3,17 +3,16 @@ // ZCD void setupZCD(); +short getHeater1Duty(); void setHeater1Duty(short duty); void setHeater2Duty(short duty); -short getHeater1Duty(); -void IRAM_ATTR zcdACISR(void *); -void IRAM_ATTR zcdLoadISR(void *); -void IRAM_ATTR timer0ISR(void *); -void IRAM_ATTR timer1ISR(void *); +void zcdACISR(void *); +void zcdLoadISR(void *); +void timer0ISR(void *); +void timer1ISR(void *); -#define DEBUG_ZCD -#define ENABLE_TIMERS +//#define DEBUG_ZCD #if defined(ESP8266) void setMistDuty(short duty);