#include "Platform.h" #include #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; Platform::TaskRegistration* Platform::firstTask = NULL; Platform::TaskRegistration* Platform::lastTask = NULL; const char* Platform::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() { #ifdef PLATFORM_PHOTON return System.version().c_str(); #elif defined(BOARD_ESP32) || defined(BOARD_ESP8266) return ESP.getSdkVersion(); #else return "Unknown!"; #endif } int Platform::freeRam() { #if defined(BOARD_ESP8266) || defined(BOARD_ESP32) return ESP.getFreeHeap(); #endif } void Platform::preSetup() { Serial.begin(115200); #ifdef PLATFORM_PHOTON System.enableFeature(FEATURE_RETAINED_MEMORY); if (bootopts.isFlash) { System.dfu(); } if (bootopts.isSerial) { bootopts.waitForRelease(); while(!Serial.isConnected()) { Particle.process(); } 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 } void 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 } void Platform::bootSplash() { #ifdef PLATFORM_PHOTON Log.notice(u8" Boot pin configuration:"); Log.notice(u8" 2: Setup - %d", bootopts.isSetup); Log.notice(u8" 3: Serial - %d", bootopts.isSerial); Log.notice(u8" 4: Flash - %d", bootopts.isFlash); #endif if (bootopts.crashCount > 0) { Log.warning(u8"Previous crash detected!!!! We're on attempt %d", bootopts.crashCount); char lastTaskBuf[16]; strncpy(lastTaskBuf, MainLoop::lastTaskName(), sizeof(lastTaskBuf)); 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 strncpy(lastTaskBuf, Renderer::lastFigmentName(), sizeof(lastTaskBuf)); lastTaskBuf[15] = 0; Log.error(u8"Last Figment was %s", lastTaskBuf); } Log.trace("Startup reason: %d", bootopts.resetReason); Log.trace("Registered tasks:"); auto it = beginTasks(); while (it != endTasks()) { if ((*it)->isFigment()) { Log.trace(" Figment: %s", (*it)->name); } else { Log.trace(" %s", (*it)->name); } ++it; } } 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 } bool Platform::getLocalTime(struct tm* timedata) { #ifdef PLATFORM_PHOTON if (Time.isValid()) { timedata->tm_hour = Time.hour(); timedata->tm_min = Time.minute(); 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 } 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; } void Platform::addLEDs(CRGB* leds, uint16_t ledCount) { FastLED.addLeds(leds, ledCount); } const String Platform::model() { static String modelName = String("Renderbug " ) + Platform::name(); return modelName; } void Platform::restart() { #ifdef BOARD_ESP8266 ESP.wdtDisable(); ESP.restart(); #elif defined(BOARD_ESP32) ESP.restart(); #endif } void Platform::doReboot(Args& args, Print& out) { out.println("Rebooting"); Platform::restart(); } void Platform::doSafeMode(Args& args, Print& out) { out.println("Rebooting into safe mode"); Platform::bootopts.forceSafeMode(); Platform::restart(); } String s; void Platform::doTaskStart(Args& args, Print& out) { s = args[1]; MainLoop::instance()->dispatch(InputEvent{InputEvent::StartThing, s.c_str()}); } void Platform::doTaskStop(Args& args, Print& out) { s = args[1]; MainLoop::instance()->dispatch(InputEvent{InputEvent::StopThing, s.c_str()}); } void Platform::doTaskList(Args& args, Print& out) { auto sched = MainLoop::instance()->scheduler; auto printer = Static::instance()->printer(); out.println("Tasks:"); for(auto task : sched.tasks) { bool isFigment = task->isFigment(); if (task->state == Task::Running) { out.print("+"); } else { out.print("-"); } if (isFigment) { out.print("F "); } else { out.print("T "); } out.println(task->name); } } const std::vector& Platform::commands() const { static const std::vector _commands = { {"tasks", &Platform::doTaskList}, {"safe-mode", &Platform::doSafeMode}, {"reboot", &Platform::doReboot}, {"stop", &Platform::doTaskStop}, {"start", &Platform::doTaskStart} }; return _commands; } BootOptions Platform::bootopts; char Platform::s_deviceID[15]; STATIC_ALLOC(Platform); STATIC_TASK(Platform);