diff --git a/code/espurna/board.cpp b/code/espurna/board.cpp index de4f21c9ca..f291c77652 100644 --- a/code/espurna/board.cpp +++ b/code/espurna/board.cpp @@ -7,312 +7,7 @@ BOARD MODULE #include "espurna.h" #include "relay.h" #include "sensor.h" - -//-------------------------------------------------------------------------------- - -PROGMEM const char espurna_modules[] = - #if ALEXA_SUPPORT - "ALEXA " - #endif - #if API_SUPPORT - "API " - #endif - #if BUTTON_SUPPORT - "BUTTON " - #endif - #if DEBUG_SERIAL_SUPPORT - "DEBUG_SERIAL " - #endif - #if DEBUG_TELNET_SUPPORT - "DEBUG_TELNET " - #endif - #if DEBUG_UDP_SUPPORT - "DEBUG_UDP " - #endif - #if DEBUG_WEB_SUPPORT - "DEBUG_WEB " - #endif - #if DOMOTICZ_SUPPORT - "DOMOTICZ " - #endif - #if ENCODER_SUPPORT - "ENCODER " - #endif - #if FAN_SUPPORT - "FAN " - #endif - #if HOMEASSISTANT_SUPPORT - "HOMEASSISTANT " - #endif - #if I2C_SUPPORT - "I2C " - #endif - #if INFLUXDB_SUPPORT - "INFLUXDB " - #endif - #if IR_SUPPORT - "IR " - #endif - #if LED_SUPPORT - "LED " - #endif - #if LLMNR_SUPPORT - "LLMNR " - #endif - #if MDNS_SERVER_SUPPORT - "MDNS " - #endif - #if MQTT_SUPPORT - "MQTT " - #endif - #if NETBIOS_SUPPORT - "NETBIOS " - #endif - #if NOFUSS_SUPPORT - "NOFUSS " - #endif - #if NTP_SUPPORT - "NTP " - #endif - #if PROMETHEUS_SUPPORT - "METRICS " - #endif - #if RELAY_SUPPORT - "RELAY " - #endif - #if RFM69_SUPPORT - "RFM69 " - #endif - #if RFB_SUPPORT - "RFB " - #endif - #if RPN_RULES_SUPPORT - "RPN_RULES " - #endif - #if SCHEDULER_SUPPORT - "SCHEDULER " - #endif - #if SENSOR_SUPPORT - "SENSOR " - #endif - #if SPIFFS_SUPPORT - "SPIFFS " - #endif - #if SSDP_SUPPORT - "SSDP " - #endif - #if TELNET_SUPPORT - #if TELNET_SERVER == TELNET_SERVER_WIFISERVER - "TELNET_SYNC " - #else - "TELNET " - #endif // TELNET_SERVER == TELNET_SERVER_WIFISERVER - #endif - #if TERMINAL_SUPPORT - "TERMINAL " - #endif - #if GARLAND_SUPPORT - "GARLAND " - #endif - #if THERMOSTAT_SUPPORT - "THERMOSTAT " - #endif - #if THERMOSTAT_DISPLAY_SUPPORT - "THERMOSTAT_DISPLAY " - #endif - #if THINGSPEAK_SUPPORT - "THINGSPEAK " - #endif - #if UART_MQTT_SUPPORT - "UART_MQTT " - #endif - #if WEB_SUPPORT - "WEB " - #endif - ""; - -PROGMEM const char espurna_ota_modules[] = - #if OTA_ARDUINOOTA_SUPPORT - "ARDUINO " - #endif - #if (OTA_CLIENT == OTA_CLIENT_ASYNCTCP) - "ASYNCTCP " - #endif - #if (OTA_CLIENT == OTA_CLIENT_HTTPUPDATE) - #if (SECURE_CLIENT == SECURE_CLIENT_NONE) - "*HTTPUPDATE " - #endif - #if (SECURE_CLIENT == SECURE_CLIENT_AXTLS) - "*HTTPUPDATE_AXTLS " - #endif - #if (SECURE_CLIENT == SECURE_CLIENT_BEARSSL) - "*HTTPUPDATE_BEARSSL " - #endif - #endif // OTA_CLIENT_HTTPUPDATE - #if OTA_MQTT_SUPPORT - "MQTT " - #endif - #if WEB_SUPPORT - "WEB " - #endif - ""; - -PROGMEM const char espurna_webui[] = - #if WEBUI_IMAGE == WEBUI_IMAGE_SMALL - "SMALL" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_LIGHT - "LIGHT" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_SENSOR - "SENSOR" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_RFBRIDGE - "RFBRIDGE" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_RFM69 - "RFM69" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_LIGHTFOX - "LIGHTFOX" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_GARLAND - "GARLAND" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_THERMOSTAT - "THERMOSTAT" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_CURTAIN - "CURTAIN" - #endif - #if WEBUI_IMAGE == WEBUI_IMAGE_FULL - "FULL" - #endif - ""; - -#if SENSOR_SUPPORT - -PROGMEM const char espurna_sensors[] = - #if AM2320_SUPPORT - "AM2320_I2C " - #endif - #if ANALOG_SUPPORT - "ANALOG " - #endif - #if BH1750_SUPPORT - "BH1750 " - #endif - #if BMP180_SUPPORT - "BMP180 " - #endif - #if BMX280_SUPPORT - "BMX280 " - #endif - #if BME680_SUPPORT - "BME680 " - #endif - #if CSE7766_SUPPORT - "CSE7766 " - #endif - #if DALLAS_SUPPORT - "DALLAS " - #endif - #if DHT_SUPPORT - "DHTXX " - #endif - #if DIGITAL_SUPPORT - "DIGITAL " - #endif - #if ECH1560_SUPPORT - "ECH1560 " - #endif - #if EMON_ADC121_SUPPORT - "EMON_ADC121 " - #endif - #if EMON_ADS1X15_SUPPORT - "EMON_ADX1X15 " - #endif - #if EMON_ANALOG_SUPPORT - "EMON_ANALOG " - #endif - #if EVENTS_SUPPORT - "EVENTS " - #endif - #if GEIGER_SUPPORT - "GEIGER " - #endif - #if GUVAS12SD_SUPPORT - "GUVAS12SD " - #endif - #if HLW8012_SUPPORT - "HLW8012 " - #endif - #if LDR_SUPPORT - "LDR " - #endif - #if MHZ19_SUPPORT - "MHZ19 " - #endif - #if MICS2710_SUPPORT - "MICS2710 " - #endif - #if MICS5525_SUPPORT - "MICS5525 " - #endif - #if NTC_SUPPORT - "NTC " - #endif - #if PMSX003_SUPPORT - "PMSX003 " - #endif - #if PULSEMETER_SUPPORT - "PULSEMETER " - #endif - #if PZEM004T_SUPPORT - "PZEM004T " - #endif - #if SDS011_SUPPORT - "SDS011 " - #endif - #if SENSEAIR_SUPPORT - "SENSEAIR " - #endif - #if SHT3X_I2C_SUPPORT - "SHT3X_I2C " - #endif - #if SI7021_SUPPORT - "SI7021 " - #endif - #if SONAR_SUPPORT - "SONAR " - #endif - #if T6613_SUPPORT - "T6613 " - #endif - #if TMP3X_SUPPORT - "TMP3X " - #endif - #if V9261F_SUPPORT - "V9261F " - #endif - #if VEML6075_SUPPORT - "VEML6075 " - #endif - #if VL53L1X_SUPPORT - "VL53L1X " - #endif - #if EZOPH_SUPPORT - "EZOPH " - #endif - #if ADE7953_SUPPORT - "ADE7953 " - #endif - #if SI1145_SUPPORT - "SI1145 " - #endif - ""; - -#endif // SENSOR_SUPPORT == 1 +#include "utils.h" //-------------------------------------------------------------------------------- @@ -337,366 +32,371 @@ const String& getIdentifier() { return value; } -String getEspurnaModules() { - return FPSTR(espurna_modules); -} +// Full Chip ID (aka MAC) +// based on the [esptool.py](https://github.com/espressif/esptool) implementation +// - register addresses: https://github.com/espressif/esptool/blob/737825ba8d7aa696e4a9213cad932bceafb79f51/esptool.py#L1140-L1143 +// - chip id & mac: https://github.com/espressif/esptool/blob/737825ba8d7aa696e4a9213cad932bceafb79f51/esptool.py#L1235-L1254 + +const String& getFullChipId() { + static String out; + + if (!out.length()) { + uint32_t regs[3] { + READ_PERI_REG(0x3ff00050), + READ_PERI_REG(0x3ff00054), + READ_PERI_REG(0x3ff0005c)}; + + uint8_t mac[6] { + 0xff, + 0xff, + 0xff, + static_cast((regs[1] >> 8ul) & 0xfful), + static_cast(regs[1] & 0xffu), + static_cast((regs[0] >> 24ul) & 0xffu)}; -String getEspurnaOTAModules() { - return FPSTR(espurna_ota_modules); + if (mac[2] != 0) { + mac[0] = (regs[2] >> 16ul) & 0xffu; + mac[1] = (regs[2] >> 8ul) & 0xffu; + mac[2] = (regs[2] & 0xffu); + } else if (0 == ((regs[1] >> 16ul) & 0xff)) { + mac[0] = 0x18; + mac[1] = 0xfe; + mac[2] = 0x34; + } else if (1 == ((regs[1] >> 16ul) & 0xff)) { + mac[0] = 0xac; + mac[1] = 0xd0; + mac[2] = 0x74; + } + + char buffer[(sizeof(mac) * 2) + 1]; + if (hexEncode(mac, sizeof(mac), buffer, sizeof(buffer))) { + out = buffer; + } + } + + return out; } +const char* getEspurnaModules() { + static const char modules[] PROGMEM = +#if ALEXA_SUPPORT + "ALEXA " +#endif +#if API_SUPPORT + "API " +#endif +#if BUTTON_SUPPORT + "BUTTON " +#endif +#if DEBUG_SERIAL_SUPPORT + "DEBUG_SERIAL " +#endif +#if DEBUG_TELNET_SUPPORT + "DEBUG_TELNET " +#endif +#if DEBUG_UDP_SUPPORT + "DEBUG_UDP " +#endif +#if DEBUG_WEB_SUPPORT + "DEBUG_WEB " +#endif +#if DOMOTICZ_SUPPORT + "DOMOTICZ " +#endif +#if ENCODER_SUPPORT + "ENCODER " +#endif +#if FAN_SUPPORT + "FAN " +#endif +#if HOMEASSISTANT_SUPPORT + "HOMEASSISTANT " +#endif +#if I2C_SUPPORT + "I2C " +#endif +#if INFLUXDB_SUPPORT + "INFLUXDB " +#endif +#if IR_SUPPORT + "IR " +#endif +#if LED_SUPPORT + "LED " +#endif +#if LLMNR_SUPPORT + "LLMNR " +#endif +#if MDNS_SERVER_SUPPORT + "MDNS " +#endif +#if MQTT_SUPPORT + "MQTT " +#endif +#if NETBIOS_SUPPORT + "NETBIOS " +#endif +#if NOFUSS_SUPPORT + "NOFUSS " +#endif +#if NTP_SUPPORT + "NTP " +#endif +#if OTA_ARDUINOOTA_SUPPORT + "ARDUINO_OTA " +#endif +#if (OTA_CLIENT != OTA_CLIENT_NONE) + "OTA_CLIENT " +#endif +#if PROMETHEUS_SUPPORT + "METRICS " +#endif +#if RELAY_SUPPORT + "RELAY " +#endif +#if RFM69_SUPPORT + "RFM69 " +#endif +#if RFB_SUPPORT + "RFB " +#endif +#if RPN_RULES_SUPPORT + "RPN_RULES " +#endif +#if SCHEDULER_SUPPORT + "SCHEDULER " +#endif #if SENSOR_SUPPORT -String getEspurnaSensors() { - return FPSTR(espurna_sensors); + "SENSOR " +#endif +#if SPIFFS_SUPPORT + "SPIFFS " +#endif +#if SSDP_SUPPORT + "SSDP " +#endif +#if TELNET_SUPPORT +#if TELNET_SERVER == TELNET_SERVER_WIFISERVER + "TELNET_SYNC " +#else + "TELNET " +#endif // TELNET_SERVER == TELNET_SERVER_WIFISERVER +#endif +#if TERMINAL_SUPPORT + "TERMINAL " +#endif +#if GARLAND_SUPPORT + "GARLAND " +#endif +#if THERMOSTAT_SUPPORT + "THERMOSTAT " +#endif +#if THERMOSTAT_DISPLAY_SUPPORT + "THERMOSTAT_DISPLAY " +#endif +#if THINGSPEAK_SUPPORT + "THINGSPEAK " +#endif +#if UART_MQTT_SUPPORT + "UART_MQTT " +#endif +#if WEB_SUPPORT + "WEB " +#endif + ""; + + return modules; } -#endif // SENSOR_SUPPORT == 1 -String getEspurnaWebUI() { - return FPSTR(espurna_webui); +const char* getEspurnaWebUI() { + static const char webui[] PROGMEM = +#if WEBUI_IMAGE == WEBUI_IMAGE_SMALL + "SMALL" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_LIGHT + "LIGHT" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_SENSOR + "SENSOR" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_RFBRIDGE + "RFBRIDGE" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_RFM69 + "RFM69" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_LIGHTFOX + "LIGHTFOX" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_GARLAND + "GARLAND" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_THERMOSTAT + "THERMOSTAT" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_CURTAIN + "CURTAIN" +#endif +#if WEBUI_IMAGE == WEBUI_IMAGE_FULL + "FULL" +#endif + ""; + + return webui; } -bool isEspurnaCore() { - #if defined(ESPURNA_CORE) || defined(ESPURNA_CORE_WEBUI) - return true; - #else - return false; - #endif +#if SENSOR_SUPPORT + +const char* getEspurnaSensors() { + static const char sensors[] PROGMEM = +#if AM2320_SUPPORT + "AM2320_I2C " +#endif +#if ANALOG_SUPPORT + "ANALOG " +#endif +#if BH1750_SUPPORT + "BH1750 " +#endif +#if BMP180_SUPPORT + "BMP180 " +#endif +#if BMX280_SUPPORT + "BMX280 " +#endif +#if BME680_SUPPORT + "BME680 " +#endif +#if CSE7766_SUPPORT + "CSE7766 " +#endif +#if DALLAS_SUPPORT + "DALLAS " +#endif +#if DHT_SUPPORT + "DHTXX " +#endif +#if DIGITAL_SUPPORT + "DIGITAL " +#endif +#if ECH1560_SUPPORT + "ECH1560 " +#endif +#if EMON_ADC121_SUPPORT + "EMON_ADC121 " +#endif +#if EMON_ADS1X15_SUPPORT + "EMON_ADX1X15 " +#endif +#if EMON_ANALOG_SUPPORT + "EMON_ANALOG " +#endif +#if EVENTS_SUPPORT + "EVENTS " +#endif +#if GEIGER_SUPPORT + "GEIGER " +#endif +#if GUVAS12SD_SUPPORT + "GUVAS12SD " +#endif +#if HLW8012_SUPPORT + "HLW8012 " +#endif +#if LDR_SUPPORT + "LDR " +#endif +#if MHZ19_SUPPORT + "MHZ19 " +#endif +#if MICS2710_SUPPORT + "MICS2710 " +#endif +#if MICS5525_SUPPORT + "MICS5525 " +#endif +#if NTC_SUPPORT + "NTC " +#endif +#if PMSX003_SUPPORT + "PMSX003 " +#endif +#if PULSEMETER_SUPPORT + "PULSEMETER " +#endif +#if PZEM004T_SUPPORT + "PZEM004T " +#endif +#if SDS011_SUPPORT + "SDS011 " +#endif +#if SENSEAIR_SUPPORT + "SENSEAIR " +#endif +#if SHT3X_I2C_SUPPORT + "SHT3X_I2C " +#endif +#if SI7021_SUPPORT + "SI7021 " +#endif +#if SONAR_SUPPORT + "SONAR " +#endif +#if T6613_SUPPORT + "T6613 " +#endif +#if TMP3X_SUPPORT + "TMP3X " +#endif +#if V9261F_SUPPORT + "V9261F " +#endif +#if VEML6075_SUPPORT + "VEML6075 " +#endif +#if VL53L1X_SUPPORT + "VL53L1X " +#endif +#if EZOPH_SUPPORT + "EZOPH " +#endif +#if ADE7953_SUPPORT + "ADE7953 " +#endif +#if SI1145_SUPPORT + "SI1145 " +#endif + ""; + + return sensors; } +#endif + bool haveRelaysOrSensors() { bool result = false; result = (relayCount() > 0); - #if SENSOR_SUPPORT - result = result || (magnitudeCount() > 0); - #endif +#if SENSOR_SUPPORT + result = result || (magnitudeCount() > 0); +#endif return result; } -int getBoardId() { - #if defined(ESPURNA_CORE) || defined(ESPURNA_CORE_WEBUI) - return 0; - #elif defined(NODEMCU_LOLIN) - return 2; - #elif defined(NODEMCU_BASIC) - return 3; - #elif defined(WEMOS_D1_MINI) - return 4; - #elif defined(WEMOS_D1_MINI_RELAYSHIELD) - return 5; - #elif defined(WEMOS_D1_TARPUNA_SHIELD) - return 6; - #elif defined(TINKERMAN_ESPURNA_H06) - return 7; - #elif defined(TINKERMAN_ESPURNA_H08) - return 8; - #elif defined(TINKERMAN_ESPURNA_SWITCH) - return 9; - #elif defined(TINKERMAN_RFM69GW) - return 10; - #elif defined(ITEAD_SONOFF_BASIC) - return 11; - #elif defined(ITEAD_SONOFF_RF) - return 12; - #elif defined(ITEAD_SONOFF_MINI) - return 13; - #elif defined(ITEAD_SONOFF_TH) - return 14; - #elif defined(ITEAD_SONOFF_SV) - return 15; - #elif defined(ITEAD_SLAMPHER) - return 16; - #elif defined(ITEAD_S20) - return 17; - #elif defined(ITEAD_SONOFF_TOUCH) - return 18; - #elif defined(ITEAD_SONOFF_POW) - return 19; - #elif defined(ITEAD_SONOFF_POW_R2) - return 20; - #elif defined(ITEAD_SONOFF_DUAL) - return 21; - #elif defined(ITEAD_SONOFF_DUAL_R2) - return 22; - #elif defined(ITEAD_SONOFF_4CH) - return 23; - #elif defined(ITEAD_SONOFF_4CH_PRO) - return 24; - #elif defined(ITEAD_1CH_INCHING) - return 25; - #elif defined(ITEAD_MOTOR) - return 26; - #elif defined(ITEAD_BNSZ01) - return 27; - #elif defined(ITEAD_SONOFF_RFBRIDGE) - return 28; - #elif defined(ITEAD_SONOFF_B1) - return 29; - #elif defined(ITEAD_SONOFF_LED) - return 30; - #elif defined(ITEAD_SONOFF_T1_1CH) - return 31; - #elif defined(ITEAD_SONOFF_T1_2CH) - return 32; - #elif defined(ITEAD_SONOFF_T1_3CH) - return 33; - #elif defined(ITEAD_SONOFF_S31) - return 34; - #elif defined(ITEAD_SONOFF_S31_LITE) - return 35; - #elif defined(ITEAD_SONOFF_IFAN02) - return 36; - #elif defined(ORVIBO_B25) - return 37; - #elif defined(YJZK_SWITCH_1CH) - return 38; - #elif defined(YJZK_SWITCH_2CH) - return 39; - #elif defined(YJZK_SWITCH_3CH) - return 40; - #elif defined(ELECTRODRAGON_WIFI_IOT) - return 41; - #elif defined(WORKCHOICE_ECOPLUG) - return 42; - #elif defined(AITHINKER_AI_LIGHT) - return 43; - #elif defined(LYASI_LIGHT) - return 44; - #elif defined(MAGICHOME_LED_CONTROLLER) - return 45; - #elif defined(MAGICHOME_LED_CONTROLLER_20) - return 46; - #elif defined(MAGICHOME_ZJ_WFMN_A_11) - return 47; - #elif defined(MAGICHOME_ZJ_WFMN_B_11) - return 48; - #elif defined(MAGICHOME_ZJ_WFMN_C_11) - return 49; - #elif defined(MAGICHOME_ZJ_ESPM_5CH_B_13) - return 50; - #elif defined(MAGICHOME_ZJ_LB_RGBWW_L) - return 51; - #elif defined(HUACANXING_H801) - return 52; - #elif defined(HUACANXING_H802) - return 53; - #elif defined(JANGOE_WIFI_RELAY_NC) - return 54; - #elif defined(JANGOE_WIFI_RELAY_NO) - return 55; - #elif defined(JORGEGARCIA_WIFI_RELAYS) - return 56; - #elif defined(OPENENERGYMONITOR_MQTT_RELAY) - return 57; - #elif defined(WION_50055) - return 58; - #elif defined(EXS_WIFI_RELAY_V31) - return 59; - #elif defined(EXS_WIFI_RELAY_V50) - return 60; - #elif defined(GENERIC_V9261F) - return 61; - #elif defined(GENERIC_ECH1560) - return 62; - #elif defined(MANCAVEMADE_ESPLIVE) - return 63; - #elif defined(INTERMITTECH_QUINLED) - return 64; - #elif defined(ARILUX_AL_LC01) - return 65; - #elif defined(ARILUX_AL_LC02) - return 66; - #elif defined(ARILUX_AL_LC02_V14) - return 67; - #elif defined(ARILUX_AL_LC06) - return 68; - #elif defined(ARILUX_AL_LC11) - return 69; - #elif defined(ARILUX_E27) - return 70; - #elif defined(XENON_SM_PW702U) - return 71; - #elif defined(ISELECTOR_SM_PW702) - return 72; - #elif defined(AUTHOMETION_LYT8266) - return 73; - #elif defined(GIZWITS_WITTY_CLOUD) - return 74; - #elif defined(KMC_70011) - return 75; - #elif defined(EUROMATE_WIFI_STECKER_SCHUKO) - return 76; - #elif defined(EUROMATE_WIFI_STECKER_SCHUKO_V2) - return 77; - #elif defined(GENERIC_8CH) - return 78; - #elif defined(STM_RELAY) - return 79; - #elif defined(TONBUX_POWERSTRIP02) - return 80; - #elif defined(LINGAN_SWA1) - return 81; - #elif defined(HEYGO_HY02) - return 82; - #elif defined(MAXCIO_WUS002S) - return 83; - #elif defined(MAXCIO_WDE004) - return 84; - #elif defined(OUKITEL_P1) - return 85; - #elif defined(YIDIAN_XSSSA05) - return 86; - #elif defined(TONBUX_XSSSA01) - return 87; - #elif defined(TONBUX_XSSSA06) - return 88; - #elif defined(GREEN_ESP8266RELAY) - return 89; - #elif defined(IKE_ESPIKE) - return 90; - #elif defined(ARNIEX_SWIFITCH) - return 91; - #elif defined(GENERIC_ESP01S_RELAY_V40) - return 92; - #elif defined(GENERIC_ESP01S_RGBLED_V10) - return 93; - #elif defined(GENERIC_ESP01S_DHT11_V10) - return 94; - #elif defined(GENERIC_ESP01S_DS18B20_V10) - return 95; - #elif defined(PILOTAK_ESP_DIN_V1) - return 96; - #elif defined(HELTEC_TOUCHRELAY) - return 97; - #elif defined(ZHILDE_44EU_W) - return 98; - #elif defined(ALLNET_4DUINO_IOT_WLAN_RELAIS) - return 99; - #elif defined(LUANI_HVIO) - return 100; - #elif defined(TONBUX_MOSQUITO_KILLER) - return 101; - #elif defined(NEO_COOLCAM_NAS_WR01W) - return 102; - #elif defined(DELTACO_SH_P01) - return 103; - #elif defined(DELTACO_SH_P03USB) - return 104; - #elif defined(FORNORM_ZLD_34EU) - return 105; - #elif defined(BH_ONOFRE) - return 106; - #elif defined(BLITZWOLF_BWSHPX) - return 107; - #elif defined(BLITZWOLF_BWSHPX_V23) - return 108; - #elif defined(BLITZWOLF_BWSHP5) - return 109; - #elif defined(TECKIN_SP21) - return 110; - #elif defined(TECKIN_SP22_V14) - return 111; - #elif defined(GOSUND_WS1) - return 112; - #elif defined(HOMECUBE_16A) - return 113; - #elif defined(VANZAVANZU_SMART_WIFI_PLUG_MINI) - return 114; - #elif defined(GENERIC_AG_L4) - return 115; - #elif defined(ALLTERCO_SHELLY1) - return 116; - #elif defined(ALLTERCO_SHELLY2) - return 117; - #elif defined(ALLTERCO_SHELLY1PM) - return 118; - #elif defined(ALLTERCO_SHELLY25) - return 119; - #elif defined(LOHAS_E27_9W) - return 120; - #elif defined(LOHAS_E26_A19) - return 121; - #elif defined(TECKIN_SB53) - return 122; - #elif defined(XIAOMI_SMART_DESK_LAMP) - return 123; - #elif defined(PHYX_ESP12_RGB) - return 124; - #elif defined(IWOOLE_LED_TABLE_LAMP) - return 125; - #elif defined(GENERIC_GU10) - return 126; - #elif defined(GENERIC_E14) - return 127; - #elif defined(DELTACO_SH_LEXXW) - return 128; - #elif defined(DELTACO_SH_LEXXRGB) - return 129; - #elif defined(NEXETE_A19) - return 130; - #elif defined(LOMBEX_LUX_NOVA2_TUNABLE_WHITE) - return 131; - #elif defined(LOMBEX_LUX_NOVA2_WHITE_COLOR) - return 132; - #elif defined(BESTEK_MRJ1011) - return 133; - #elif defined(GBLIFE_RGBW_SOCKET) - return 134; - #elif defined(SMARTLIFE_MINI_SMART_SOCKET) - return 135; - #elif defined(HAMA_WIFI_STECKDOSE_00176533) - return 136; - #elif defined(DIGOO_NX_SP202) - return 137; - #elif defined(FOXEL_LIGHTFOX_DUAL) - return 138; - #elif defined(TECKIN_SP20) - return 139; - #elif defined(LITESUN_LA_WF3) - return 140; - #elif defined(PSH_WIFI_PLUG) - return 141; - #elif defined(PSH_RGBW_CONTROLLER) - return 142; - #elif defined(PSH_WIFI_SENSOR) - return 143; - #elif defined(JINVOO_VALVE_SM_AW713) - return 144; - #elif defined(TUYA_GENERIC_DIMMER) - return 145; - #elif defined(ETEKCITY_ESW01_USA) - return 146; - #elif defined(FS_UAP1) - return 147; - #elif defined(TFLAG_NX_SMX00) - return 148; - #elif defined(MUVIT_IO_MIOBULB001) - return 149; - #elif defined(HYKKER_SMART_HOME_POWER_PLUG) - return 150; - #elif defined(KOGAN_SMARTER_HOME_PLUG_W_POW) - return 151; - #elif defined(LSC_SMART_LED_LIGHT_STRIP) - return 152; - #elif defined(EHOMEDIY_WT02) - return 153; - #elif defined(EHOMEDIY_WT03) - return 154; - #elif defined(LINKSPRITE_LINKNODE_R4) - return 155; - #elif defined(GENERIC_ESP01_512KB) - return 156; - #elif defined(GOSUND_WP3) - return 157; - #elif defined(GENERIC_AG_L4_V3) - return 158; - #elif defined(PRODINO_WIFI) - return 159; - #elif defined(GOSUND_SP111) - return 160; - #elif defined(GOSUND_P1) - return 161; - #else - return -1; // CUSTOM - #endif -} +void boardSetup() { +#if DEBUG_SERIAL_SUPPORT + if (debugLogBuffer()) { + return; + } + DEBUG_MSG_P(PSTR("[MAIN] " APP_NAME " %s built %s\n"), getVersion(), buildTime().c_str()); + DEBUG_MSG_P(PSTR("[MAIN] " APP_AUTHOR "\n")); + DEBUG_MSG_P(PSTR("[MAIN] " APP_WEBSITE "\n\n")); + DEBUG_MSG_P(PSTR("[MAIN] CPU chip ID: %s\n"), getFullChipId().c_str()); + DEBUG_MSG_P(PSTR("[MAIN] SDK: %s\n"), ESP.getSdkVersion()); + DEBUG_MSG_P(PSTR("[MAIN] Arduino Core: %s\n"), getCoreVersion().c_str()); + DEBUG_MSG_P(PSTR("[MAIN] Support: %s\n"), getEspurnaModules()); +#if SENSOR_SUPPORT + DEBUG_MSG_P(PSTR("[MAIN] Sensors: %s\n"), getEspurnaSensors()); +#endif +#endif +} diff --git a/code/espurna/board.h b/code/espurna/board.h index 872128936d..2f8c856651 100644 --- a/code/espurna/board.h +++ b/code/espurna/board.h @@ -9,14 +9,11 @@ BOARD MODULE #include const String& getChipId(); +const String& getFullChipId(); const String& getIdentifier(); -String getEspurnaModules(); -String getEspurnaOTAModules(); -String getEspurnaSensors(); +const char* getEspurnaModules(); +const char* getEspurnaSensors(); +const char* getEspurnaWebUI(); -String getEspurnaWebUI(); - -bool isEspurnaCore(); - -int getBoardId(); +void boardSetup(); diff --git a/code/espurna/compat.h b/code/espurna/compat.h index 7730f24b34..7251a572e5 100644 --- a/code/espurna/compat.h +++ b/code/espurna/compat.h @@ -8,6 +8,16 @@ COMPATIBILITY BETWEEN 2.3.0 and latest versions #include "espurna.h" +// ----------------------------------------------------------------------------- + +inline constexpr bool isEspurnaCore() { +#if defined(ESPURNA_CORE) || defined(ESPURNA_CORE_WEBUI) + return true; +#else + return false; +#endif +} + // ----------------------------------------------------------------------------- // Core version 2.4.2 and higher changed the cont_t structure to a pointer: // https://github.com/esp8266/Arduino/commit/5d5ea92a4d004ab009d5f642629946a0cb8893dd#diff-3fa12668b289ccb95b7ab334833a4ba8L35 diff --git a/code/espurna/crash.cpp b/code/espurna/crash.cpp index e5b15b6514..4e577283b9 100644 --- a/code/espurna/crash.cpp +++ b/code/espurna/crash.cpp @@ -21,8 +21,11 @@ Copyright (C) 2019-2020 by Maxim Prokhorov #include "system.h" +#include "rtcmem.h" #include "storage_eeprom.h" +constexpr uint32_t EmptyTimestamp { 0xffffffff }; + bool _save_crash_enabled = true; size_t crashReservedSize() { @@ -101,8 +104,7 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack * Clears crash info CRASH_TIME value, later checked in crashDump() */ void crashClear() { - uint32_t crash_time = 0xFFFFFFFF; - eepromPut(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time); + eepromPut(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, EmptyTimestamp); eepromCommit(); } @@ -119,14 +121,14 @@ void _crashDump(Print& print, bool check) { uint32_t crash_time; eepromGet(EepromCrashBegin + SAVE_CRASH_CRASH_TIME, crash_time); - bool crash_time_erased = ((crash_time == 0) || (crash_time == 0xFFFFFFFF)); + bool crash_time_erased = ((crash_time == 0) || (crash_time == EmptyTimestamp)); if (check && crash_time_erased) { return; } uint8_t reason = eepromRead(EepromCrashBegin + SAVE_CRASH_RESTART_REASON); if (!crash_time_erased) { - snprintf_P(buffer, sizeof(buffer), PSTR("\nLatest crash was at %lu ms after boot\n"), crash_time); + snprintf_P(buffer, sizeof(buffer), PSTR("\nlatest crash was at %lu ms after boot\n"), crash_time); print.print(buffer); } @@ -214,12 +216,7 @@ void _crashDump(Print& print, bool check) { #if TERMINAL_SUPPORT void _crashTerminalCommand(const terminal::CommandContext& ctx) { - if ((ctx.argc == 2) && (ctx.argv[1].equals(F("force")))) { - crashForceDump(ctx.output); - } else { - crashDump(ctx.output); - crashClear(); - } + crashForceDump(ctx.output); terminalOK(ctx); } @@ -235,14 +232,30 @@ void crashDump(Print& print) { _crashDump(print, true); } +void crashResetReason(Print& print) { + auto reason = customResetReason(); + bool custom { CustomResetReason::None != reason }; + print.printf_P(PSTR("last reset reason: %s\n"), custom + ? customResetReasonToPayload(reason).c_str() + : ESP.getResetReason().c_str()); + + if (!custom) { + print.printf_P(PSTR("extra info: %s\n"), ESP.getResetInfo().c_str()); + } + + crashDump(print); +} + void crashSetup() { + if (!rtcmemStatus()) { + crashClear(); + } - #if TERMINAL_SUPPORT - terminalRegisterCommand(F("CRASH"), _crashTerminalCommand); - #endif +#if TERMINAL_SUPPORT + terminalRegisterCommand(F("CRASH"), _crashTerminalCommand); +#endif _save_crash_enabled = getSetting("sysCrashSave", 1 == SAVE_CRASH_ENABLED); - } #endif // DEBUG_SUPPORT diff --git a/code/espurna/crash.h b/code/espurna/crash.h index 863576cff0..286ea97c37 100644 --- a/code/espurna/crash.h +++ b/code/espurna/crash.h @@ -58,6 +58,7 @@ constexpr size_t CrashTraceReservedSize = CrashReservedSize - SAVE_CRASH_STACK_T size_t crashReservedSize(); +void crashResetReason(Print&); void crashForceDump(Print&); void crashDump(Print&); void crashClear(); diff --git a/code/espurna/debug.cpp b/code/espurna/debug.cpp index 2c84e96ccc..0bf524f2a5 100644 --- a/code/espurna/debug.cpp +++ b/code/espurna/debug.cpp @@ -35,7 +35,6 @@ char _udp_syslog_header[64]; bool _debug_enabled = false; - // ----------------------------------------------------------------------------- // printf-like debug methods // ----------------------------------------------------------------------------- @@ -376,8 +375,11 @@ bool _debugHeartbeat(heartbeat::Mask mask) { if (mask & heartbeat::Report::Uptime) DEBUG_MSG_P(PSTR("[MAIN] Uptime: %s\n"), getUptime().c_str()); - if (mask & heartbeat::Report::Freeheap) - infoHeapStats(); + if (mask & heartbeat::Report::Freeheap) { + auto stats = systemHeapStats(); + DEBUG_MSG_P(PSTR("[MAIN] %5u / %5u bytes available (%5u contiguous)\n"), + stats.available, systemInitialFreeHeap(), stats.usable); + } if ((mask & heartbeat::Report::Vcc) && (ADC_MODE_VALUE == ADC_VCC)) DEBUG_MSG_P(PSTR("[MAIN] Power: %lu mV\n"), ESP.getVcc()); diff --git a/code/espurna/homeassistant.cpp b/code/espurna/homeassistant.cpp index 74409b1bfe..7e381522f3 100644 --- a/code/espurna/homeassistant.cpp +++ b/code/espurna/homeassistant.cpp @@ -65,7 +65,7 @@ class Device { Strings(const Strings&) = delete; Strings(Strings&&) = default; - Strings(String&& prefix_, String&& name_, const String& identifier_, const String& version_, const String& manufacturer_, const String& device_) : + Strings(String&& prefix_, String&& name_, const String& identifier_, const char* version_, const char* manufacturer_, const char* device_) : prefix(std::move(prefix_)), name(std::move(name_)), identifier(identifier_), @@ -80,9 +80,9 @@ class Device { String prefix; String name; String identifier; - String version; - String manufacturer; - String device; + const char* version; + const char* manufacturer; + const char* device; }; using StringsPtr = std::unique_ptr; @@ -96,7 +96,7 @@ class Device { Device(const Device&) = delete; Device(Device&&) = default; - Device(String&& prefix, String&& name, const String& identifier, const String& version, const String& manufacturer, const String& device) : + Device(String&& prefix, String&& name, const String& identifier, const char* version, const char* manufacturer, const char* device) : _strings(std::make_unique(std::move(prefix), std::move(name), identifier, version, manufacturer, device)), _buffer(std::make_unique()), _root(_buffer->createObject()) @@ -105,9 +105,9 @@ class Device { ids.add(_strings->identifier.c_str()); _root["name"] = _strings->name.c_str(); - _root["sw"] = _strings->version.c_str(); - _root["mf"] = _strings->manufacturer.c_str(); - _root["mdl"] = _strings->device.c_str(); + _root["sw"] = _strings->version; + _root["mf"] = _strings->manufacturer; + _root["mdl"] = _strings->device; } const String& name() const { diff --git a/code/espurna/main.cpp b/code/espurna/main.cpp index 3e6ddb6f81..191dc0f785 100644 --- a/code/espurna/main.cpp +++ b/code/espurna/main.cpp @@ -116,9 +116,7 @@ void setup() { } setBoardName(); - // Show welcome message and system configuration - info(true); - + boardSetup(); wifiSetup(); otaSetup(); @@ -290,6 +288,7 @@ void setup() { if (_loop_delay != loop_delay) { setSetting("loopDelay", _loop_delay); } + } void loop() { diff --git a/code/espurna/mqtt.cpp b/code/espurna/mqtt.cpp index 0632e7bb39..522b9a7973 100644 --- a/code/espurna/mqtt.cpp +++ b/code/espurna/mqtt.cpp @@ -620,7 +620,7 @@ bool _mqttHeartbeat(heartbeat::Mask mask) { mqttSend(MQTT_TOPIC_APP, APP_NAME); if (mask & heartbeat::Report::Version) - mqttSend(MQTT_TOPIC_VERSION, getVersion().c_str()); + mqttSend(MQTT_TOPIC_VERSION, getVersion()); if (mask & heartbeat::Report::Board) mqttSend(MQTT_TOPIC_BOARD, getBoardName().c_str()); diff --git a/code/espurna/storage_eeprom.h b/code/espurna/storage_eeprom.h index d232ee893f..1140c65465 100644 --- a/code/espurna/storage_eeprom.h +++ b/code/espurna/storage_eeprom.h @@ -48,7 +48,7 @@ void eepromSetup(); extern EEPROM_Rotate EEPROMr; inline unsigned long eepromSpace() { - return EEPROMr.reserved() * SPI_FLASH_SEC_SIZE; + return EEPROMr.size() * SPI_FLASH_SEC_SIZE; } inline void eepromClear() { diff --git a/code/espurna/telnet.cpp b/code/espurna/telnet.cpp index 1b928867a6..7d5fab469e 100644 --- a/code/espurna/telnet.cpp +++ b/code/espurna/telnet.cpp @@ -23,6 +23,8 @@ Updated to use WiFiServer and support reverse connections by Niek van der Maas < #include #include "board.h" +#include "crash.h" +#include "terminal.h" #include "ws.h" #if TELNET_SERVER == TELNET_SERVER_ASYNC @@ -360,14 +362,6 @@ void _telnetNotifyConnected(unsigned char i) { DEBUG_MSG_P(PSTR("[TELNET] Client #%u connected\n"), i); - // If there is no terminal support automatically dump info and crash data - #if DEBUG_SUPPORT - #if not TERMINAL_SUPPORT - crashDump(terminalDefaultStream()); - crashClear(); - #endif - #endif - if (!isEspurnaCore()) { _telnetClientsAuth[i] = !_telnetAuth; if (_telnetAuth) { @@ -381,6 +375,10 @@ void _telnetNotifyConnected(unsigned char i) { _telnetClientsAuth[i] = true; } +#if DEBUG_SUPPORT + crashResetReason(terminalDefaultStream()); +#endif + } #if TELNET_SERVER == TELNET_SERVER_WIFISERVER diff --git a/code/espurna/terminal.cpp b/code/espurna/terminal.cpp index 459d3fcd7f..74527c3082 100644 --- a/code/espurna/terminal.cpp +++ b/code/espurna/terminal.cpp @@ -12,6 +12,7 @@ Copyright (C) 2020 by Maxim Prokhorov #if TERMINAL_SUPPORT #include "api.h" +#include "crash.h" #include "settings.h" #include "system.h" #include "telnet.h" @@ -269,6 +270,107 @@ void start(String&& hostname, Callback&& callback) { } // namespace dns +extern "C" uint32_t _FS_start; +extern "C" uint32_t _FS_end; + +struct Layout { + Layout() = delete; + + constexpr Layout(const Layout&) = default; + constexpr Layout(Layout&&) = default; + constexpr Layout(const char* const name, uint32_t start, uint32_t end) : + _name(name), + _start(start), + _end(end) + {} + + constexpr uint32_t size() const { + return _end - _start; + } + + constexpr uint32_t start() const { + return _start; + } + + constexpr uint32_t end() const { + return _end; + } + + constexpr const char* name() const { + return _name; + } + +private: + const char* const _name; + uint32_t _start; + uint32_t _end; +}; + +struct Layouts { + using List = std::forward_list; + + Layouts() = delete; + explicit Layouts(uint32_t size) : + _size(size), + _current(size), + _sectors(size / SPI_FLASH_SEC_SIZE) + {} + + const Layout* head() const { + if (_list.empty()) { + return nullptr; + } + + return &_list.front(); + } + + bool lock() { + if (_lock) { + return true; + } + + _lock = true; + return false; + } + + uint32_t sectors() const { + return _sectors; + } + + uint32_t size() const { + return _size - _current; + } + + uint32_t current() const { + return _current; + } + + Layouts& add(const char* const name, uint32_t size) { + if (!_lock && _current >= size) { + Layout layout(name, _current - size, _current); + _current -= layout.size(); + _list.push_front(layout); + } + + return *this; + } + + template + void foreach(T&& callback) { + for (auto& layout : _list) { + callback(layout); + } + } + +private: + bool _lock { false }; + List _list; + uint32_t _size; + uint32_t _current; + uint32_t _sectors; +}; + + void _terminalInitCommands() { terminalRegisterCommand(F("COMMANDS"), _terminalHelpCommand); @@ -345,9 +447,62 @@ void _terminalInitCommands() { terminalOK(ctx); }); - terminalRegisterCommand(F("INFO"), [](const terminal::CommandContext&) { - info(); - terminalOK(); + terminalRegisterCommand(F("INFO"), [](const terminal::CommandContext& ctx) { + if (!systemCheck()) { + ctx.output.print(F("\n\n!!! device is in safe mode !!!\n\n")); + } + + ctx.output.printf_P(PSTR(APP_NAME " %s built %s\n"), getVersion(), buildTime().c_str()); + ctx.output.printf_P(PSTR("mcu: esp8266 chipid: %s\n"), getFullChipId().c_str()); + ctx.output.printf_P(PSTR("sdk: %s core: %s\n"), + ESP.getSdkVersion(), getCoreVersion().c_str()); + ctx.output.printf_P(PSTR("md5: %s\n"), ESP.getSketchMD5().c_str()); + ctx.output.printf_P(PSTR("support: %s\n"), getEspurnaModules()); +#if SENSOR_SUPPORT + ctx.output.printf_P(PSTR("sensors: %s\n"), getEspurnaSensors()); +#endif + +#if DEBUG_SUPPORT + crashResetReason(ctx.output); +#endif + terminalOK(ctx); + }); + + terminalRegisterCommand(F("STORAGE"), [](const terminal::CommandContext& ctx) { + ctx.output.printf_P(PSTR("flash chip ID: 0x%06X\n"), ESP.getFlashChipId()); + ctx.output.printf_P(PSTR("speed: %u\n"), ESP.getFlashChipSpeed()); + ctx.output.printf_P(PSTR("mode: %s\n"), getFlashChipMode()); + + ctx.output.printf_P(PSTR("size: %u (SPI), %u (SDK)\n"), + ESP.getFlashChipRealSize(), ESP.getFlashChipSize()); + + Layouts layout(ESP.getFlashChipRealSize()); + + // SDK specifies a hard-coded layout, there's no data beyond + // (...addressable by the Core, since it adheres the setting) + if (ESP.getFlashChipRealSize() > ESP.getFlashChipSize()) { + layout.add("unused", ESP.getFlashChipRealSize() - ESP.getFlashChipSize()); + } + + // app is at a normal location, [0...size), but... since it is offset by the free space, make sure it is aligned + // to the sector size (...and it is expected from the getFreeSketchSpace, as the app will align to use the fixed + // sector address for OTA writes). + + layout.add("sdk", 4 * SPI_FLASH_SEC_SIZE); + layout.add("eeprom", eepromSpace()); + + auto app_size = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); + auto ota_size = layout.current() - app_size; + + // OTA is allowed to use all but one eeprom sectors that, leaving the last one + // for the settings snapshot during the update + + layout.add("ota", ota_size); + layout.add("app", app_size); + + layout.foreach([&](const Layout& l) { + ctx.output.printf_P("%-6s [%08X...%08X) (%u bytes)\n", l.name(), l.start(), l.end(), l.size()); + }); }); terminalRegisterCommand(F("RESET"), [](const terminal::CommandContext& ctx) { @@ -371,7 +526,7 @@ void _terminalInitCommands() { #if SECURE_CLIENT == SECURE_CLIENT_BEARSSL terminalRegisterCommand(F("MFLN.PROBE"), [](const terminal::CommandContext& ctx) { if (ctx.argc != 3) { - terminalError(F("[url] [value]")); + terminalError(ctx, F(" ")); return; } @@ -382,16 +537,17 @@ void _terminalInitCommands() { client->setInsecure(); if (client->probeMaxFragmentLength(_url.host.c_str(), _url.port, requested_mfln)) { - terminalOK(); - } else { - terminalError(F("Buffer size not supported")); + terminalOK(ctx); + return; } + + terminalError(ctx, F("Buffer size not supported")); }); #endif terminalRegisterCommand(F("HOST"), [](const terminal::CommandContext& ctx) { if (ctx.argc != 2) { - terminalError(ctx, F("HOST ")); + terminalError(ctx, F("")); return; } @@ -430,11 +586,11 @@ void _terminalInitCommands() { void _terminalLoop() { - #if DEBUG_SERIAL_SUPPORT - while (DEBUG_PORT.available()) { - _io.inject(DEBUG_PORT.read()); - } - #endif +#if DEBUG_SERIAL_SUPPORT + while (DEBUG_PORT.available()) { + _io.inject(DEBUG_PORT.read()); + } +#endif _terminal.process([](terminal::Terminal::Result result) { bool out = false; @@ -623,12 +779,12 @@ void terminalWebApiSetup() { #endif // TERMINAL_WEB_API_SUPPORT -Stream & terminalDefaultStream() { +Stream& terminalDefaultStream() { return (Stream &) _io; } size_t terminalCapacity() { - return _io.capacity(); + return Io::capacity(); } void terminalInject(void *data, size_t len) { @@ -644,7 +800,7 @@ void terminalRegisterCommand(const __FlashStringHelper* name, terminal::Terminal }; void terminalOK(Print& print) { - print.printf_P(PSTR("+%s\n"), "OK"); + print.print(F("OK\n")); } void terminalError(Print& print, const String& error) { diff --git a/code/espurna/utils.cpp b/code/espurna/utils.cpp index 5ea0346a43..58b0783aa5 100644 --- a/code/espurna/utils.cpp +++ b/code/espurna/utils.cpp @@ -31,16 +31,6 @@ void setDefaultHostname() { } } -const String& getDevice() { - static const String value(F(DEVICE)); - return value; -} - -const String& getManufacturer() { - static const String value(F(MANUFACTURER)); - return value; -} - String getBoardName() { return getSetting("boardName", F(DEVICE_NAME)); } @@ -88,16 +78,26 @@ const String& getCoreRevision() { return revision; } -const String& getVersion() { - static const String value { +const char* getVersion() { + static const char version[] PROGMEM { #if defined(APP_REVISION) - F(APP_VERSION APP_REVISION) + APP_VERSION APP_REVISION #else - F(APP_VERSION) + APP_VERSION #endif }; - return value; + return version; +} + +const char* getDevice() { + static const char device[] PROGMEM = DEVICE; + return device; +} + +const char* getManufacturer() { + static const char manufacturer[] PROGMEM = MANUFACTURER; + return manufacturer; } String buildTime() { @@ -141,219 +141,6 @@ String getUptime() { #endif // NTP_SUPPORT -// ----------------------------------------------------------------------------- -// INFO -// ----------------------------------------------------------------------------- - -extern "C" uint32_t _SPIFFS_start; -extern "C" uint32_t _SPIFFS_end; - -unsigned int info_bytes2sectors(size_t size) { - return (int) (size + SPI_FLASH_SEC_SIZE - 1) / SPI_FLASH_SEC_SIZE; -} - -unsigned long info_ota_space() { - return (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; -} - -unsigned long info_filesystem_space() { - return ((uint32_t)&_SPIFFS_end - (uint32_t)&_SPIFFS_start); -} - -void _info_print_memory_layout_line(const char * name, unsigned long bytes, bool reset) { - static unsigned long index = 0; - if (reset) index = 0; - if (0 == bytes) return; - unsigned int _sectors = info_bytes2sectors(bytes); - DEBUG_MSG_P(PSTR("[MAIN] %-20s: %8lu bytes / %4d sectors (%4d to %4d)\n"), name, bytes, _sectors, index, index + _sectors - 1); - index += _sectors; -} - -void _info_print_memory_layout_line(const char * name, unsigned long bytes) { - _info_print_memory_layout_line(name, bytes, false); -} - -void infoMemory(const char * name, unsigned int total_memory, unsigned int free_memory) { - - DEBUG_MSG_P( - PSTR("[MAIN] %-6s: %5u bytes initially | %5u bytes used (%2u%%) | %5u bytes free (%2u%%)\n"), - name, - total_memory, - total_memory - free_memory, - 100 * (total_memory - free_memory) / total_memory, - free_memory, - 100 * free_memory / total_memory - ); - -} - -void infoMemory(const char* name, const HeapStats& stats) { - infoMemory(name, systemInitialFreeHeap(), stats.available); -} - -void infoHeapStats(const char* name, const HeapStats& stats) { - DEBUG_MSG_P( - PSTR("[MAIN] %-6s: %5u contiguous bytes available (%u%% fragmentation)\n"), - name, - stats.usable, - stats.frag_pct - ); -} - -void infoHeapStats(bool show_frag_stats) { - auto stats = systemHeapStats(); - infoMemory("Heap", stats); - if (show_frag_stats) { - infoHeapStats("Heap", stats); - } -} - -const char* _info_wifi_sleep_mode(WiFiSleepType_t type) { - switch (type) { - case WIFI_NONE_SLEEP: - return "NONE"; - case WIFI_LIGHT_SLEEP: - return "LIGHT"; - case WIFI_MODEM_SLEEP: - return "MODEM"; - default: - break; - } - - return "UNKNOWN"; -} - -void info(bool first) { -#if DEBUG_SUPPORT -#if DEBUG_LOG_BUFFER_SUPPORT - if (first && debugLogBuffer()) return; -#endif - - DEBUG_MSG_P(PSTR("\n\n---8<-------\n\n")); - - // ------------------------------------------------------------------------- - - DEBUG_MSG_P(PSTR("[MAIN] " APP_NAME " %s\n"), getVersion().c_str()); - DEBUG_MSG_P(PSTR("[MAIN] " APP_AUTHOR "\n")); - DEBUG_MSG_P(PSTR("[MAIN] " APP_WEBSITE "\n\n")); - DEBUG_MSG_P(PSTR("[MAIN] CPU chip ID: 0x%06X\n"), ESP.getChipId()); - DEBUG_MSG_P(PSTR("[MAIN] CPU frequency: %u MHz\n"), ESP.getCpuFreqMHz()); - DEBUG_MSG_P(PSTR("[MAIN] SDK version: %s\n"), ESP.getSdkVersion()); - DEBUG_MSG_P(PSTR("[MAIN] Core version: %s\n"), getCoreVersion().c_str()); - DEBUG_MSG_P(PSTR("[MAIN] Core revision: %s\n"), getCoreRevision().c_str()); - DEBUG_MSG_P(PSTR("[MAIN] Built: %s\n"), buildTime().c_str()); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - FlashMode_t mode [[gnu::unused]] = ESP.getFlashChipMode(); - - DEBUG_MSG_P(PSTR("[MAIN] Flash chip ID: 0x%06X\n"), ESP.getFlashChipId()); - DEBUG_MSG_P(PSTR("[MAIN] Flash speed: %u Hz\n"), ESP.getFlashChipSpeed()); - DEBUG_MSG_P(PSTR("[MAIN] Flash mode: %s\n"), mode == FM_QIO ? "QIO" : mode == FM_QOUT ? "QOUT" : mode == FM_DIO ? "DIO" : mode == FM_DOUT ? "DOUT" : "UNKNOWN"); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - _info_print_memory_layout_line("Flash size (CHIP)", ESP.getFlashChipRealSize(), true); - _info_print_memory_layout_line("Flash size (SDK)", ESP.getFlashChipSize(), true); - _info_print_memory_layout_line("Reserved", 1 * SPI_FLASH_SEC_SIZE, true); - _info_print_memory_layout_line("Firmware size", ESP.getSketchSize()); - _info_print_memory_layout_line("Max OTA size", info_ota_space()); - _info_print_memory_layout_line("SPIFFS size", info_filesystem_space()); - _info_print_memory_layout_line("EEPROM size", eepromSpace()); - _info_print_memory_layout_line("Reserved", 4 * SPI_FLASH_SEC_SIZE); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - #if SPIFFS_SUPPORT - FSInfo fs_info; - bool fs = SPIFFS.info(fs_info); - if (fs) { - DEBUG_MSG_P(PSTR("[MAIN] SPIFFS total size : %8u bytes / %4d sectors\n"), fs_info.totalBytes, info_bytes2sectors(fs_info.totalBytes)); - DEBUG_MSG_P(PSTR("[MAIN] used size : %8u bytes\n"), fs_info.usedBytes); - DEBUG_MSG_P(PSTR("[MAIN] block size : %8u bytes\n"), fs_info.blockSize); - DEBUG_MSG_P(PSTR("[MAIN] page size : %8u bytes\n"), fs_info.pageSize); - DEBUG_MSG_P(PSTR("[MAIN] max files : %8u\n"), fs_info.maxOpenFiles); - DEBUG_MSG_P(PSTR("[MAIN] max length : %8u\n"), fs_info.maxPathLength); - } else { - DEBUG_MSG_P(PSTR("[MAIN] No SPIFFS partition\n")); - } - DEBUG_MSG_P(PSTR("\n")); - #endif - - // ------------------------------------------------------------------------- - - eepromSectorsDebug(); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - infoMemory("EEPROM", SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE - settingsSize()); - infoHeapStats(!first); - infoMemory("Stack", CONT_STACKSIZE, systemFreeStack()); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - DEBUG_MSG_P(PSTR("[MAIN] Boot version: %d\n"), ESP.getBootVersion()); - DEBUG_MSG_P(PSTR("[MAIN] Boot mode: %d\n"), ESP.getBootMode()); - - auto reason = customResetReason(); - if (CustomResetReason::None != reason) { - DEBUG_MSG_P(PSTR("[MAIN] Last reset reason: %s\n"), customResetReasonToPayload(reason).c_str()); - } else { - DEBUG_MSG_P(PSTR("[MAIN] Last reset reason: %s\n"), ESP.getResetReason().c_str()); - DEBUG_MSG_P(PSTR("[MAIN] Last reset info: %s\n"), ESP.getResetInfo().c_str()); - } - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - DEBUG_MSG_P(PSTR("[MAIN] Board: %s\n"), getBoardName().c_str()); - DEBUG_MSG_P(PSTR("[MAIN] Support: %s\n"), getEspurnaModules().c_str()); - DEBUG_MSG_P(PSTR("[MAIN] OTA: %s\n"), getEspurnaOTAModules().c_str()); -#if SENSOR_SUPPORT - DEBUG_MSG_P(PSTR("[MAIN] Sensors: %s\n"), getEspurnaSensors().c_str()); -#endif - DEBUG_MSG_P(PSTR("[MAIN] WebUI image: %s\n"), getEspurnaWebUI().c_str()); - DEBUG_MSG_P(PSTR("\n")); - - // ------------------------------------------------------------------------- - - if (!first) { - DEBUG_MSG_P(PSTR("[MAIN] Firmware MD5: %s\n"), (char *) ESP.getSketchMD5().c_str()); - } - - if (ADC_MODE_VALUE == ADC_VCC) { - DEBUG_MSG_P(PSTR("[MAIN] Power: %u mV\n"), ESP.getVcc()); - } - if (espurnaLoopDelay()) { - DEBUG_MSG_P(PSTR("[MAIN] Power saving delay value: %lu ms\n"), espurnaLoopDelay()); - } - - const WiFiSleepType_t sleep_mode = WiFi.getSleepMode(); - if (sleep_mode != WIFI_NONE_SLEEP) { - DEBUG_MSG_P(PSTR("[MAIN] WiFi Sleep Mode: %s\n"), _info_wifi_sleep_mode(sleep_mode)); - } - - // ------------------------------------------------------------------------- - -#if SYSTEM_CHECK_ENABLED - if (!systemCheck()) { - DEBUG_MSG_P(PSTR("\n")); - DEBUG_MSG_P(PSTR("[MAIN] Device is in SAFE MODE\n")); - } -#endif - - // ------------------------------------------------------------------------- - - DEBUG_MSG_P(PSTR("\n\n---8<-------\n\n")); - -#endif // DEBUG_SUPPORT == 1 -} - // ----------------------------------------------------------------------------- // SSL // ----------------------------------------------------------------------------- @@ -529,3 +316,29 @@ size_t hexDecode(const char* in, size_t in_size, uint8_t* out, size_t out_size) return out_index; } + +const char* getFlashChipMode() { + const char* mode { nullptr }; + if (!mode) { + switch (ESP.getFlashChipMode()) { + case FM_QIO: + mode = "QIO"; + break; + case FM_QOUT: + mode = "QOUT"; + break; + case FM_DIO: + mode = "DIO"; + break; + case FM_DOUT: + mode = "DOUT"; + break; + case FM_UNKNOWN: + default: + mode = "UNKNOWN"; + break; + } + } + + return mode; +} diff --git a/code/espurna/utils.h b/code/espurna/utils.h index 5abc591222..346c029529 100644 --- a/code/espurna/utils.h +++ b/code/espurna/utils.h @@ -12,19 +12,19 @@ Copyright (C) 2017-2019 by Xose PĂ©rez #include "system.h" -#define INLINE inline __attribute__((always_inline)) - extern "C" uint32_t _SPIFFS_start; extern "C" uint32_t _SPIFFS_end; void setDefaultHostname(); void setBoardName(); -const String& getDevice(); -const String& getManufacturer(); const String& getCoreVersion(); const String& getCoreRevision(); -const String& getVersion(); + +const char* getFlashChipMode(); +const char* getVersion(); +const char* getDevice(); +const char* getManufacturer(); String getAdminPass(); String getBoardName(); @@ -36,7 +36,6 @@ String getUptime(); void infoHeapStats(const char* name, const HeapStats& stats); void infoHeapStats(bool show_frag_stats = false); void infoMemory(const char* name, unsigned int total_memory, unsigned int free_memory); -void info(bool first = false); bool sslCheckFingerPrint(const char * fingerprint); bool sslFingerPrintArray(const char * fingerprint, unsigned char * bytearray); diff --git a/code/espurna/web.cpp b/code/espurna/web.cpp index aaccf064be..b8169f6130 100644 --- a/code/espurna/web.cpp +++ b/code/espurna/web.cpp @@ -239,8 +239,8 @@ void _onDiscover(AsyncWebServerRequest *request) { StaticJsonBuffer jsonBuffer; JsonObject &root = jsonBuffer.createObject(); root["app"] = APP_NAME; - root["version"] = getVersion().c_str(); - root["device"] = device.c_str(); + root["version"] = getVersion(); + root["device"] = device; root["hostname"] = hostname.c_str(); AsyncResponseStream *response = request->beginResponseStream("application/json", root.measureLength() + 1); @@ -267,7 +267,7 @@ void _onGetConfig(AsyncWebServerRequest *request) { response->addHeader("X-Frame-Options", "deny"); response->printf("{\n\"app\": \"" APP_NAME "\""); - response->printf(",\n\"version\": \"%s\"", getVersion().c_str()); + response->printf(",\n\"version\": \"%s\"", getVersion()); response->printf(",\n\"backup\": \"1\""); #if NTP_SUPPORT response->printf(",\n\"timestamp\": \"%s\"", ntpDateTime().c_str()); diff --git a/code/espurna/wifi.cpp b/code/espurna/wifi.cpp index fd85a359ae..253c9a852d 100644 --- a/code/espurna/wifi.cpp +++ b/code/espurna/wifi.cpp @@ -1618,7 +1618,7 @@ void init() { disable(); } -uint8_t stations() { +size_t stations() { return WiFi.softAPgetStationNum(); } @@ -2455,6 +2455,14 @@ void wifiApCheck() { wifi::action(wifi::Action::AccessPointFallbackCheck); } +size_t wifiApStations() { + if (wifi::ap::enabled()) { + return wifi::ap::stations(); + } + + return 0; +} + void wifiSetup() { wifi::internal::init(); wifi::settings::migrate(migrateVersion()); diff --git a/code/espurna/wifi.h b/code/espurna/wifi.h index 754effffaf..4bb6c52bf2 100644 --- a/code/espurna/wifi.h +++ b/code/espurna/wifi.h @@ -79,6 +79,7 @@ bool wifiConnected(); // Whether the AP is up and running bool wifiConnectable(); +size_t wifiApStations(); // Current STA connection String wifiStaSsid(); diff --git a/code/espurna/ws.cpp b/code/espurna/ws.cpp index c7959d7591..c5cda020ec 100644 --- a/code/espurna/ws.cpp +++ b/code/espurna/ws.cpp @@ -256,7 +256,7 @@ void WsDebug::send(bool connected) { } bool wsDebugSend(const char* prefix, const char* message) { - if (wifiConnected() && wsConnected()) { + if ((wifiConnected() || wifiApStations()) && wsConnected()) { _ws_debug.add(prefix, message); return true; } @@ -487,15 +487,15 @@ void _wsOnConnected(JsonObject& root) { root["webMode"] = WEB_MODE_NORMAL; root["app_name"] = APP_NAME; - root["app_version"] = getVersion().c_str(); + root["app_version"] = getVersion(); root["app_build"] = buildTime(); - root["device"] = getDevice().c_str(); - root["manufacturer"] = getManufacturer().c_str(); + root["device"] = getDevice(); + root["manufacturer"] = getManufacturer(); root["chipid"] = getChipId().c_str(); - root["mac"] = WiFi.macAddress(); + root["mac"] = getFullChipId().c_str(); root["bssid"] = WiFi.BSSIDstr(); root["channel"] = WiFi.channel(); - root["hostname"] = getSetting("hostname"); + root["hostname"] = getSetting("hostname", getIdentifier()); root["desc"] = getSetting("desc"); root["network"] = wifiStaSsid(); root["deviceip"] = wifiStaIp().toString();