renderbug-cpp/src/Platform.cpp

334 lines
7.0 KiB
C++

#include "Platform.h"
#include <ArduinoLog.h>
#include "Static.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
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<MQTTTelemetry>::instance()->logPrinter());
Static<MQTTTelemetry>::instance()->setSequencer(Static<Sequencer>::instance());
#else
Log.begin(LOG_LEVEL_TRACE, Static<SerialInput>::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<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
}
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<WS2812, RENDERBUG_LED_PIN, RENDERBUG_LED_PACKING>(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<SerialInput>::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<Command>&
Platform::commands() const
{
static const std::vector<Command> _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);