From 23993a09cf88d93f9c8528a5e24905d1f3b04344 Mon Sep 17 00:00:00 2001 From: Torrie Fischer Date: Wed, 20 Dec 2023 10:47:26 +0100 Subject: [PATCH] build: clean up the mess of ifdefs from platform into a scons-configured hal --- build-hal.py | 9 ++ lib/Figments/MainLoop.cpp | 4 +- platformio.ini | 131 ++--------------- src/BootOptions.cpp | 54 +------ src/BootOptions.h | 2 +- src/FsUtils.cpp | 8 +- src/FsUtils.h | 4 +- src/Hal.h | 30 ++++ src/Platform.cpp | 120 +++------------- src/Platform.h | 1 + src/inputs/ConfigInput.cpp | 5 - src/inputs/ConfigInput.h | 77 ---------- src/platform/arduino/MQTTTelemetry.cpp | 76 +++++----- src/platform/arduino/MQTTTelemetry.h | 4 +- src/platform/arduino/WiFiTask.cpp | 4 +- .../{ => esp32}/BluetoothSerialTelemetry.cpp | 0 .../{ => esp32}/BluetoothSerialTelemetry.h | 0 src/platform/arduino/esp32/Platform.cpp | 106 ++++++++++++++ .../arduino/{ => esp32}/U8Display.cpp | 0 src/platform/arduino/esp8266/Platform.cpp | 134 ++++++++++++++++++ verify-configs.py | 17 +++ 21 files changed, 376 insertions(+), 410 deletions(-) create mode 100644 build-hal.py create mode 100644 src/Hal.h delete mode 100644 src/inputs/ConfigInput.cpp delete mode 100644 src/inputs/ConfigInput.h rename src/platform/arduino/{ => esp32}/BluetoothSerialTelemetry.cpp (100%) rename src/platform/arduino/{ => esp32}/BluetoothSerialTelemetry.h (100%) create mode 100644 src/platform/arduino/esp32/Platform.cpp rename src/platform/arduino/{ => esp32}/U8Display.cpp (100%) create mode 100644 src/platform/arduino/esp8266/Platform.cpp diff --git a/build-hal.py b/build-hal.py new file mode 100644 index 0000000..d3641ae --- /dev/null +++ b/build-hal.py @@ -0,0 +1,9 @@ +Import("env") +board = env.get("BOARD_MCU") +frameworks = env.get("PIOFRAMEWORK") + +print(f"HAL configuration:") +for framework in frameworks: + env.Append(SRC_FILTER=[f"+"]) + env.Append(SRC_FILTER=[f"+"]) + print(f"- platform/{framework}{board}") diff --git a/lib/Figments/MainLoop.cpp b/lib/Figments/MainLoop.cpp index b0a2450..6277e4f 100644 --- a/lib/Figments/MainLoop.cpp +++ b/lib/Figments/MainLoop.cpp @@ -71,7 +71,7 @@ MainLoop::loop() Task* slowestTask = NULL; for(Task* task : scheduler) { //unsigned int start = millis(); -#if defined(BOARD_ESP32) or defined(BOARD_ESP8266) +#if defined(ESP32) or defined(ESP8266) unsigned int start = ESP.getCycleCount(); #else unsigned int start = millis(); @@ -79,7 +79,7 @@ MainLoop::loop() Log.verbose("Running %s", task->name); s_lastTaskName = task->name; task->loop(); -#if defined(BOARD_ESP32) or defined(BOARD_ESP8266) +#if defined(ESP32) or defined(ESP8266) unsigned int runtime = (ESP.getCycleCount() - start) / 160000; #else unsigned int runtime = millis() - start; diff --git a/platformio.ini b/platformio.ini index 46c31c7..45d5ac4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,20 +8,24 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html +[env] +extra_scripts = pre:verify-configs.py, pre:build-hal.py + [common_env_data] -src_filter = "+<*> -<.git/> -<.svn/> - - + + +" +src_filter = +<*>, -<.git/>, -<.svn/>, - lib_ldf_mode = chain+ -extra_scripts = verify-configs.py src_build_flags = -DRENDERBUG_VERSION=3 -DRENDERBUG_LED_PIN=14 -DRENDERBUG_LED_PACKING=RGB -DDEFAULT_PATTERN_INDEX=0 + -fstack-protector -Wall lib_deps_external = fastled/FastLED@^3.5.0 thijse/ArduinoLog@^1.1.0 bblanchon/ArduinoJson@^6.17.3 + JsonStreamingParser LittleFS [config_u8display] @@ -31,32 +35,10 @@ lib_deps = olikraus/U8g2@^2.34.15 src_filter = "+" -[config_mqtt] -src_build_flags = - -DCONFIG_MQTT -lib_deps = - knolleary/PubSubClient@^2.8.0 -src_filter = "+" - -[config_wifi] -src_build_flags = - -DCONFIG_WIFI -src_filter = "+" - -[config_bluetooth] -src_build_flags = - -DCONFIG_BLUETOOTH -src_filter = "+" -lib_deps = - BluetoothSerial - [config_ota] src_build_flags = - -DCONFIG_OTA src_filter = "+" lib_deps = - ArduinoOTA - ESP8266mDNS [config_nocolor] src_build_flags = @@ -72,28 +54,8 @@ src_build_flags = -DCONFIG_MPU5060 src_filter = "+" -[env:bike] -extends = env:esp32, config_u8display -src_filter = "${env:esp32.src_filter} ${config_u8display.src_filter}" -lib_deps = - ${env:esp32.lib_deps} - ${config_u8display.lib_deps} -src_build_flags = - ${env:esp32.src_build_flags} - ${config_u8display.src_build_flags} -build_type = debug - -[env:bike_ble] -extends = env:bike -lib_deps = - ${env:bike.lib_deps} - nkolban/ESP32 BLE Arduino@1.0.1 -src_build_flags = - ${env:bike.src_build_flags} - [env:esp32] extends = config_nocolor -extra_scripts = verify-configs.py board_build.filesystem = littlefs platform = espressif32 board = featheresp32 @@ -103,11 +65,13 @@ check_flags = src_build_flags = ${common_env_data.src_build_flags} ${config_nocolor.src_build_flags} - -DPLATFORM_ARDUINO -DBOARD_ESP32 -DCONFIG_THREADED_INPUTS + -DRENDERBUG_LED_PIN=14 lib_deps = ${common_env_data.lib_deps_external} + BluetoothSerial + knolleary/PubSubClient@^2.8.0 src_filter = "${common_env_data.src_filter}" monitor_filters = esp32_exception_decoder monitor_speed = 115200 @@ -131,43 +95,19 @@ platform = espressif8266 board = huzzah framework = arduino board_build.filesystem = littlefs +monitor_filters = esp8266_exception_decoder src_build_flags = ${common_env_data.src_build_flags} - -DPLATFORM_ARDUINO - -DBOARD_ESP8266 -DCORE_DEBUG_LEVEL=5 - -fstack-protector lib_deps = ${common_env_data.lib_deps_external} + knolleary/PubSubClient@^2.8.0 arduino-libraries/NTPClient@^3.1.0 + ESP8266WiFi + ESP8266mDNS + ArduinoOTA src_filter = "${common_env_data.src_filter}" -[env:esp32_bluetooth] -extends = env:esp32, config_bluetooth -src_filter = "${env:esp32.src_filter} ${config_mqtt.src_filter} ${config_wifi.src_filter} ${config_bluetooth.src_filter}" -lib_deps = - ${env:esp32.lib_deps} - ${config_bluetooth.lib_deps} - ${config_mqtt.lib_deps} -src_build_flags = - ${env:esp32.src_build_flags} - ${config_bluetooth.src_build_flags} - ${config_wifi.src_build_flags} - -DRENDERBUG_LED_PIN=14 - -[env:esp32_wifi] -extends = env:esp32, config_wifi, config_mqtt -src_filter = "${env:esp32.src_filter} ${config_wifi.src_filter} ${config_mqtt.src_filter}" -buid_type = debug -lib_deps = - ${env:esp32.lib_deps} - ${config_mqtt.lib_deps} -src_build_flags = - ${env:esp32.src_build_flags} - ${config_mqtt.src_build_flags} - ${config_wifi.src_build_flags} - -DRENDERBUG_LED_PIN=14 - [env:esp32_display] extends = env:esp32, config_u8display src_filter = "${env:esp32.src_filter} ${config_u8display.src_filter}" @@ -179,46 +119,3 @@ src_build_flags = ${env:esp32.src_build_flags} ${config_u8display.src_build_flags} -DRENDERBUG_LED_PIN=14 - -[env:esp32_wifi_display] -extends = env:esp32, config_wifi, config_mqtt, config_u8display -src_filter = "${env:esp32.src_filter} ${config_wifi.src_filter} ${config_mqtt.src_filter} ${config_u8display.src_filter}" -build_type = debug -lib_deps = - ${env:esp32.lib_deps} - ${config_mqtt.lib_deps} - ${config_u8display.lib_deps} -src_build_flags = - ${env:esp32.src_build_flags} - ${config_mqtt.src_build_flags} - ${config_wifi.src_build_flags} - ${config_u8display.src_build_flags} - -DRENDERBUG_LED_PIN=14 - -[env:prototype] -extends = env:esp32, config_buttons, config_mpu5060 -src_filter = "${env:esp32.src_filter} ${config_buttons.src_filter} ${config_mpu5060.src_filter}" - -[env:esp8266_wifi] -extends = env:esp8266, config_wifi, config_mqtt, config_ota -src_filter = "${env:esp32.src_filter} ${config_ota.src_filter} ${config_wifi.src_filter} ${config_mqtt.src_filter}" -src_build_flags = - ${env:esp8266.src_build_flags} - ${config_mqtt.src_build_flags} - ${config_wifi.src_build_flags} - ${config_ota.src_build_flags} -lib_deps = - ${env:esp8266.lib_deps} - ${config_mqtt.lib_deps} - ESP8266WiFi - ${config_ota.lib_deps} - -#[env:home_lighting_grb] -#extends = env:esp8266_wifi config_u8display -#src_build_flags = -# ${env:home_lighting.src_build_flags} -# -DRENDERBUG_LED_PACKING=GRB - -#[env:home_lighting-12f] -#extends = env:esp8266_wifi config_u8display -#board = esp12e diff --git a/src/BootOptions.cpp b/src/BootOptions.cpp index e7d5b7b..a9cdaee 100644 --- a/src/BootOptions.cpp +++ b/src/BootOptions.cpp @@ -3,10 +3,6 @@ #include -#ifdef BOARD_ESP8266 -#include -#endif - #ifdef PLATFORM_PHOTON LEDStatus serialStatus = LEDStatus(RGB_COLOR_ORANGE, LED_PATTERN_FADE, LED_SPEED_FAST, LED_PRIORITY_BACKGROUND); LEDStatus configStatus = LEDStatus(RGB_COLOR_YELLOW, LED_PATTERN_FADE, LED_SPEED_NORMAL, LED_PRIORITY_IMPORTANT); @@ -14,21 +10,6 @@ retained bool LAST_BOOT_WAS_FLASH; retained bool LAST_BOOT_WAS_SERIAL; #endif -#ifndef __NOINIT_ATTR // Pre-defined on esp32 -#define __NOINIT_ATTR __attribute__ ((section (".noinit"))) -#endif - -#define SAFE_MODE_MAGIC 6942 - -__NOINIT_ATTR uint8_t s_rebootCount; -__NOINIT_ATTR uint16_t s_forceSafeMode; - -void -BootOptions::forceSafeMode() -{ - s_forceSafeMode = SAFE_MODE_MAGIC; -} - void BootOptions::initPins() { @@ -53,40 +34,7 @@ BootOptions::BootOptions() configStatus.setActive(isSetup); serialStatus.setActive(isSerial); #endif -#ifdef BOARD_ESP32 - resetReason = esp_reset_reason(); - crashCount = s_rebootCount; - if (resetReason >= 4) { // TODO: These values are defined in - // esp32/rom/rtc.h, but not sure if that's included - // on platformio builds - if (crashCount++ >= 3) { - // Boot into safe mode if the watchdog reset us three times in a row. - isSafeMode = true; - } - } else { - crashCount = 0; - } - s_rebootCount = crashCount; -#endif -#ifdef BOARD_ESP8266 - struct rst_info resetInfo = *ESP.getResetInfoPtr(); - resetReason = resetInfo.reason; - crashCount = s_rebootCount; - if (resetInfo.reason == REASON_SOFT_WDT_RST || resetInfo.reason == REASON_WDT_RST || resetInfo.reason == REASON_EXCEPTION_RST) { - if (crashCount++ >= 3) { - // Boot into safe mode if the watchdog reset us three times in a row. - isSafeMode = true; - } - } else { - crashCount = 0; - } - s_rebootCount = crashCount; - - if (resetInfo.reason > 0 && s_forceSafeMode == SAFE_MODE_MAGIC) { - isSafeMode = true; - s_forceSafeMode = 0; - } -#endif + PlatformImpl<>::initBootOptions(*this); } void diff --git a/src/BootOptions.h b/src/BootOptions.h index a103b94..3318c2a 100644 --- a/src/BootOptions.h +++ b/src/BootOptions.h @@ -1,5 +1,6 @@ #pragma once #include +#include "Hal.h" struct BootOptions { static void initPins(); @@ -7,7 +8,6 @@ struct BootOptions { BootOptions(); void waitForRelease(); - void forceSafeMode(); bool isSetup = false; bool isSerial = false; diff --git a/src/FsUtils.cpp b/src/FsUtils.cpp index 4b94941..b09a740 100644 --- a/src/FsUtils.cpp +++ b/src/FsUtils.cpp @@ -6,10 +6,10 @@ filename_iterator::filename_iterator() {} filename_iterator::filename_iterator(const char* path, const char* suffix) -#ifdef BOARD_ESP8266 +#ifdef ESP8266 : dir(LittleFS.openDir(path)), #endif -#ifdef BOARD_ESP32 +#ifdef ESP32 : dir(LittleFS.open(path)), #endif valid(true), @@ -26,7 +26,7 @@ filename_iterator::next() } int extPos = -1; do { -#ifdef BOARD_ESP8266 +#ifdef ESP8266 valid = dir.next(); if (valid) { String fname = dir.fileName(); @@ -36,7 +36,7 @@ filename_iterator::next() } } #endif -#ifdef BOARD_ESP32 +#ifdef ESP32 File next = dir.openNextFile(); valid = (bool)next; if (valid && !next.isDirectory()) { diff --git a/src/FsUtils.h b/src/FsUtils.h index c01a917..a6379c4 100644 --- a/src/FsUtils.h +++ b/src/FsUtils.h @@ -24,10 +24,10 @@ struct filename_iterator: public std::iterator +class PlatformImpl { + public: + static const char* name(); + static const char* version(); + static int freeRam(); + static void startWatchdog(); + static void startNTP(); + static bool getLocalTime(struct tm* timedata, int timezone); + static void loop(); + static const char* deviceID(); + __attribute__((noreturn)) static void restart(); + static void bootSplash(); + static void printCrashInfo(); + + static void initBootOptions(BootOptions& opts); + static void forceSafeMode(); +}; diff --git a/src/Platform.cpp b/src/Platform.cpp index 6e0dffd..50bdce0 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -3,40 +3,16 @@ #include "Static.h" #include -#ifdef BOARD_ESP32 -#ifdef CONFIG_WIFI -#include -#endif -#include -#elif defined(BOARD_ESP8266) -#ifdef CONFIG_WIFI -#include -#include -#include -#include - -WiFiUDP wifiUdp; -NTPClient timeClient(wifiUdp, "pool.ntp.org", 3600 * -7); -#endif -#endif - #ifdef PLATFORM_PHOTON STARTUP(BootOptions::initPins()); #else #include "inputs/Serial.h" -#ifdef CONFIG_MQTT #include "platform/arduino/MQTTTelemetry.h" -#endif void printNewline(Print* logOutput, int logLevel) { (void)logLevel; // unused logOutput->print("\n"); } -int printEspLog(const char* fmt, va_list args) -{ - Log.notice(fmt, args); - return 1; -} #endif int Platform::s_timezone = 0; @@ -46,24 +22,18 @@ Platform::TaskRegistration* Platform::lastTask = NULL; const char* Platform::name() { + return PlatformImpl<>::name(); #ifdef PLATFORM_PHOTON return "Photon"; -#elif defined(BOARD_ESP8266) - return "ESP8266"; -#elif defined(BOARD_ESP32) - return "ESP32"; -#else - return "Unknown!"; #endif } const char* Platform::version() { + return PlatformImpl<>::version(); #ifdef PLATFORM_PHOTON return System.version().c_str(); -#elif defined(BOARD_ESP32) || defined(BOARD_ESP8266) - return ESP.getSdkVersion(); #else return "Unknown!"; #endif @@ -72,9 +42,7 @@ Platform::version() int Platform::freeRam() { -#if defined(BOARD_ESP8266) || defined(BOARD_ESP32) - return ESP.getFreeHeap(); -#endif + return PlatformImpl<>::freeRam(); } void @@ -94,26 +62,17 @@ Platform::preSetup() Log.notice("\xf0\x9f\x94\x8c Serial connected"); } #else -#ifdef CONFIG_MQTT Log.begin(LOG_LEVEL_TRACE, Static::instance()->logPrinter()); Static::instance()->setSequencer(Static::instance()); -#else - Log.begin(LOG_LEVEL_TRACE, Static::instance()->logPrinter()); -#endif Log.setSuffix(printNewline); #endif -#ifdef BOARD_ESP32 - esp_task_wdt_init(10, true); - esp_task_wdt_add(NULL); - esp_log_set_vprintf(printEspLog); -#endif #ifdef BOARD_ESP8266 - ESP.wdtEnable(0); if (!ESP.checkFlashCRC()) { Log.fatal("Firmware failed CRC check!!!"); } #endif + PlatformImpl<>::startWatchdog(); } void @@ -121,19 +80,15 @@ Platform::setup() { #ifdef PLATFORM_PHOTON Time.zone(Static::instance()->getTimezone()); -#elif defined(BOARD_ESP32) - constexpr int dst = 1; - configTime(s_timezone* 3600, 3600 * dst, "pool.ntp.org"); -#elif defined(BOARD_ESP8266) -#ifdef CONFIG_WIFI - timeClient.begin(); -#endif #endif + PlatformImpl<>::startNTP(); } void Platform::bootSplash() { + PlatformImpl<>::bootSplash(); + #ifdef PLATFORM_PHOTON Log.notice(u8" Boot pin configuration:"); Log.notice(u8" 2: Setup - %d", bootopts.isSetup); @@ -148,14 +103,7 @@ Platform::bootSplash() lastTaskBuf[15] = 0; Log.error(u8"Crash occurred in task %s", lastTaskBuf); -#ifdef BOARD_ESP8266 - auto rInfo = ESP.getResetInfoPtr(); - if (Platform::bootopts.resetReason == REASON_EXCEPTION_RST) { - Log.error("Fatal exception (%d):", rInfo->exccause); - } - Log.error("epc1=%X, epc2=%X, epc3=%X, excvaddr=%X, depc=%X", - rInfo->epc1, rInfo->epc2, rInfo->epc3, rInfo->excvaddr, rInfo->depc); -#endif + PlatformImpl<>::printCrashInfo(); strncpy(lastTaskBuf, Renderer::lastFigmentName(), sizeof(lastTaskBuf)); lastTaskBuf[15] = 0; @@ -164,7 +112,6 @@ Platform::bootSplash() Log.trace("Startup reason: %d", bootopts.resetReason); - Log.trace("Registered tasks:"); auto it = beginTasks(); while (it != endTasks()) { @@ -180,16 +127,7 @@ Platform::bootSplash() void Platform::loop() { -#ifdef BOARD_ESP8266 -#ifdef CONFIG_WIFI - if (WiFi.status() == WL_CONNECTED) { - timeClient.update(); - } -#endif - ESP.wdtFeed(); -#elif defined(BOARD_ESP32) - esp_task_wdt_reset(); -#endif + PlatformImpl<>::loop(); } bool @@ -202,40 +140,19 @@ Platform::getLocalTime(struct tm* timedata) return true; } return false; -#elif defined(BOARD_ESP32) - time_t rawtime; - memset(&rawtime, 0, sizeof(rawtime)); - time(&rawtime); - (*timedata) = (*localtime(&rawtime)); - return (timedata->tm_year > (2016-1990)); -#else -#ifdef CONFIG_WIFI - timedata->tm_hour = timeClient.getHours(); - timedata->tm_min = timeClient.getMinutes(); -#else - memset(timedata, sizeof(struct tm), 0); - return false; -#endif - return true; #endif + return PlatformImpl<>::getLocalTime(timedata, s_timezone); } const char* Platform::deviceID() { - uint64_t chipid; -#ifdef BOARD_ESP32 - chipid = ESP.getEfuseMac(); -#elif defined(BOARD_ESP8266) - chipid = ESP.getChipId(); -#endif - snprintf(s_deviceID, sizeof(s_deviceID), "%08X", (uint32_t)chipid); - return s_deviceID; + return PlatformImpl<>::deviceID(); } void Platform::addLEDs(CRGB* leds, uint16_t ledCount) { - FastLED.addLeds(leds, ledCount); + FastLED.addLeds(leds, ledCount); } const String @@ -247,12 +164,7 @@ Platform::model() void Platform::restart() { -#ifdef BOARD_ESP8266 - ESP.wdtDisable(); - ESP.restart(); -#elif defined(BOARD_ESP32) - ESP.restart(); -#endif + PlatformImpl<>::restart(); } @@ -260,15 +172,15 @@ void Platform::doReboot(Args& args, Print& out) { out.println("Rebooting"); - Platform::restart(); + restart(); } void Platform::doSafeMode(Args& args, Print& out) { out.println("Rebooting into safe mode"); - Platform::bootopts.forceSafeMode(); - Platform::restart(); + PlatformImpl<>::forceSafeMode(); + restart(); } String s; diff --git a/src/Platform.h b/src/Platform.h index 8deae6c..3130ab3 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -2,6 +2,7 @@ #include #include #include "BootOptions.h" +#include "Hal.h" class Platform : public Task { static int s_timezone; diff --git a/src/inputs/ConfigInput.cpp b/src/inputs/ConfigInput.cpp deleted file mode 100644 index 67ae8e8..0000000 --- a/src/inputs/ConfigInput.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "./ConfigInput.h" -#include "./Static.h" - -STATIC_ALLOC(ConfigInput); -STATIC_TASK(ConfigInput); diff --git a/src/inputs/ConfigInput.h b/src/inputs/ConfigInput.h deleted file mode 100644 index a7d074b..0000000 --- a/src/inputs/ConfigInput.h +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once -#include - -class ConfigInputTask : public BufferedInputSource { - public: - ConfigInputTask() : BufferedInputSource("ConfigInput") {} - - void handleEvent(const InputEvent& evt) override { - if (evt.intent == InputEvent::UserInput) { - Buttons::Chord chord = (Buttons::Chord) evt.asInt(); - switch (chord) { - case Buttons::Circle: - m_currentIntent = nextIntent(); - //Log.info("Next setting... (%d)", m_currentIntent); - break; - case Buttons::CircleTriangle: - //Log.info("Increment..."); - increment(); - break; - case Buttons::CircleCross: - //Log.info("Decrement..."); - decrement(); - break; - case Buttons::Triangle: - //Log.info("Save..."); - setEvent(InputEvent::SaveConfigurationRequest); - break; - default: - break; - } - } - } - -private: - InputEvent::Intent m_currentIntent = InputEvent::SetDisplayLength; - - void decrement() { - int current = 0; - switch (m_currentIntent) { - case InputEvent::SetDisplayLength: - current = Static::instance()->coordMap()->pixelCount; - break; - case InputEvent::SetDisplayOffset: - current = Static::instance()->coordMap()->startPixel; - break; - default: - break; - } - setEvent(InputEvent{m_currentIntent, current - 1}); - } - - void increment() { - int current = 0; - switch (m_currentIntent) { - case InputEvent::SetDisplayLength: - current = Static::instance()->coordMap()->pixelCount; - break; - case InputEvent::SetDisplayOffset: - current = Static::instance()->coordMap()->startPixel; - break; - default: - break; - } - setEvent(InputEvent{m_currentIntent, current + 1}); - } - - InputEvent::Intent nextIntent() { - switch (m_currentIntent) { - case InputEvent::SetDisplayLength: - return InputEvent::SetDisplayOffset; - case InputEvent::SetDisplayOffset: - return InputEvent::SetDisplayLength; - default: - return InputEvent::None; - } - } -}; diff --git a/src/platform/arduino/MQTTTelemetry.cpp b/src/platform/arduino/MQTTTelemetry.cpp index 5d43200..ee9403c 100644 --- a/src/platform/arduino/MQTTTelemetry.cpp +++ b/src/platform/arduino/MQTTTelemetry.cpp @@ -31,7 +31,7 @@ const MQTTDevice Device{ Platform::deviceID(), Platform::deviceName(), Platform::model(), -#ifdef BOARD_ESP8266 +#ifdef ESP8266 ESP.getSketchMD5(), #else "", @@ -95,10 +95,6 @@ const MQTTEntity Lightswitch { "light", Device, "lightswitch" }; -const MQTTEntity flashlightSwitch { - "switch", Device, "flashlight" -}; - const MQTTEntity FPSSensor { "sensor", Device, "fps" }; @@ -124,27 +120,28 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt) m_json.clear(); Lightswitch.toJson(m_json); - - int i = 0; - for(const Sequencer::Scene& scene : m_sequencer->scenes()) { - m_json["fx_list"][i++] = scene.name; - } m_json["brightness"] = true; m_json["rgb"] = true; publishDoc(Lightswitch.configTopic().c_str(), true); - - //Log.verbose("Publish %s %s", Lightswitch.configTopic().c_str(), buf); - //m_mqtt.publish(Lightswitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true); m_mqtt.subscribe(Lightswitch.commandTopic().c_str()); - m_json.clear(); - flashlightSwitch.toJson(m_json, false); - m_json["cmd_t"] = "~/set"; - m_json["ret"] = true; - publishDoc(flashlightSwitch.configTopic().c_str(), true); - //m_mqtt.publish(flashlightSwitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true); - m_mqtt.subscribe(flashlightSwitch.commandTopic().c_str()); + for(auto scene : Static::instance()->scenes()) { + m_json.clear(); + String strName{scene.name}; + MQTTEntity sceneObj { + "scene", + Device, + strName + }; + sceneObj.toJson(m_json, false); + m_json["cmd_t"] = "~/set"; + m_json["ret"] = false; + m_json["payload_on"] = "active"; + publishDoc(sceneObj.configTopic().c_str(), false); + m_mqtt.subscribe(sceneObj.commandTopic().c_str()); + Log.info("Published scene %s", sceneObj.configTopic().c_str()); + } m_json.clear(); FPSSensor.toJson(m_json, false); @@ -168,13 +165,7 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt) } } else { String statTopic = Lightswitch.statTopic(); - if (evt.intent == InputEvent::StopThing && String(evt.asString()) == "Flashlight") { - String flashlightStatTopic = flashlightSwitch.statTopic(); - m_mqtt.publish(flashlightStatTopic.c_str(), "OFF"); - } else if (evt.intent == InputEvent::StartThing && String(evt.asString()) == "Flashlight") { - String flashlightStatTopic = flashlightSwitch.statTopic(); - m_mqtt.publish(flashlightStatTopic.c_str(), "ON"); - } else if (evt.intent == InputEvent::SetPower) { + if (evt.intent == InputEvent::SetPower) { m_json.clear(); m_isOn = evt.asInt() ? true : false; m_json["state"] = m_isOn ? "ON" : "OFF"; @@ -192,7 +183,7 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt) m_json["color"]["b"] = color.b; m_json["state"] = m_isOn ? "ON" : "OFF"; publishDoc(statTopic.c_str()); - } else if (evt.intent == InputEvent::SetPattern) { + } else if (evt.intent == InputEvent::SetScene) { m_json.clear(); m_json["effect"] = evt.asString(); m_json["state"] = m_isOn ? "ON" : "OFF"; @@ -280,17 +271,7 @@ void MQTTTelemetry::callback(char* topic, const char* payload) { setEvent(InputEvent::NetworkActivity); - if (flashlightSwitch.isCommandTopic(topic)) { - if (!strncmp((char*)payload, "ON", sizeof("ON"))) { - Log.notice("Turning on flashlight"); - setEvent(InputEvent{InputEvent::SetPower, true}); - setEvent(InputEvent{InputEvent::SetPattern, "Flashlight"}); - setEvent(InputEvent{InputEvent::SetBrightness, 255}); - } else if (!strncmp((char*)payload, "OFF", sizeof("OFF"))) { - Log.notice("Turning off flashlight"); - setEvent(InputEvent{InputEvent::SetPattern, "Idle"}); - } - } else if (Lightswitch.isCommandTopic(topic)) { + if (Lightswitch.isCommandTopic(topic)) { deserializeJson(m_json, payload); if (m_json.containsKey("state")) { @@ -299,7 +280,7 @@ MQTTTelemetry::callback(char* topic, const char* payload) setEvent(InputEvent{InputEvent::SetPower, true}); } else if (m_json["state"] == "OFF") { Log.notice("Turning off power"); - setEvent(InputEvent{InputEvent::SetPattern, "Idle"}); + setEvent(InputEvent{InputEvent::SetScene, "Idle"}); setEvent(InputEvent{InputEvent::SetPower, false}); } } @@ -352,7 +333,7 @@ MQTTTelemetry::callback(char* topic, const char* payload) if (m_json.containsKey("effect")) { strcpy(m_patternBuf, m_json["effect"].as()); - setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf}); + setEvent(InputEvent{InputEvent::SetScene, m_patternBuf}); } if (m_json.containsKey("color")) { @@ -367,6 +348,19 @@ MQTTTelemetry::callback(char* topic, const char* payload) } Log.notice("Event done."); + } else { + for(auto scene : Static::instance()->scenes()) { + String strName{scene.name}; + MQTTEntity sceneObj { + "scene", + Device, + strName + }; + if (sceneObj.isCommandTopic(topic)) { + setEvent(InputEvent{InputEvent::SetScene, scene.name}); + return; + } + } } } diff --git a/src/platform/arduino/MQTTTelemetry.h b/src/platform/arduino/MQTTTelemetry.h index 6a3ec29..433875a 100644 --- a/src/platform/arduino/MQTTTelemetry.h +++ b/src/platform/arduino/MQTTTelemetry.h @@ -7,9 +7,9 @@ #include "../../Sequencer.h" -#ifdef BOARD_ESP8266 +#ifdef ESP8266 #include -#elif defined(BOARD_ESP32) +#elif defined(ESP32) #include #endif diff --git a/src/platform/arduino/WiFiTask.cpp b/src/platform/arduino/WiFiTask.cpp index 398d1c3..1347f16 100644 --- a/src/platform/arduino/WiFiTask.cpp +++ b/src/platform/arduino/WiFiTask.cpp @@ -1,10 +1,10 @@ #include #include -#ifdef BOARD_ESP8266 +#ifdef ESP8266 #include #endif -#ifdef BOARD_ESP32 +#ifdef ESP32 #include #endif #include "Static.h" diff --git a/src/platform/arduino/BluetoothSerialTelemetry.cpp b/src/platform/arduino/esp32/BluetoothSerialTelemetry.cpp similarity index 100% rename from src/platform/arduino/BluetoothSerialTelemetry.cpp rename to src/platform/arduino/esp32/BluetoothSerialTelemetry.cpp diff --git a/src/platform/arduino/BluetoothSerialTelemetry.h b/src/platform/arduino/esp32/BluetoothSerialTelemetry.h similarity index 100% rename from src/platform/arduino/BluetoothSerialTelemetry.h rename to src/platform/arduino/esp32/BluetoothSerialTelemetry.h diff --git a/src/platform/arduino/esp32/Platform.cpp b/src/platform/arduino/esp32/Platform.cpp new file mode 100644 index 0000000..9c4ec73 --- /dev/null +++ b/src/platform/arduino/esp32/Platform.cpp @@ -0,0 +1,106 @@ +#include "../../../Platform.h" + +#include +#include + +__NOINIT_ATTR static uint8_t s_rebootCount; +__NOINIT_ATTR static uint16_t s_forceSafeMode; +#define SAFE_MODE_MAGIC 6942 + +template<> +void +PlatformImpl::initBootOptions(BootOptions& opts) +{ + opts.resetReason = esp_reset_reason(); + opts.crashCount = s_rebootCount; + if (opts.resetReason >= 4) { // TODO: These values are defined in + // esp32/rom/rtc.h, but not sure if that's included + // on platformio builds + if (opts.crashCount++ >= 3) { + // Boot into safe mode if the watchdog reset us three times in a row. + isSafeMode = true; + } + } else { + opts.crashCount = 0; + } + s_rebootCount = crashCount; +} + +template<> +const char* +PlatformImpl::name() +{ + return "ESP32"; +} + +template<> +const char* +PlatformImpl::version() +{ + return ESP.getSdkVersion(); +} + +template<> +const char* +PlatformImpl::deviceID() +{ + uint64_t chipid; + chipid = ESP.getEfuseMac(); + snprintf(s_deviceID, sizeof(s_deviceID), "%08X", (uint32_t)chipid); + return s_deviceID; +} + +template<> +int +PlatformImpl::freeRam() +{ + return ESP.getFreeHeap(); +} + +int printEspLog(const char* fmt, va_list args) +{ + Log.notice(fmt, args); + return 1; +} + +template<> +void +PlatformImpl::startWatchdog() +{ + esp_task_wdt_init(10, true); + esp_task_wdt_add(NULL); + esp_log_set_vprintf(printEspLog); +} + +template<> +void +PlatformImpl::startNTP() +{ + constexpr int dst = 1; + configTime(0, 3600 * dst, "pool.ntp.org"); +} + +template<> +void +PlatformImpl::loop() +{ + esp_task_wdt_reset(); +} + +template<> +bool +PlatformImpl::getLocalTime(struct tm* timedata, int timezone) +{ + time_t rawtime; + memset(&rawtime, 0, sizeof(rawtime)); + time(&rawtime); + (*timedata) = (*localtime(&rawtime)); + return (timedata->tm_year > (2016-1990)); +} + +template<> +void +PlatformImpl::restart() +{ + ESP.restart(); +} diff --git a/src/platform/arduino/U8Display.cpp b/src/platform/arduino/esp32/U8Display.cpp similarity index 100% rename from src/platform/arduino/U8Display.cpp rename to src/platform/arduino/esp32/U8Display.cpp diff --git a/src/platform/arduino/esp8266/Platform.cpp b/src/platform/arduino/esp8266/Platform.cpp new file mode 100644 index 0000000..f1ffb91 --- /dev/null +++ b/src/platform/arduino/esp8266/Platform.cpp @@ -0,0 +1,134 @@ +#include "../../../Platform.h" +#include +#include +#include +#include + +#define __NOINIT_ATTR __attribute__ ((section (".noinit"))) +__NOINIT_ATTR static uint8_t s_rebootCount; +__NOINIT_ATTR static uint16_t s_forceSafeMode; +#define SAFE_MODE_MAGIC 6942 + +WiFiUDP wifiUdp; +NTPClient timeClient(wifiUdp, "pool.ntp.org", 3600 * -7); + +template<> +const char* +PlatformImpl::name() +{ + return "ESP8266"; +} + +template<> +const char* +PlatformImpl::version() +{ + return ESP.getSdkVersion(); +} + +template<> +int +PlatformImpl::freeRam() +{ + return ESP.getFreeHeap(); +} + +template<> +void +PlatformImpl::startWatchdog() +{ + ESP.wdtEnable(0); +} + +template<> +bool +PlatformImpl::getLocalTime(struct tm* timedata, int timezone) +{ + timedata->tm_hour = (timeClient.getHours() + timezone) % 23; + timedata->tm_min = timeClient.getMinutes(); + return true; +} + +template<> +void +PlatformImpl::startNTP() +{ + timeClient.begin(); +} + +template<> +void +PlatformImpl::loop() +{ + if (WiFi.status() == WL_CONNECTED) { + timeClient.update(); + } + ESP.wdtFeed(); +} + +template<> +const char* +PlatformImpl::deviceID() +{ + static char s_deviceID[15]; + static uint16_t chipid = ESP.getChipId(); + snprintf(s_deviceID, sizeof(s_deviceID), "%08X", (uint32_t)chipid); + return s_deviceID; +} + +template<> +void +PlatformImpl::restart() +{ + ESP.wdtDisable(); + ESP.restart(); +} + +template<> +void +PlatformImpl::bootSplash() +{ + Log.notice("ESP8266!"); +} + +template<> +void +PlatformImpl::printCrashInfo() +{ + auto rInfo = ESP.getResetInfoPtr(); + if (Platform::bootopts.resetReason == REASON_EXCEPTION_RST) { + Log.error("Fatal exception (%d):", rInfo->exccause); + } + Log.error("epc1=%X, epc2=%X, epc3=%X, excvaddr=%X, depc=%X", + rInfo->epc1, rInfo->epc2, rInfo->epc3, rInfo->excvaddr, rInfo->depc); +} + +template<> +void +PlatformImpl::initBootOptions(BootOptions& opts) +{ + struct rst_info resetInfo = *ESP.getResetInfoPtr(); + opts.resetReason = resetInfo.reason; + opts.crashCount = s_rebootCount; + if (resetInfo.reason == REASON_SOFT_WDT_RST || resetInfo.reason == REASON_WDT_RST || resetInfo.reason == REASON_EXCEPTION_RST) { + if (opts.crashCount++ >= 3) { + // Boot into safe mode if the watchdog reset us three times in a row. + opts.isSafeMode = true; + } + } else { + opts.crashCount = 0; + } + s_rebootCount = opts.crashCount; + + if (resetInfo.reason > 0 && s_forceSafeMode == SAFE_MODE_MAGIC) { + opts.isSafeMode = true; + s_forceSafeMode = 0; + } +} + +template<> +void +PlatformImpl::forceSafeMode() +{ + s_forceSafeMode = SAFE_MODE_MAGIC; +} diff --git a/verify-configs.py b/verify-configs.py index 6b695bf..44fc27b 100644 --- a/verify-configs.py +++ b/verify-configs.py @@ -11,4 +11,21 @@ def verify_json(source, target, env): print("Validating " + root + '/' + file + '...') json.load(open(root + '/' + file, 'r')) + usedTasks = set() + + for root, dirnames, files in os.walk("data/profiles/"): + for file in files: + if file.endswith(".json"): + data = json.load(open(root + '/' + file, 'r')) + for task in data['tasks']: + usedTasks.add(task) + + for sceneName in data['scenes']: + for task in data['scenes'][sceneName]: + usedTasks.add(task) + + print("Used tasks:") + for task in sorted(usedTasks): + print("- " + task) + env.AddPreAction("buildfs", verify_json)