build: clean up the mess of ifdefs from platform into a scons-configured hal

This commit is contained in:
Torrie Fischer 2023-12-20 10:47:26 +01:00
parent 236795917a
commit 23993a09cf
21 changed files with 376 additions and 410 deletions

9
build-hal.py Normal file
View File

@ -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"+<platform/{framework}/{board}/*>"])
env.Append(SRC_FILTER=[f"+<platform/{framework}/*.cpp>"])
print(f"- platform/{framework}{board}")

View File

@ -71,7 +71,7 @@ MainLoop::loop()
Task* slowestTask = NULL; Task* slowestTask = NULL;
for(Task* task : scheduler) { for(Task* task : scheduler) {
//unsigned int start = millis(); //unsigned int start = millis();
#if defined(BOARD_ESP32) or defined(BOARD_ESP8266) #if defined(ESP32) or defined(ESP8266)
unsigned int start = ESP.getCycleCount(); unsigned int start = ESP.getCycleCount();
#else #else
unsigned int start = millis(); unsigned int start = millis();
@ -79,7 +79,7 @@ MainLoop::loop()
Log.verbose("Running %s", task->name); Log.verbose("Running %s", task->name);
s_lastTaskName = task->name; s_lastTaskName = task->name;
task->loop(); task->loop();
#if defined(BOARD_ESP32) or defined(BOARD_ESP8266) #if defined(ESP32) or defined(ESP8266)
unsigned int runtime = (ESP.getCycleCount() - start) / 160000; unsigned int runtime = (ESP.getCycleCount() - start) / 160000;
#else #else
unsigned int runtime = millis() - start; unsigned int runtime = millis() - start;

View File

@ -8,20 +8,24 @@
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[env]
extra_scripts = pre:verify-configs.py, pre:build-hal.py
[common_env_data] [common_env_data]
src_filter = "+<*> -<.git/> -<.svn/> -<platform/> -<inputs/> +<inputs/BPM.cpp> +<inputs/Serial.cpp> +<inputs/CircadianRhythm.cpp>" src_filter = +<*>, -<.git/>, -<.svn/>, -<platform/>
lib_ldf_mode = chain+ lib_ldf_mode = chain+
extra_scripts = verify-configs.py
src_build_flags = src_build_flags =
-DRENDERBUG_VERSION=3 -DRENDERBUG_VERSION=3
-DRENDERBUG_LED_PIN=14 -DRENDERBUG_LED_PIN=14
-DRENDERBUG_LED_PACKING=RGB -DRENDERBUG_LED_PACKING=RGB
-DDEFAULT_PATTERN_INDEX=0 -DDEFAULT_PATTERN_INDEX=0
-fstack-protector
-Wall -Wall
lib_deps_external = lib_deps_external =
fastled/FastLED@^3.5.0 fastled/FastLED@^3.5.0
thijse/ArduinoLog@^1.1.0 thijse/ArduinoLog@^1.1.0
bblanchon/ArduinoJson@^6.17.3 bblanchon/ArduinoJson@^6.17.3
JsonStreamingParser
LittleFS LittleFS
[config_u8display] [config_u8display]
@ -31,32 +35,10 @@ lib_deps =
olikraus/U8g2@^2.34.15 olikraus/U8g2@^2.34.15
src_filter = "+<platform/arduino/U8Display.cpp>" src_filter = "+<platform/arduino/U8Display.cpp>"
[config_mqtt]
src_build_flags =
-DCONFIG_MQTT
lib_deps =
knolleary/PubSubClient@^2.8.0
src_filter = "+<platform/arduino/MQTTTelemetry.cpp>"
[config_wifi]
src_build_flags =
-DCONFIG_WIFI
src_filter = "+<platform/arduino/WiFiTask.cpp>"
[config_bluetooth]
src_build_flags =
-DCONFIG_BLUETOOTH
src_filter = "+<platform/arduino/BluetoothSerialTelemetry.cpp>"
lib_deps =
BluetoothSerial
[config_ota] [config_ota]
src_build_flags = src_build_flags =
-DCONFIG_OTA
src_filter = "+<platform/arduino/OTA.cpp>" src_filter = "+<platform/arduino/OTA.cpp>"
lib_deps = lib_deps =
ArduinoOTA
ESP8266mDNS
[config_nocolor] [config_nocolor]
src_build_flags = src_build_flags =
@ -72,28 +54,8 @@ src_build_flags =
-DCONFIG_MPU5060 -DCONFIG_MPU5060
src_filter = "+<inputs/MPU6050.cpp>" src_filter = "+<inputs/MPU6050.cpp>"
[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] [env:esp32]
extends = config_nocolor extends = config_nocolor
extra_scripts = verify-configs.py
board_build.filesystem = littlefs board_build.filesystem = littlefs
platform = espressif32 platform = espressif32
board = featheresp32 board = featheresp32
@ -103,11 +65,13 @@ check_flags =
src_build_flags = src_build_flags =
${common_env_data.src_build_flags} ${common_env_data.src_build_flags}
${config_nocolor.src_build_flags} ${config_nocolor.src_build_flags}
-DPLATFORM_ARDUINO
-DBOARD_ESP32 -DBOARD_ESP32
-DCONFIG_THREADED_INPUTS -DCONFIG_THREADED_INPUTS
-DRENDERBUG_LED_PIN=14
lib_deps = lib_deps =
${common_env_data.lib_deps_external} ${common_env_data.lib_deps_external}
BluetoothSerial
knolleary/PubSubClient@^2.8.0
src_filter = "${common_env_data.src_filter}" src_filter = "${common_env_data.src_filter}"
monitor_filters = esp32_exception_decoder monitor_filters = esp32_exception_decoder
monitor_speed = 115200 monitor_speed = 115200
@ -131,43 +95,19 @@ platform = espressif8266
board = huzzah board = huzzah
framework = arduino framework = arduino
board_build.filesystem = littlefs board_build.filesystem = littlefs
monitor_filters = esp8266_exception_decoder
src_build_flags = src_build_flags =
${common_env_data.src_build_flags} ${common_env_data.src_build_flags}
-DPLATFORM_ARDUINO
-DBOARD_ESP8266
-DCORE_DEBUG_LEVEL=5 -DCORE_DEBUG_LEVEL=5
-fstack-protector
lib_deps = lib_deps =
${common_env_data.lib_deps_external} ${common_env_data.lib_deps_external}
knolleary/PubSubClient@^2.8.0
arduino-libraries/NTPClient@^3.1.0 arduino-libraries/NTPClient@^3.1.0
ESP8266WiFi
ESP8266mDNS
ArduinoOTA
src_filter = "${common_env_data.src_filter}" 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] [env:esp32_display]
extends = env:esp32, config_u8display extends = env:esp32, config_u8display
src_filter = "${env:esp32.src_filter} ${config_u8display.src_filter}" src_filter = "${env:esp32.src_filter} ${config_u8display.src_filter}"
@ -179,46 +119,3 @@ src_build_flags =
${env:esp32.src_build_flags} ${env:esp32.src_build_flags}
${config_u8display.src_build_flags} ${config_u8display.src_build_flags}
-DRENDERBUG_LED_PIN=14 -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

View File

@ -3,10 +3,6 @@
#include <EEPROM.h> #include <EEPROM.h>
#ifdef BOARD_ESP8266
#include <ESP8266WiFi.h>
#endif
#ifdef PLATFORM_PHOTON #ifdef PLATFORM_PHOTON
LEDStatus serialStatus = LEDStatus(RGB_COLOR_ORANGE, LED_PATTERN_FADE, LED_SPEED_FAST, LED_PRIORITY_BACKGROUND); 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); 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; retained bool LAST_BOOT_WAS_SERIAL;
#endif #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 void
BootOptions::initPins() BootOptions::initPins()
{ {
@ -53,40 +34,7 @@ BootOptions::BootOptions()
configStatus.setActive(isSetup); configStatus.setActive(isSetup);
serialStatus.setActive(isSerial); serialStatus.setActive(isSerial);
#endif #endif
#ifdef BOARD_ESP32 PlatformImpl<>::initBootOptions(*this);
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
} }
void void

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include "Hal.h"
struct BootOptions { struct BootOptions {
static void initPins(); static void initPins();
@ -7,7 +8,6 @@ struct BootOptions {
BootOptions(); BootOptions();
void waitForRelease(); void waitForRelease();
void forceSafeMode();
bool isSetup = false; bool isSetup = false;
bool isSerial = false; bool isSerial = false;

View File

@ -6,10 +6,10 @@ filename_iterator::filename_iterator()
{} {}
filename_iterator::filename_iterator(const char* path, const char* suffix) filename_iterator::filename_iterator(const char* path, const char* suffix)
#ifdef BOARD_ESP8266 #ifdef ESP8266
: dir(LittleFS.openDir(path)), : dir(LittleFS.openDir(path)),
#endif #endif
#ifdef BOARD_ESP32 #ifdef ESP32
: dir(LittleFS.open(path)), : dir(LittleFS.open(path)),
#endif #endif
valid(true), valid(true),
@ -26,7 +26,7 @@ filename_iterator::next()
} }
int extPos = -1; int extPos = -1;
do { do {
#ifdef BOARD_ESP8266 #ifdef ESP8266
valid = dir.next(); valid = dir.next();
if (valid) { if (valid) {
String fname = dir.fileName(); String fname = dir.fileName();
@ -36,7 +36,7 @@ filename_iterator::next()
} }
} }
#endif #endif
#ifdef BOARD_ESP32 #ifdef ESP32
File next = dir.openNextFile(); File next = dir.openNextFile();
valid = (bool)next; valid = (bool)next;
if (valid && !next.isDirectory()) { if (valid && !next.isDirectory()) {

View File

@ -24,10 +24,10 @@ struct filename_iterator: public std::iterator<std::input_iterator_tag, const ch
bool valid; bool valid;
const char* suffix; const char* suffix;
#ifdef BOARD_ESP8266 #ifdef ESP8266
Dir dir; Dir dir;
#endif #endif
#ifdef BOARD_ESP32 #ifdef ESP32
File dir; File dir;
#endif #endif
}; };

30
src/Hal.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
struct BootOptions;
typedef enum {
HAL_UNKNOWN,
HAL_ESP32,
HAL_ESP8266
} HalBackend;
constexpr HalBackend DefaultBackend = HAL_ESP8266;
template<HalBackend Backend = DefaultBackend>
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();
};

View File

@ -3,40 +3,16 @@
#include "Static.h" #include "Static.h"
#include <time.h> #include <time.h>
#ifdef BOARD_ESP32
#ifdef CONFIG_WIFI
#include <WiFi.h>
#endif
#include <esp_task_wdt.h>
#elif defined(BOARD_ESP8266)
#ifdef CONFIG_WIFI
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <ctime>
WiFiUDP wifiUdp;
NTPClient timeClient(wifiUdp, "pool.ntp.org", 3600 * -7);
#endif
#endif
#ifdef PLATFORM_PHOTON #ifdef PLATFORM_PHOTON
STARTUP(BootOptions::initPins()); STARTUP(BootOptions::initPins());
#else #else
#include "inputs/Serial.h" #include "inputs/Serial.h"
#ifdef CONFIG_MQTT
#include "platform/arduino/MQTTTelemetry.h" #include "platform/arduino/MQTTTelemetry.h"
#endif
void printNewline(Print* logOutput, int logLevel) void printNewline(Print* logOutput, int logLevel)
{ {
(void)logLevel; // unused (void)logLevel; // unused
logOutput->print("\n"); logOutput->print("\n");
} }
int printEspLog(const char* fmt, va_list args)
{
Log.notice(fmt, args);
return 1;
}
#endif #endif
int Platform::s_timezone = 0; int Platform::s_timezone = 0;
@ -46,24 +22,18 @@ Platform::TaskRegistration* Platform::lastTask = NULL;
const char* const char*
Platform::name() Platform::name()
{ {
return PlatformImpl<>::name();
#ifdef PLATFORM_PHOTON #ifdef PLATFORM_PHOTON
return "Photon"; return "Photon";
#elif defined(BOARD_ESP8266)
return "ESP8266";
#elif defined(BOARD_ESP32)
return "ESP32";
#else
return "Unknown!";
#endif #endif
} }
const char* const char*
Platform::version() Platform::version()
{ {
return PlatformImpl<>::version();
#ifdef PLATFORM_PHOTON #ifdef PLATFORM_PHOTON
return System.version().c_str(); return System.version().c_str();
#elif defined(BOARD_ESP32) || defined(BOARD_ESP8266)
return ESP.getSdkVersion();
#else #else
return "Unknown!"; return "Unknown!";
#endif #endif
@ -72,9 +42,7 @@ Platform::version()
int int
Platform::freeRam() Platform::freeRam()
{ {
#if defined(BOARD_ESP8266) || defined(BOARD_ESP32) return PlatformImpl<>::freeRam();
return ESP.getFreeHeap();
#endif
} }
void void
@ -94,26 +62,17 @@ Platform::preSetup()
Log.notice("\xf0\x9f\x94\x8c Serial connected"); Log.notice("\xf0\x9f\x94\x8c Serial connected");
} }
#else #else
#ifdef CONFIG_MQTT
Log.begin(LOG_LEVEL_TRACE, Static<MQTTTelemetry>::instance()->logPrinter()); Log.begin(LOG_LEVEL_TRACE, Static<MQTTTelemetry>::instance()->logPrinter());
Static<MQTTTelemetry>::instance()->setSequencer(Static<Sequencer>::instance()); Static<MQTTTelemetry>::instance()->setSequencer(Static<Sequencer>::instance());
#else
Log.begin(LOG_LEVEL_TRACE, Static<SerialInput>::instance()->logPrinter());
#endif
Log.setSuffix(printNewline); Log.setSuffix(printNewline);
#endif #endif
#ifdef BOARD_ESP32
esp_task_wdt_init(10, true);
esp_task_wdt_add(NULL);
esp_log_set_vprintf(printEspLog);
#endif
#ifdef BOARD_ESP8266 #ifdef BOARD_ESP8266
ESP.wdtEnable(0);
if (!ESP.checkFlashCRC()) { if (!ESP.checkFlashCRC()) {
Log.fatal("Firmware failed CRC check!!!"); Log.fatal("Firmware failed CRC check!!!");
} }
#endif #endif
PlatformImpl<>::startWatchdog();
} }
void void
@ -121,19 +80,15 @@ Platform::setup()
{ {
#ifdef PLATFORM_PHOTON #ifdef PLATFORM_PHOTON
Time.zone(Static<Platform>::instance()->getTimezone()); Time.zone(Static<Platform>::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 #endif
PlatformImpl<>::startNTP();
} }
void void
Platform::bootSplash() Platform::bootSplash()
{ {
PlatformImpl<>::bootSplash();
#ifdef PLATFORM_PHOTON #ifdef PLATFORM_PHOTON
Log.notice(u8" Boot pin configuration:"); Log.notice(u8" Boot pin configuration:");
Log.notice(u8" 2: Setup - %d", bootopts.isSetup); Log.notice(u8" 2: Setup - %d", bootopts.isSetup);
@ -148,14 +103,7 @@ Platform::bootSplash()
lastTaskBuf[15] = 0; lastTaskBuf[15] = 0;
Log.error(u8"Crash occurred in task %s", lastTaskBuf); Log.error(u8"Crash occurred in task %s", lastTaskBuf);
#ifdef BOARD_ESP8266 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);
#endif
strncpy(lastTaskBuf, Renderer::lastFigmentName(), sizeof(lastTaskBuf)); strncpy(lastTaskBuf, Renderer::lastFigmentName(), sizeof(lastTaskBuf));
lastTaskBuf[15] = 0; lastTaskBuf[15] = 0;
@ -164,7 +112,6 @@ Platform::bootSplash()
Log.trace("Startup reason: %d", bootopts.resetReason); Log.trace("Startup reason: %d", bootopts.resetReason);
Log.trace("Registered tasks:"); Log.trace("Registered tasks:");
auto it = beginTasks(); auto it = beginTasks();
while (it != endTasks()) { while (it != endTasks()) {
@ -180,16 +127,7 @@ Platform::bootSplash()
void void
Platform::loop() Platform::loop()
{ {
#ifdef BOARD_ESP8266 PlatformImpl<>::loop();
#ifdef CONFIG_WIFI
if (WiFi.status() == WL_CONNECTED) {
timeClient.update();
}
#endif
ESP.wdtFeed();
#elif defined(BOARD_ESP32)
esp_task_wdt_reset();
#endif
} }
bool bool
@ -202,40 +140,19 @@ Platform::getLocalTime(struct tm* timedata)
return true; return true;
} }
return false; 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 #endif
return PlatformImpl<>::getLocalTime(timedata, s_timezone);
} }
const char* const char*
Platform::deviceID() Platform::deviceID()
{ {
uint64_t chipid; return PlatformImpl<>::deviceID();
#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;
} }
void void
Platform::addLEDs(CRGB* leds, uint16_t ledCount) { Platform::addLEDs(CRGB* leds, uint16_t ledCount) {
FastLED.addLeds<WS2812, RENDERBUG_LED_PIN, RENDERBUG_LED_PACKING>(leds, ledCount); FastLED.addLeds<NEOPIXEL, RENDERBUG_LED_PIN>(leds, ledCount);
} }
const String const String
@ -247,12 +164,7 @@ Platform::model()
void void
Platform::restart() { Platform::restart() {
#ifdef BOARD_ESP8266 PlatformImpl<>::restart();
ESP.wdtDisable();
ESP.restart();
#elif defined(BOARD_ESP32)
ESP.restart();
#endif
} }
@ -260,15 +172,15 @@ void
Platform::doReboot(Args& args, Print& out) Platform::doReboot(Args& args, Print& out)
{ {
out.println("Rebooting"); out.println("Rebooting");
Platform::restart(); restart();
} }
void void
Platform::doSafeMode(Args& args, Print& out) Platform::doSafeMode(Args& args, Print& out)
{ {
out.println("Rebooting into safe mode"); out.println("Rebooting into safe mode");
Platform::bootopts.forceSafeMode(); PlatformImpl<>::forceSafeMode();
Platform::restart(); restart();
} }
String s; String s;

View File

@ -2,6 +2,7 @@
#include <FastLED.h> #include <FastLED.h>
#include <Figments.h> #include <Figments.h>
#include "BootOptions.h" #include "BootOptions.h"
#include "Hal.h"
class Platform : public Task { class Platform : public Task {
static int s_timezone; static int s_timezone;

View File

@ -1,5 +0,0 @@
#include "./ConfigInput.h"
#include "./Static.h"
STATIC_ALLOC(ConfigInput);
STATIC_TASK(ConfigInput);

View File

@ -1,77 +0,0 @@
#pragma once
#include <Figments.h>
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<ConfigService>::instance()->coordMap()->pixelCount;
break;
case InputEvent::SetDisplayOffset:
current = Static<ConfigService>::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<ConfigService>::instance()->coordMap()->pixelCount;
break;
case InputEvent::SetDisplayOffset:
current = Static<ConfigService>::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;
}
}
};

View File

@ -31,7 +31,7 @@ const MQTTDevice Device{
Platform::deviceID(), Platform::deviceID(),
Platform::deviceName(), Platform::deviceName(),
Platform::model(), Platform::model(),
#ifdef BOARD_ESP8266 #ifdef ESP8266
ESP.getSketchMD5(), ESP.getSketchMD5(),
#else #else
"", "",
@ -95,10 +95,6 @@ const MQTTEntity Lightswitch {
"light", Device, "lightswitch" "light", Device, "lightswitch"
}; };
const MQTTEntity flashlightSwitch {
"switch", Device, "flashlight"
};
const MQTTEntity FPSSensor { const MQTTEntity FPSSensor {
"sensor", Device, "fps" "sensor", Device, "fps"
}; };
@ -124,27 +120,28 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt)
m_json.clear(); m_json.clear();
Lightswitch.toJson(m_json); 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["brightness"] = true;
m_json["rgb"] = true; m_json["rgb"] = true;
publishDoc(Lightswitch.configTopic().c_str(), 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_mqtt.subscribe(Lightswitch.commandTopic().c_str());
for(auto scene : Static<Sequencer>::instance()->scenes()) {
m_json.clear(); m_json.clear();
flashlightSwitch.toJson(m_json, false); String strName{scene.name};
MQTTEntity sceneObj {
"scene",
Device,
strName
};
sceneObj.toJson(m_json, false);
m_json["cmd_t"] = "~/set"; m_json["cmd_t"] = "~/set";
m_json["ret"] = true; m_json["ret"] = false;
publishDoc(flashlightSwitch.configTopic().c_str(), true); m_json["payload_on"] = "active";
//m_mqtt.publish(flashlightSwitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true); publishDoc(sceneObj.configTopic().c_str(), false);
m_mqtt.subscribe(flashlightSwitch.commandTopic().c_str()); m_mqtt.subscribe(sceneObj.commandTopic().c_str());
Log.info("Published scene %s", sceneObj.configTopic().c_str());
}
m_json.clear(); m_json.clear();
FPSSensor.toJson(m_json, false); FPSSensor.toJson(m_json, false);
@ -168,13 +165,7 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt)
} }
} else { } else {
String statTopic = Lightswitch.statTopic(); String statTopic = Lightswitch.statTopic();
if (evt.intent == InputEvent::StopThing && String(evt.asString()) == "Flashlight") { if (evt.intent == InputEvent::SetPower) {
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) {
m_json.clear(); m_json.clear();
m_isOn = evt.asInt() ? true : false; m_isOn = evt.asInt() ? true : false;
m_json["state"] = m_isOn ? "ON" : "OFF"; m_json["state"] = m_isOn ? "ON" : "OFF";
@ -192,7 +183,7 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt)
m_json["color"]["b"] = color.b; m_json["color"]["b"] = color.b;
m_json["state"] = m_isOn ? "ON" : "OFF"; m_json["state"] = m_isOn ? "ON" : "OFF";
publishDoc(statTopic.c_str()); publishDoc(statTopic.c_str());
} else if (evt.intent == InputEvent::SetPattern) { } else if (evt.intent == InputEvent::SetScene) {
m_json.clear(); m_json.clear();
m_json["effect"] = evt.asString(); m_json["effect"] = evt.asString();
m_json["state"] = m_isOn ? "ON" : "OFF"; m_json["state"] = m_isOn ? "ON" : "OFF";
@ -280,17 +271,7 @@ void
MQTTTelemetry::callback(char* topic, const char* payload) MQTTTelemetry::callback(char* topic, const char* payload)
{ {
setEvent(InputEvent::NetworkActivity); setEvent(InputEvent::NetworkActivity);
if (flashlightSwitch.isCommandTopic(topic)) { if (Lightswitch.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)) {
deserializeJson(m_json, payload); deserializeJson(m_json, payload);
if (m_json.containsKey("state")) { if (m_json.containsKey("state")) {
@ -299,7 +280,7 @@ MQTTTelemetry::callback(char* topic, const char* payload)
setEvent(InputEvent{InputEvent::SetPower, true}); setEvent(InputEvent{InputEvent::SetPower, true});
} else if (m_json["state"] == "OFF") { } else if (m_json["state"] == "OFF") {
Log.notice("Turning off power"); Log.notice("Turning off power");
setEvent(InputEvent{InputEvent::SetPattern, "Idle"}); setEvent(InputEvent{InputEvent::SetScene, "Idle"});
setEvent(InputEvent{InputEvent::SetPower, false}); setEvent(InputEvent{InputEvent::SetPower, false});
} }
} }
@ -352,7 +333,7 @@ MQTTTelemetry::callback(char* topic, const char* payload)
if (m_json.containsKey("effect")) { if (m_json.containsKey("effect")) {
strcpy(m_patternBuf, m_json["effect"].as<const char*>()); strcpy(m_patternBuf, m_json["effect"].as<const char*>());
setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf}); setEvent(InputEvent{InputEvent::SetScene, m_patternBuf});
} }
if (m_json.containsKey("color")) { if (m_json.containsKey("color")) {
@ -367,6 +348,19 @@ MQTTTelemetry::callback(char* topic, const char* payload)
} }
Log.notice("Event done."); Log.notice("Event done.");
} else {
for(auto scene : Static<Sequencer>::instance()->scenes()) {
String strName{scene.name};
MQTTEntity sceneObj {
"scene",
Device,
strName
};
if (sceneObj.isCommandTopic(topic)) {
setEvent(InputEvent{InputEvent::SetScene, scene.name});
return;
}
}
} }
} }

View File

@ -7,9 +7,9 @@
#include "../../Sequencer.h" #include "../../Sequencer.h"
#ifdef BOARD_ESP8266 #ifdef ESP8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#elif defined(BOARD_ESP32) #elif defined(ESP32)
#include <WiFi.h> #include <WiFi.h>
#endif #endif

View File

@ -1,10 +1,10 @@
#include <Input.h> #include <Input.h>
#include <ArduinoLog.h> #include <ArduinoLog.h>
#ifdef BOARD_ESP8266 #ifdef ESP8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#endif #endif
#ifdef BOARD_ESP32 #ifdef ESP32
#include <WiFi.h> #include <WiFi.h>
#endif #endif
#include "Static.h" #include "Static.h"

View File

@ -0,0 +1,106 @@
#include "../../../Platform.h"
#include <WiFi.h>
#include <esp_task_wdt.h>
__NOINIT_ATTR static uint8_t s_rebootCount;
__NOINIT_ATTR static uint16_t s_forceSafeMode;
#define SAFE_MODE_MAGIC 6942
template<>
void
PlatformImpl<HAL_ESP32>::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<HAL_ESP32>::name()
{
return "ESP32";
}
template<>
const char*
PlatformImpl<HAL_ESP32>::version()
{
return ESP.getSdkVersion();
}
template<>
const char*
PlatformImpl<HAL_ESP32>::deviceID()
{
uint64_t chipid;
chipid = ESP.getEfuseMac();
snprintf(s_deviceID, sizeof(s_deviceID), "%08X", (uint32_t)chipid);
return s_deviceID;
}
template<>
int
PlatformImpl<HAL_ESP32>::freeRam()
{
return ESP.getFreeHeap();
}
int printEspLog(const char* fmt, va_list args)
{
Log.notice(fmt, args);
return 1;
}
template<>
void
PlatformImpl<HAL_ESP32>::startWatchdog()
{
esp_task_wdt_init(10, true);
esp_task_wdt_add(NULL);
esp_log_set_vprintf(printEspLog);
}
template<>
void
PlatformImpl<HAL_ESP32>::startNTP()
{
constexpr int dst = 1;
configTime(0, 3600 * dst, "pool.ntp.org");
}
template<>
void
PlatformImpl<HAL_ESP32>::loop()
{
esp_task_wdt_reset();
}
template<>
bool
PlatformImpl<HAL_ESP32>::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<HAL_ESP32>::restart()
{
ESP.restart();
}

View File

@ -0,0 +1,134 @@
#include "../../../Platform.h"
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <ctime>
#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<HAL_ESP8266>::name()
{
return "ESP8266";
}
template<>
const char*
PlatformImpl<HAL_ESP8266>::version()
{
return ESP.getSdkVersion();
}
template<>
int
PlatformImpl<HAL_ESP8266>::freeRam()
{
return ESP.getFreeHeap();
}
template<>
void
PlatformImpl<HAL_ESP8266>::startWatchdog()
{
ESP.wdtEnable(0);
}
template<>
bool
PlatformImpl<HAL_ESP8266>::getLocalTime(struct tm* timedata, int timezone)
{
timedata->tm_hour = (timeClient.getHours() + timezone) % 23;
timedata->tm_min = timeClient.getMinutes();
return true;
}
template<>
void
PlatformImpl<HAL_ESP8266>::startNTP()
{
timeClient.begin();
}
template<>
void
PlatformImpl<HAL_ESP8266>::loop()
{
if (WiFi.status() == WL_CONNECTED) {
timeClient.update();
}
ESP.wdtFeed();
}
template<>
const char*
PlatformImpl<HAL_ESP8266>::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<HAL_ESP8266>::restart()
{
ESP.wdtDisable();
ESP.restart();
}
template<>
void
PlatformImpl<HAL_ESP8266>::bootSplash()
{
Log.notice("ESP8266!");
}
template<>
void
PlatformImpl<HAL_ESP8266>::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<HAL_ESP8266>::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<HAL_ESP8266>::forceSafeMode()
{
s_forceSafeMode = SAFE_MODE_MAGIC;
}

View File

@ -11,4 +11,21 @@ def verify_json(source, target, env):
print("Validating " + root + '/' + file + '...') print("Validating " + root + '/' + file + '...')
json.load(open(root + '/' + file, 'r')) 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) env.AddPreAction("buildfs", verify_json)