Compare commits
No commits in common. "9a3186edbd96d4f4514126ad34f59fcd7e9545a1" and "74c2ddb405e645046d8dbbd5ae4a70b74f24ac4d" have entirely different histories.
9a3186edbd
...
74c2ddb405
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"rotation": 3,
|
|
||||||
"strides": [
|
|
||||||
{"x": 0, "y": 0, "pixels": 17},
|
|
||||||
{"x": 0, "y": 1, "pixels": 17},
|
|
||||||
{"x": 0, "y": 2, "pixels": 17},
|
|
||||||
{"x": 0, "y": 3, "pixels": 17},
|
|
||||||
{"x": 0, "y": 4, "pixels": 16},
|
|
||||||
{"x": 0, "y": 5, "pixels": 17},
|
|
||||||
{"x": 0, "y": 6, "pixels": 17},
|
|
||||||
{"x": 0, "y": 7, "pixels": 17},
|
|
||||||
{"x": 0, "y": 8, "pixels": 17},
|
|
||||||
{"x": 0, "y": 9, "pixels": 17},
|
|
||||||
{"x": 0, "y": 10, "pixels": 17},
|
|
||||||
{"x": 0, "y": 11, "pixels": 17},
|
|
||||||
{"x": 0, "y": 12, "pixels": 18},
|
|
||||||
{"x": 0, "y": 13, "pixels": 17},
|
|
||||||
{"x": 0, "y": 14, "pixels": 18},
|
|
||||||
{"x": 0, "y": 15, "pixels": 17},
|
|
||||||
{"x": 0, "y": 16, "pixels": 17},
|
|
||||||
{"x": 0, "y": 17, "pixels": 17}
|
|
||||||
]
|
|
||||||
}
|
|
@ -4,8 +4,7 @@
|
|||||||
"Renderer",
|
"Renderer",
|
||||||
"SerialInput",
|
"SerialInput",
|
||||||
"BPM",
|
"BPM",
|
||||||
"Bluetooth",
|
"Bluetooth"
|
||||||
"Serial"
|
|
||||||
],
|
],
|
||||||
"scenes": {
|
"scenes": {
|
||||||
"Idle": ["Solid", "MPU5060", "Pulse", "IdleColors", "CircadianRhythm"],
|
"Idle": ["Solid", "MPU5060", "Pulse", "IdleColors", "CircadianRhythm"],
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
"WiFi",
|
"WiFi",
|
||||||
"MQTT",
|
"MQTT",
|
||||||
"ArduinoOTA",
|
"ArduinoOTA",
|
||||||
"BPM",
|
"BPM"
|
||||||
"Serial"
|
|
||||||
],
|
],
|
||||||
"scenes": {
|
"scenes": {
|
||||||
"Idle": ["Solid", "MPU5060", "IdleColors", "CircadianRhythm"],
|
"Idle": ["Solid", "MPU5060", "IdleColors", "CircadianRhythm"],
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
"WiFi",
|
"WiFi",
|
||||||
"MQTT",
|
"MQTT",
|
||||||
"ArduinoOTA",
|
"ArduinoOTA",
|
||||||
"UpdateStatusAnimation",
|
"UpdateStatusAnimation"
|
||||||
"Serial"
|
|
||||||
],
|
],
|
||||||
"scenes": {
|
"scenes": {
|
||||||
"Idle": ["Solid", "MPU5060", "Pulse", "IdleColors", "CircadianRhythm"],
|
"Idle": ["Solid", "MPU5060", "Pulse", "IdleColors", "CircadianRhythm"],
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"tasks": [
|
|
||||||
"Bluetooth",
|
|
||||||
"WiFi",
|
|
||||||
"Renderer",
|
|
||||||
"Power",
|
|
||||||
"BPM",
|
|
||||||
"MQTT",
|
|
||||||
"ArduinoOTA",
|
|
||||||
"UpdateStatusAnimation",
|
|
||||||
"Serial"
|
|
||||||
],
|
|
||||||
"scenes": {
|
|
||||||
"Rain": ["Rain", "Rainbow"],
|
|
||||||
"Test": ["Test"],
|
|
||||||
"Idle": ["Solid", "Pulse", "Rainbow", "CircadianRhythm"],
|
|
||||||
"Acid": ["Chimes", "Pulse", "IdleColors", "Rainbow"],
|
|
||||||
"Flashlight": ["Flashlight"]
|
|
||||||
},
|
|
||||||
"surfaceMap": "ponder",
|
|
||||||
"defaults": {
|
|
||||||
"mqtt.ip": "10.0.0.2"
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,8 +4,7 @@
|
|||||||
"Renderer",
|
"Renderer",
|
||||||
"ConfigInput",
|
"ConfigInput",
|
||||||
"ConfigDisplay",
|
"ConfigDisplay",
|
||||||
"InputBlip",
|
"InputBlip"
|
||||||
"Serial"
|
|
||||||
],
|
],
|
||||||
"scenes": [],
|
"scenes": [],
|
||||||
"surfaceMap": "default"
|
"surfaceMap": "default"
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#include "./Command.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
doNothing(Args& args, Print& printer)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Command::Command() : func(doNothing) {}
|
|
@ -1,33 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
class Args {
|
|
||||||
private:
|
|
||||||
String *str;
|
|
||||||
public:
|
|
||||||
Args(String *str) : str(str) {}
|
|
||||||
String operator[](int pos) {
|
|
||||||
char buf[64];
|
|
||||||
strncpy(buf, str->c_str(), sizeof(buf));
|
|
||||||
char *args = strtok(buf, " ");
|
|
||||||
while (pos > 0 && args != NULL) {
|
|
||||||
args = strtok(NULL, " ");
|
|
||||||
pos--;
|
|
||||||
}
|
|
||||||
if (args == NULL) {
|
|
||||||
return String();
|
|
||||||
}
|
|
||||||
return String(args);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CommandList;
|
|
||||||
|
|
||||||
struct Command {
|
|
||||||
using Executor = std::function<void(Args&, Print& output)>;
|
|
||||||
Executor func;
|
|
||||||
const char* name = NULL;
|
|
||||||
|
|
||||||
Command();
|
|
||||||
Command(const char* name, Executor func) : name(name), func(func) {}
|
|
||||||
};
|
|
@ -43,7 +43,6 @@ CRGB&
|
|||||||
Display::pixelAt(int idx)
|
Display::pixelAt(int idx)
|
||||||
{
|
{
|
||||||
const int kx = idx % pixelCount();
|
const int kx = idx % pixelCount();
|
||||||
assert(abs(kx) < pixelCount());
|
|
||||||
if (kx < 0) {
|
if (kx < 0) {
|
||||||
return m_pixels[pixelCount() + 1 + kx];
|
return m_pixels[pixelCount() + 1 + kx];
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#include "./Figment.h"
|
|
||||||
|
|
||||||
const std::vector<Command> emptyCommands;
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
|
||||||
Task::commands() const
|
|
||||||
{
|
|
||||||
return emptyCommands;
|
|
||||||
}
|
|
@ -2,7 +2,6 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
#include "./Command.h"
|
|
||||||
|
|
||||||
#define F_LIKELY(x) __builtin_expect(!!(x), true)
|
#define F_LIKELY(x) __builtin_expect(!!(x), true)
|
||||||
#define F_UNLIKELY(x) __builtin_expect(!!(x), false)
|
#define F_UNLIKELY(x) __builtin_expect(!!(x), false)
|
||||||
@ -69,8 +68,6 @@ struct Task : public virtual Loopable {
|
|||||||
|
|
||||||
const char* name = "";
|
const char* name = "";
|
||||||
State state = Stopped;
|
State state = Stopped;
|
||||||
|
|
||||||
virtual const std::vector<Command> &commands() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,10 +114,6 @@ struct InputEvent: public Variant {
|
|||||||
InputEvent()
|
InputEvent()
|
||||||
: Variant(), intent(None) {}
|
: Variant(), intent(None) {}
|
||||||
|
|
||||||
bool operator!=(const InputEvent::Intent& otherIntent) {
|
|
||||||
return intent != otherIntent;
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent intent;
|
Intent intent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,23 +24,17 @@ MainLoop::dispatchSync(const InputEvent& evt)
|
|||||||
{
|
{
|
||||||
if (evt.intent == InputEvent::StartThing || evt.intent == InputEvent::StopThing) {
|
if (evt.intent == InputEvent::StartThing || evt.intent == InputEvent::StopThing) {
|
||||||
const bool jobState = (evt.intent == InputEvent::StartThing);
|
const bool jobState = (evt.intent == InputEvent::StartThing);
|
||||||
bool wasFound = false;
|
|
||||||
for(auto figmentJob: scheduler.tasks) {
|
for(auto figmentJob: scheduler.tasks) {
|
||||||
if (!strcmp(figmentJob->name, evt.asString())) {
|
if (!strcmp(figmentJob->name, evt.asString())) {
|
||||||
if (jobState) {
|
if (jobState) {
|
||||||
Log.trace("** Starting %s", figmentJob->name);
|
Log.trace("** Starting %s", figmentJob->name);
|
||||||
figmentJob->start();
|
figmentJob->start();
|
||||||
wasFound = true;
|
|
||||||
} else {
|
} else {
|
||||||
Log.trace("** Stopping %s", figmentJob->name);
|
Log.trace("** Stopping %s", figmentJob->name);
|
||||||
figmentJob->stop();
|
figmentJob->stop();
|
||||||
wasFound = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!wasFound) {
|
|
||||||
Log.warning("** Unable to find task %s", evt.asString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Task* task : scheduler) {
|
for(Task* task : scheduler) {
|
||||||
@ -92,8 +86,7 @@ MainLoop::loop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
frameSpeed = millis() - frameStart;
|
frameSpeed = millis() - frameStart;
|
||||||
if (frameSpeed >= 34) { // TODO: Configure max frame time at build. Default
|
if (frameSpeed >= 23) { // TODO: Configure max frame time at build
|
||||||
// to 30FPS
|
|
||||||
const char* slowestName = (slowestTask->name ? slowestTask->name : "(Unnamed)");
|
const char* slowestName = (slowestTask->name ? slowestTask->name : "(Unnamed)");
|
||||||
Log.warning("Slow frame: %dms, %d tasks, longest task %s was %dms", frameSpeed, taskCount, slowestName, slowest);
|
Log.warning("Slow frame: %dms, %d tasks, longest task %s was %dms", frameSpeed, taskCount, slowestName, slowest);
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,6 @@
|
|||||||
|
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
|
|
||||||
#ifndef __NOINIT_ATTR // Pre-defined on esp32
|
|
||||||
#define __NOINIT_ATTR __attribute__ ((section (".noinit")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__NOINIT_ATTR const char* s_lastFigmentName;
|
|
||||||
|
|
||||||
const char*
|
|
||||||
Renderer::lastFigmentName()
|
|
||||||
{
|
|
||||||
return s_lastFigmentName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Renderer::loop()
|
Renderer::loop()
|
||||||
{
|
{
|
||||||
@ -25,7 +13,6 @@ Renderer::loop()
|
|||||||
unsigned int frameStart = ESP.getCycleCount();
|
unsigned int frameStart = ESP.getCycleCount();
|
||||||
#endif
|
#endif
|
||||||
Log.verbose("Render %s", figment->name);
|
Log.verbose("Render %s", figment->name);
|
||||||
s_lastFigmentName = figment->name;
|
|
||||||
figment->render(dpy);
|
figment->render(dpy);
|
||||||
#if defined(BOARD_ESP32) or defined(BOARD_ESP8266)
|
#if defined(BOARD_ESP32) or defined(BOARD_ESP8266)
|
||||||
unsigned int runtime = (ESP.getCycleCount() - frameStart) / 160000;
|
unsigned int runtime = (ESP.getCycleCount() - frameStart) / 160000;
|
||||||
|
@ -10,8 +10,6 @@ public:
|
|||||||
void loop() override;
|
void loop() override;
|
||||||
void onStart() override;
|
void onStart() override;
|
||||||
|
|
||||||
static const char* lastFigmentName();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<Figment*> m_figments;
|
const std::vector<Figment*> m_figments;
|
||||||
const std::vector<Display*> m_displays;
|
const std::vector<Display*> m_displays;
|
||||||
|
@ -86,8 +86,6 @@ struct Ringbuf {
|
|||||||
size_t size() {
|
size_t size() {
|
||||||
if (m_tail > m_head) {
|
if (m_tail > m_head) {
|
||||||
return m_tail - m_head;
|
return m_tail - m_head;
|
||||||
} else if (m_tail == m_head) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return m_tail + (Size - m_head);
|
return m_tail + (Size - m_head);
|
||||||
}
|
}
|
||||||
|
@ -54,20 +54,17 @@ void
|
|||||||
Surface::paintShader(Surface::Shader shader)
|
Surface::paintShader(Surface::Shader shader)
|
||||||
{
|
{
|
||||||
PerfCounter _("paintShader");
|
PerfCounter _("paintShader");
|
||||||
uint8_t startX = min(start.x, end.x);
|
const uint16_t width = end.x - start.x + 1;
|
||||||
uint8_t startY = min(start.y, end.y);
|
const uint16_t height = end.y - start.y + 1;
|
||||||
uint8_t endX = max(start.x, end.x);
|
|
||||||
uint8_t endY = max(start.y, end.y);
|
|
||||||
const uint16_t width = endX - startX + 1;
|
|
||||||
const uint16_t height = endY - startY + 1;
|
|
||||||
const uint8_t xMod = 255 / width;
|
const uint8_t xMod = 255 / width;
|
||||||
const uint8_t yMod = 255 / height;
|
const uint8_t yMod = 255 / height;
|
||||||
for(auto x = 0; x < width; x++) {
|
for(auto x = 0; x < width; x++) {
|
||||||
for(auto y = 0; y < height; y++) {
|
for(auto y = 0; y < height; y++) {
|
||||||
PhysicalCoordinates coords{x + startX, y + startY};
|
PhysicalCoordinates coords{x + start.x, y + start.y};
|
||||||
VirtualCoordinates virtCoords{m_display->coordinateMapping()->physicalToVirtualCoords(coords)};
|
VirtualCoordinates virtCoords{m_display->coordinateMapping()->physicalToVirtualCoords(coords)};
|
||||||
VirtualCoordinates surfaceCoords{xMod * x, yMod * y};
|
VirtualCoordinates surfaceCoords{xMod * x, yMod * y};
|
||||||
//Log.notice("width=%d height=%d vx=%d vy=%d sx=%d sy=%d x=%d y=%d px=%d py=%d", width, height, startX, startY, x, y, coords.x, coords.y); // 256 = 1.0
|
//Log.notice("width=%d height=%d vx=%d vy=%d sx=%d sy=%d x=%d y=%d px=%d py=%d", width, height, start.x, start.y, x, y, coords.x, coords.y);
|
||||||
|
// 256 = 1.0
|
||||||
// 128 = 0.0
|
// 128 = 0.0
|
||||||
// 0 = 1.0
|
// 0 = 1.0
|
||||||
shader(m_display->pixelAt(coords), virtCoords, coords, surfaceCoords);
|
shader(m_display->pixelAt(coords), virtCoords, coords, surfaceCoords);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[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/> -<inputs/> +<inputs/BPM.cpp>"
|
||||||
lib_ldf_mode = chain+
|
lib_ldf_mode = chain+
|
||||||
extra_scripts = verify-configs.py
|
extra_scripts = verify-configs.py
|
||||||
src_build_flags =
|
src_build_flags =
|
||||||
|
@ -14,21 +14,10 @@ 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
|
#ifdef BOARD_ESP32
|
||||||
#define __NOINIT_ATTR __attribute__ ((section (".noinit")))
|
__NOINIT_ATTR uint8_t s_rebootCount = 0;
|
||||||
#endif
|
#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()
|
||||||
{
|
{
|
||||||
@ -71,20 +60,23 @@ BootOptions::BootOptions()
|
|||||||
#ifdef BOARD_ESP8266
|
#ifdef BOARD_ESP8266
|
||||||
struct rst_info resetInfo = *ESP.getResetInfoPtr();
|
struct rst_info resetInfo = *ESP.getResetInfoPtr();
|
||||||
resetReason = resetInfo.reason;
|
resetReason = resetInfo.reason;
|
||||||
crashCount = s_rebootCount;
|
EEPROM.begin(sizeof(crashCount));
|
||||||
if (resetInfo.reason == REASON_SOFT_WDT_RST || resetInfo.reason == REASON_WDT_RST || resetInfo.reason == REASON_EXCEPTION_RST) {
|
EEPROM.get(sizeof(HardwareConfig) + 32, crashCount);
|
||||||
|
EEPROM.end();
|
||||||
|
if (resetInfo.reason == REASON_WDT_RST || resetInfo.reason == REASON_EXCEPTION_RST) {
|
||||||
if (crashCount++ >= 3) {
|
if (crashCount++ >= 3) {
|
||||||
// Boot into safe mode if the watchdog reset us three times in a row.
|
// Boot into safe mode if the watchdog reset us three times in a row.
|
||||||
isSafeMode = true;
|
isSafeMode = true;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
crashCount = 0;
|
EEPROM.begin(sizeof(crashCount));
|
||||||
|
EEPROM.put(sizeof(HardwareConfig) + 32, crashCount);
|
||||||
|
EEPROM.end();
|
||||||
}
|
}
|
||||||
s_rebootCount = crashCount;
|
} else if (crashCount != 0) {
|
||||||
|
crashCount = 0;
|
||||||
if (resetInfo.reason > 0 && s_forceSafeMode == SAFE_MODE_MAGIC) {
|
EEPROM.begin(sizeof(crashCount));
|
||||||
isSafeMode = true;
|
EEPROM.put(sizeof(HardwareConfig) + 32, crashCount);
|
||||||
s_forceSafeMode = 0;
|
EEPROM.end();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ struct BootOptions {
|
|||||||
BootOptions();
|
BootOptions();
|
||||||
|
|
||||||
void waitForRelease();
|
void waitForRelease();
|
||||||
void forceSafeMode();
|
|
||||||
|
|
||||||
bool isSetup = false;
|
bool isSetup = false;
|
||||||
bool isSerial = false;
|
bool isSerial = false;
|
||||||
|
@ -53,7 +53,7 @@ Configuration::get(const char* key, bool defaultVal) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticJsonDocument<2048> jsonConfig;
|
StaticJsonDocument<1024> jsonConfig;
|
||||||
|
|
||||||
constexpr uint16_t HardwareConfig::MAX_LED_NUM;
|
constexpr uint16_t HardwareConfig::MAX_LED_NUM;
|
||||||
|
|
||||||
@ -154,11 +154,6 @@ ConfigService::loadMap(const String& mapName)
|
|||||||
deserializeJson(jsonConfig, configFile);
|
deserializeJson(jsonConfig, configFile);
|
||||||
configFile.close();
|
configFile.close();
|
||||||
JsonArray strideList = jsonConfig["strides"];
|
JsonArray strideList = jsonConfig["strides"];
|
||||||
if (jsonConfig.containsKey("rotation")) {
|
|
||||||
m_jsonMap.rotation = jsonConfig["rotation"];
|
|
||||||
} else {
|
|
||||||
m_jsonMap.rotation = 0;
|
|
||||||
}
|
|
||||||
m_jsonMap.load(strideList);
|
m_jsonMap.load(strideList);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -218,9 +213,8 @@ ConfigService::loadProfile(const char* profileName)
|
|||||||
m_jsonMap.loadDefault();
|
m_jsonMap.loadDefault();
|
||||||
}
|
}
|
||||||
Log.notice("config: Loaded!");
|
Log.notice("config: Loaded!");
|
||||||
strcpy(m_config.data.loadedProfile, profileName);
|
|
||||||
} else {
|
} else {
|
||||||
Log.warning("config: Could not find profile json %s!", fname.c_str());
|
Log.warning("config: Could not load profile %s!", profileName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,56 +254,5 @@ ConfigService::handleEvent(const InputEvent &evt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
doMapList(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
static const auto conf = Static<ConfigService>::instance();
|
|
||||||
out.println("Available maps:");
|
|
||||||
LittleFS.begin();
|
|
||||||
for(auto it = conf->mapsBegin();it != conf->mapsEnd(); it++) {
|
|
||||||
out.println(*it);
|
|
||||||
}
|
|
||||||
LittleFS.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doSave(Args& args, Print& print)
|
|
||||||
{
|
|
||||||
MainLoop::instance()->dispatch(InputEvent::SaveConfigurationRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
static String s;
|
|
||||||
|
|
||||||
void
|
|
||||||
doSetProfile(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
s = args[1];
|
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::LoadConfigurationByName, s.c_str()});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doCoordMap(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
VirtualCoordinates coords{atoi(args[1].c_str()), atoi(args[2].c_str())};
|
|
||||||
auto map = Static<ConfigService>::instance()->coordMap();
|
|
||||||
auto pPos = map->virtualToPhysicalCoords(coords);
|
|
||||||
auto idx = map->physicalCoordsToIndex(pPos);
|
|
||||||
char buf[32];
|
|
||||||
sprintf(buf, "(%d, %d) -> (%d, %d) -> %d", coords.x, coords.y, pPos.x, pPos.y, idx);
|
|
||||||
out.println(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
|
||||||
ConfigService::commands() const
|
|
||||||
{
|
|
||||||
static const std::vector<Command> _commands = {
|
|
||||||
{"save", doSave},
|
|
||||||
{"profile", doSetProfile},
|
|
||||||
{"maps", doMapList},
|
|
||||||
{"coordmap", doCoordMap}
|
|
||||||
};
|
|
||||||
return _commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_ALLOC(ConfigService);
|
STATIC_ALLOC(ConfigService);
|
||||||
STATIC_TASK(ConfigService);
|
STATIC_TASK(ConfigService);
|
||||||
|
56
src/Config.h
56
src/Config.h
@ -2,7 +2,6 @@
|
|||||||
#include <Figments.h>
|
#include <Figments.h>
|
||||||
#include "JsonCoordinateMapping.h"
|
#include "JsonCoordinateMapping.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <LittleFS.h>
|
|
||||||
|
|
||||||
class Configuration {
|
class Configuration {
|
||||||
public:
|
public:
|
||||||
@ -40,7 +39,7 @@ struct HardwareConfig {
|
|||||||
void save();
|
void save();
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
static constexpr uint16_t MAX_LED_NUM = 512;
|
static constexpr uint16_t MAX_LED_NUM = 255;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t getCRC() const;
|
uint8_t getCRC() const;
|
||||||
@ -60,59 +59,6 @@ struct ConfigService: public Task {
|
|||||||
const char* loadedProfile() const;
|
const char* loadedProfile() const;
|
||||||
void overrideProfile(const char* profileName);
|
void overrideProfile(const char* profileName);
|
||||||
const char* getConfigValue(const char* key) const;
|
const char* getConfigValue(const char* key) const;
|
||||||
const std::vector<Command>& commands() const override;
|
|
||||||
|
|
||||||
struct filename_iterator: public std::iterator<std::input_iterator_tag, const char*> {
|
|
||||||
Dir dir;
|
|
||||||
String ret;
|
|
||||||
bool valid;
|
|
||||||
const char* suffix;
|
|
||||||
explicit filename_iterator() : suffix(NULL), valid(false) {}
|
|
||||||
explicit filename_iterator(const char* path, const char* suffix) : dir(LittleFS.openDir(path)), valid(true), suffix(suffix) {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
void next() {
|
|
||||||
if (!valid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int extPos = -1;
|
|
||||||
do {
|
|
||||||
valid = dir.next();
|
|
||||||
Log.info("valid %F", valid);
|
|
||||||
if (valid) {
|
|
||||||
String fname = dir.fileName();
|
|
||||||
extPos = fname.lastIndexOf(suffix);
|
|
||||||
Log.info("compare %s %d", fname.c_str(), extPos);
|
|
||||||
if (extPos != -1) {
|
|
||||||
ret = fname.substring(0, extPos);
|
|
||||||
Log.info("found %s", ret.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (valid && extPos == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
filename_iterator& operator++() {
|
|
||||||
next();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
filename_iterator& operator++(int) {filename_iterator ret = *this; ++(*this); return ret;}
|
|
||||||
bool operator==(const filename_iterator &other) const { return valid == other.valid;}
|
|
||||||
bool operator!=(const filename_iterator &other) const { return !(*this == other); }
|
|
||||||
const char* operator*() const {
|
|
||||||
if (!valid) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return ret.c_str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
filename_iterator mapsBegin() const { return filename_iterator("/maps/", ".json"); }
|
|
||||||
filename_iterator mapsEnd() const { return filename_iterator(); }
|
|
||||||
|
|
||||||
filename_iterator profilesBegin() const { return filename_iterator("/profiles/", ".json"); }
|
|
||||||
filename_iterator profilesEnd() const { return filename_iterator(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HardwareConfig m_config;
|
HardwareConfig m_config;
|
||||||
|
119
src/Platform.cpp
119
src/Platform.cpp
@ -16,21 +16,21 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
WiFiUDP wifiUdp;
|
WiFiUDP wifiUdp;
|
||||||
NTPClient timeClient(wifiUdp, "pool.ntp.org", 3600 * -7);
|
//NTPClient timeClient(wifiUdp, "pool.ntp.org", 3600 * -7);
|
||||||
|
NTPClient timeClient(wifiUdp, "10.0.0.1", 3600 * -7);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PLATFORM_PHOTON
|
#ifdef PLATFORM_PHOTON
|
||||||
STARTUP(BootOptions::initPins());
|
STARTUP(BootOptions::initPins());
|
||||||
#else
|
#else
|
||||||
#include "inputs/Serial.h"
|
|
||||||
#ifdef CONFIG_MQTT
|
#ifdef CONFIG_MQTT
|
||||||
#include "platform/arduino/MQTTTelemetry.h"
|
#include "platform/arduino/MQTTTelemetry.h"
|
||||||
#endif
|
#endif
|
||||||
void printNewline(Print* logOutput, int logLevel)
|
void printNewline(Print* logOutput, int logLevel)
|
||||||
{
|
{
|
||||||
(void)logLevel; // unused
|
(void)logLevel; // unused
|
||||||
logOutput->print("\n");
|
logOutput->print("\r\n");
|
||||||
}
|
}
|
||||||
int printEspLog(const char* fmt, va_list args)
|
int printEspLog(const char* fmt, va_list args)
|
||||||
{
|
{
|
||||||
@ -62,7 +62,7 @@ Platform::version()
|
|||||||
{
|
{
|
||||||
#ifdef PLATFORM_PHOTON
|
#ifdef PLATFORM_PHOTON
|
||||||
return System.version().c_str();
|
return System.version().c_str();
|
||||||
#elif defined(BOARD_ESP32) || defined(BOARD_ESP8266)
|
#elif defined(BOARD_ESP32)
|
||||||
return ESP.getSdkVersion();
|
return ESP.getSdkVersion();
|
||||||
#else
|
#else
|
||||||
return "Unknown!";
|
return "Unknown!";
|
||||||
@ -72,7 +72,10 @@ Platform::version()
|
|||||||
int
|
int
|
||||||
Platform::freeRam()
|
Platform::freeRam()
|
||||||
{
|
{
|
||||||
#if defined(BOARD_ESP8266) || defined(BOARD_ESP32)
|
#ifdef BOARD_ESP8266
|
||||||
|
return ESP.getFreeHeap();
|
||||||
|
#endif
|
||||||
|
#ifdef BOARD_ESP32
|
||||||
return ESP.getFreeHeap();
|
return ESP.getFreeHeap();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -81,6 +84,7 @@ void
|
|||||||
Platform::preSetup()
|
Platform::preSetup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
delay(5000);
|
||||||
#ifdef PLATFORM_PHOTON
|
#ifdef PLATFORM_PHOTON
|
||||||
System.enableFeature(FEATURE_RETAINED_MEMORY);
|
System.enableFeature(FEATURE_RETAINED_MEMORY);
|
||||||
if (bootopts.isFlash) {
|
if (bootopts.isFlash) {
|
||||||
@ -98,7 +102,7 @@ Platform::preSetup()
|
|||||||
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
|
#else
|
||||||
Log.begin(LOG_LEVEL_TRACE, Static<SerialInput>::instance()->logPrinter());
|
Log.begin(LOG_LEVEL_TRACE, &Serial);
|
||||||
#endif
|
#endif
|
||||||
Log.setSuffix(printNewline);
|
Log.setSuffix(printNewline);
|
||||||
#endif
|
#endif
|
||||||
@ -110,9 +114,6 @@ Platform::preSetup()
|
|||||||
#endif
|
#endif
|
||||||
#ifdef BOARD_ESP8266
|
#ifdef BOARD_ESP8266
|
||||||
ESP.wdtEnable(0);
|
ESP.wdtEnable(0);
|
||||||
if (!ESP.checkFlashCRC()) {
|
|
||||||
Log.fatal("Firmware failed CRC check!!!");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,30 +142,6 @@ Platform::bootSplash()
|
|||||||
Log.notice(u8" 4: Flash - %d", bootopts.isFlash);
|
Log.notice(u8" 4: Flash - %d", bootopts.isFlash);
|
||||||
#endif
|
#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:");
|
Log.trace("Registered tasks:");
|
||||||
auto it = beginTasks();
|
auto it = beginTasks();
|
||||||
while (it != endTasks()) {
|
while (it != endTasks()) {
|
||||||
@ -234,8 +211,8 @@ Platform::deviceID()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Platform::addLEDs(CRGB* leds, uint16_t ledCount) {
|
Platform::addLEDs(CRGB* leds, unsigned int ledCount) {
|
||||||
FastLED.addLeds<WS2812, RENDERBUG_LED_PIN, RENDERBUG_LED_PACKING>(leds, ledCount);
|
FastLED.addLeds<WS2812B, RENDERBUG_LED_PIN, RENDERBUG_LED_PACKING>(leds, ledCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
const String
|
const String
|
||||||
@ -255,78 +232,6 @@ Platform::restart() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__attribute__((noreturn))
|
|
||||||
void
|
|
||||||
doReboot(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
out.println("Rebooting");
|
|
||||||
Platform::restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((noreturn))
|
|
||||||
void
|
|
||||||
doSafeMode(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
out.println("Rebooting into safe mode");
|
|
||||||
Platform::bootopts.forceSafeMode();
|
|
||||||
Platform::restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
String s;
|
|
||||||
|
|
||||||
void
|
|
||||||
doTaskStart(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
s = args[1];
|
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::StartThing, s.c_str()});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doTaskStop(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
s = args[1];
|
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::StopThing, s.c_str()});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
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> _commands = {
|
|
||||||
{"tasks", doTaskList},
|
|
||||||
{"safe-mode", doSafeMode},
|
|
||||||
{"reboot", doReboot},
|
|
||||||
{"stop", doTaskStop},
|
|
||||||
{"start", doTaskStart}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
|
||||||
Platform::commands() const
|
|
||||||
{
|
|
||||||
return _commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
BootOptions
|
BootOptions
|
||||||
Platform::bootopts;
|
Platform::bootopts;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class Platform : public Task {
|
|||||||
static BootOptions bootopts;
|
static BootOptions bootopts;
|
||||||
static void setTimezone(int tz) { s_timezone = tz; }
|
static void setTimezone(int tz) { s_timezone = tz; }
|
||||||
static int getTimezone() { return s_timezone; }
|
static int getTimezone() { return s_timezone; }
|
||||||
static void addLEDs(CRGB* leds, uint16_t ledCount);
|
static void addLEDs(CRGB* leds, unsigned int ledCount);
|
||||||
|
|
||||||
static const char* name();
|
static const char* name();
|
||||||
static const char* version();
|
static const char* version();
|
||||||
@ -105,6 +105,4 @@ class Platform : public Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void restart();
|
static void restart();
|
||||||
|
|
||||||
const std::vector<Command>& commands() const override;
|
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "./Platform.h"
|
#include "./Platform.h"
|
||||||
#include "./Static.h"
|
#include "./Static.h"
|
||||||
#include "./Config.h"
|
#include "./Config.h"
|
||||||
#include "./inputs/Serial.h"
|
|
||||||
|
|
||||||
TaskFunc safeModeNag([]{
|
TaskFunc safeModeNag([]{
|
||||||
static uint8_t frame = 0;
|
static uint8_t frame = 0;
|
||||||
@ -42,7 +41,6 @@ SafeMode::safeModeApp{{
|
|||||||
// System logging
|
// System logging
|
||||||
Static<LogService>::instance(),
|
Static<LogService>::instance(),
|
||||||
&safeModeNag,
|
&safeModeNag,
|
||||||
Static<SerialInput>::instance(),
|
|
||||||
#ifdef CONFIG_WIFI
|
#ifdef CONFIG_WIFI
|
||||||
// ESP Wifi
|
// ESP Wifi
|
||||||
Static<WiFiTask>::instance(),
|
Static<WiFiTask>::instance(),
|
||||||
|
@ -94,34 +94,5 @@ Sequencer::handleEvent(const InputEvent& evt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
doScenes(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
out.println("Available scenes: ");
|
|
||||||
for (auto scene : Static<Sequencer>::instance()->scenes()) {
|
|
||||||
out.println(scene.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String s;
|
|
||||||
|
|
||||||
void
|
|
||||||
doScene(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
s = args[1];
|
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPattern, s.c_str()});
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Command> _commands = {
|
|
||||||
{"scene", doScene},
|
|
||||||
{"scenes", doScenes}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
|
||||||
Sequencer::commands() const
|
|
||||||
{
|
|
||||||
return _commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_ALLOC(Sequencer);
|
STATIC_ALLOC(Sequencer);
|
||||||
STATIC_TASK(Sequencer);
|
STATIC_TASK(Sequencer);
|
||||||
|
@ -23,7 +23,6 @@ public:
|
|||||||
|
|
||||||
const char* currentSceneName();
|
const char* currentSceneName();
|
||||||
const std::vector<Scene> scenes() const;
|
const std::vector<Scene> scenes() const;
|
||||||
const std::vector<Command>& commands() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_idx;
|
int m_idx;
|
||||||
|
@ -2,54 +2,6 @@
|
|||||||
#include "../Static.h"
|
#include "../Static.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
void
|
|
||||||
doBrightness(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
String nextVal = args[1];
|
|
||||||
uint8_t newBrightness = (uint8_t)atoi(nextVal.c_str());
|
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetBrightness, newBrightness});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doOn(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPower, 255});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doOff(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPower, 0});
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doForceBrightness(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
String nextVal = args[1];
|
|
||||||
uint8_t newBrightness = (uint8_t)atoi(nextVal.c_str());
|
|
||||||
Static<Power>::instance()->forceBrightness(newBrightness);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Power::forceBrightness(uint8_t v)
|
|
||||||
{
|
|
||||||
m_forced = true;
|
|
||||||
FastLED.setBrightness(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Command> _commands = {
|
|
||||||
{"brightness", doBrightness},
|
|
||||||
{"brightness-force", doForceBrightness},
|
|
||||||
{"on", doOn},
|
|
||||||
{"off", doOff}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
|
||||||
Power::commands() const
|
|
||||||
{
|
|
||||||
return _commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Power::handleConfigChange(const Configuration& config)
|
Power::handleConfigChange(const Configuration& config)
|
||||||
{
|
{
|
||||||
|
@ -10,17 +10,15 @@ public:
|
|||||||
switch (evt.intent) {
|
switch (evt.intent) {
|
||||||
case InputEvent::PowerToggle:
|
case InputEvent::PowerToggle:
|
||||||
m_powerState = m_powerState.value() <= 128 ? 255 : 0;
|
m_powerState = m_powerState.value() <= 128 ? 255 : 0;
|
||||||
m_forced = false;
|
//Log.info("POWER TOGGLE %d", m_powerState.value());
|
||||||
Log.notice("Power toggled to %t", m_powerState);
|
|
||||||
break;
|
break;
|
||||||
case InputEvent::SetPower:
|
case InputEvent::SetPower:
|
||||||
m_powerState = evt.asInt() == 0 ? 0 : 255;
|
m_powerState = evt.asInt() == 0 ? 0 : 255;
|
||||||
m_forced = false;
|
Log.notice("Power is now %d", m_powerState);
|
||||||
Log.notice("Power state is now %t", m_powerState);
|
|
||||||
break;
|
break;
|
||||||
case InputEvent::SetBrightness:
|
case InputEvent::SetBrightness:
|
||||||
m_brightness = evt.asInt();
|
m_brightness = evt.asInt();
|
||||||
m_forced = false;
|
m_brightness = 255;
|
||||||
break;
|
break;
|
||||||
case InputEvent::Beat:
|
case InputEvent::Beat:
|
||||||
m_beatDecay.set(0, 255);
|
m_beatDecay.set(0, 255);
|
||||||
@ -42,7 +40,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void render(Display* dpy) const override {
|
void render(Display* dpy) const override {
|
||||||
if (F_LIKELY(m_valid && !m_forced)) {
|
if (F_LIKELY(m_valid)) {
|
||||||
const uint8_t decayedBrightness = scale8((uint8_t)m_brightness, m_useBPM ? ease8InOutCubic((uint8_t)m_beatDecay) : 255);
|
const uint8_t decayedBrightness = scale8((uint8_t)m_brightness, m_useBPM ? ease8InOutCubic((uint8_t)m_beatDecay) : 255);
|
||||||
const uint8_t clippedBrightness = std::min(decayedBrightness, (uint8_t)255);
|
const uint8_t clippedBrightness = std::min(decayedBrightness, (uint8_t)255);
|
||||||
const uint8_t scaledBrightness = scale8(m_powerState, clippedBrightness);
|
const uint8_t scaledBrightness = scale8(m_powerState, clippedBrightness);
|
||||||
@ -52,9 +50,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void forceBrightness(uint8_t v);
|
|
||||||
|
|
||||||
const std::vector<Command>& commands() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AnimatedNumber m_powerState = 255;
|
AnimatedNumber m_powerState = 255;
|
||||||
@ -64,5 +59,4 @@ private:
|
|||||||
uint16_t m_milliamps = 500;
|
uint16_t m_milliamps = 500;
|
||||||
bool m_valid = true;
|
bool m_valid = true;
|
||||||
bool m_useBPM = false;
|
bool m_useBPM = false;
|
||||||
bool m_forced = false;
|
|
||||||
};
|
};
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
#include "Rain.h"
|
|
||||||
#include "../Static.h"
|
|
||||||
|
|
||||||
RainAnimation::RainAnimation() : Figment("Rain")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RainAnimation::render(Display* dpy) const
|
|
||||||
{
|
|
||||||
Surface sfc = Surface(dpy, {0, 0}, {255, 255});
|
|
||||||
uint8_t noiseY = sin8(m_noiseOffset % 255);
|
|
||||||
uint8_t noiseX = cos8(m_noiseOffset % 255);
|
|
||||||
sfc.paintShader([=](CRGB& pixel, const VirtualCoordinates& coords, const PhysicalCoordinates, const VirtualCoordinates& surfaceCoords) {
|
|
||||||
pixel = CHSV(m_hue, inoise8(noiseX + coords.x, coords.y), inoise8(m_noiseOffset + coords.x, noiseY + coords.y));
|
|
||||||
});
|
|
||||||
m_drops.render(dpy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RainAnimation::loop()
|
|
||||||
{
|
|
||||||
EVERY_N_MILLISECONDS(250) {
|
|
||||||
m_drops.update();
|
|
||||||
}
|
|
||||||
EVERY_N_MILLISECONDS(60) {
|
|
||||||
m_hue.update(1);
|
|
||||||
m_curColor.h = m_hue;
|
|
||||||
}
|
|
||||||
m_noiseOffset += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RainAnimation::handleEvent(const InputEvent& evt) {
|
|
||||||
if (evt.intent == InputEvent::SetColor) {
|
|
||||||
CHSV next = rgb2hsv_approximate(evt.asRGB());
|
|
||||||
m_hue.set(next.h);
|
|
||||||
m_drops.forEach([=](Raindrop& drop) {
|
|
||||||
drop.nextColor = next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_ALLOC(RainAnimation);
|
|
||||||
STATIC_TASK(RainAnimation);
|
|
@ -1,48 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <Figments.h>
|
|
||||||
|
|
||||||
class RainAnimation: public Figment {
|
|
||||||
private:
|
|
||||||
struct Raindrop {
|
|
||||||
int size = 20;
|
|
||||||
int x = random(255);
|
|
||||||
int y = random(255);
|
|
||||||
CHSV fg{180, 255, 255};
|
|
||||||
CHSV nextColor{180, 255, 255};
|
|
||||||
|
|
||||||
void render(Display* dpy) const {
|
|
||||||
Surface sfc{dpy, {x - size, y - size}, {x + size, y + size}};
|
|
||||||
paint(sfc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void paint(Surface& sfc) const {
|
|
||||||
sfc.paintShader([=](CRGB& pixel, const VirtualCoordinates& coords, const PhysicalCoordinates, const VirtualCoordinates& surfaceCoords) {
|
|
||||||
int distance = 255 - (min(128, abs(128 - surfaceCoords.x)) + min(128, abs(128 - surfaceCoords.y)));
|
|
||||||
pixel += CHSV{fg.h, fg.s, scale8_video(fg.v, distance)};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void update() {
|
|
||||||
if (random(255) >= 100) {
|
|
||||||
y++;
|
|
||||||
if (y >= 255) {
|
|
||||||
y = 0;
|
|
||||||
x += 13;
|
|
||||||
x %= 255;
|
|
||||||
fg = nextColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SpriteList<Raindrop, 10> m_drops;
|
|
||||||
uint16_t m_noiseOffset;
|
|
||||||
CHSV m_curColor{180, 255, 255};
|
|
||||||
AnimatedNumber m_hue;
|
|
||||||
public:
|
|
||||||
RainAnimation();
|
|
||||||
//void handleEvent(const InputEvent& evt) override;
|
|
||||||
void loop() override;
|
|
||||||
void render(Display* dpy) const override;
|
|
||||||
void handleEvent(const InputEvent& evt) override;
|
|
||||||
};
|
|
@ -1,32 +1,53 @@
|
|||||||
#include "./TestAnimation.h"
|
#include "./TestAnimation.h"
|
||||||
#include "../Static.h"
|
|
||||||
#include <FastLED.h>
|
#include <FastLED.h>
|
||||||
|
|
||||||
|
const char*
|
||||||
|
TestAnimation::name() const
|
||||||
|
{
|
||||||
|
return "Test";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TestAnimation::handleEvent(const InputEvent& evt)
|
||||||
|
{
|
||||||
|
if (evt.intent == InputEvent::Acceleration) {
|
||||||
|
if (evt.asInt() > 5) {
|
||||||
|
m_brightness += 15;
|
||||||
|
}
|
||||||
|
m_hue += scale8(evt.asInt(), 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.intent == InputEvent::UserInput) {
|
||||||
|
switch(evt.asInt()) {
|
||||||
|
case 1:
|
||||||
|
m_brightness.set(255, 0);break;
|
||||||
|
case 2:
|
||||||
|
m_saturation.set(255, 128);break;
|
||||||
|
default:
|
||||||
|
m_brightness.set(255, 0);
|
||||||
|
m_saturation.set(255, 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TestAnimation::loop()
|
TestAnimation::loop()
|
||||||
{
|
{
|
||||||
m_x += 1;
|
m_x += 4;
|
||||||
m_y += 1;
|
if (m_x % 12 == 0) {
|
||||||
|
m_y += 28;
|
||||||
|
}
|
||||||
|
m_hue.update();
|
||||||
|
m_saturation.update();
|
||||||
|
m_brightness.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TestAnimation::render(Display* dpy) const
|
TestAnimation::render(Display* dpy) const
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < dpy->pixelCount(); i++) {
|
for(uint8_t col = 0; col < 3; col++) {
|
||||||
dpy->pixelAt(i) = CRGB{255, 255, 255};
|
for (uint8_t i = 0; i < 254; i+=10) {
|
||||||
|
dpy->pixelAt(VirtualCoordinates{(uint8_t)(m_x + (col * (254 / 3))), (uint8_t)(i + m_y)}) = CHSV(m_hue, m_saturation + 100, scale8(i, m_brightness));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
// Blank the canvas to white
|
|
||||||
Surface{dpy, {0, 0}, {255, 255}} = CRGB{255, 255, 255};
|
|
||||||
// Draw red line on top row
|
|
||||||
Surface{dpy, {0, 0}, {255, 0}} = CRGB{255, 0, 0};
|
|
||||||
// Green line on first column
|
|
||||||
Surface{dpy, {0, 0}, {0, 255}} = CRGB{0, 255, 0};
|
|
||||||
|
|
||||||
//Surface{dpy, {m_x, 0}, {m_x, 255}} = CRGB{255, 0, 0};
|
|
||||||
///Surface{dpy, {0, m_y}, {255, m_y}} = CRGB{255, 0, 0};
|
|
||||||
//dpy->pixelAt(VirtualCoordinates{m_x, m_y}) = CRGB{255, 0, 255};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC_ALLOC(TestAnimation);
|
|
||||||
STATIC_TASK(TestAnimation);
|
|
||||||
|
@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
class TestAnimation: public Figment {
|
class TestAnimation: public Figment {
|
||||||
public:
|
public:
|
||||||
TestAnimation() : Figment("Test") {}
|
const char* name() const;
|
||||||
|
void handleEvent(const InputEvent& evt) override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
void render(Display* dpy) const override;
|
void render(Display* dpy) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AnimatedNumber m_hue;
|
||||||
|
AnimatedNumber m_saturation;
|
||||||
|
AnimatedNumber m_brightness;
|
||||||
uint8_t m_x;
|
uint8_t m_x;
|
||||||
uint8_t m_y;
|
uint8_t m_y;
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ UpdateStatus::handleEvent(const InputEvent& evt)
|
|||||||
if (evt.intent == InputEvent::FirmwareUpdate) {
|
if (evt.intent == InputEvent::FirmwareUpdate) {
|
||||||
static int updateCount = 0;
|
static int updateCount = 0;
|
||||||
updateCount++;
|
updateCount++;
|
||||||
Log.info("Update count %d", updateCount);
|
//Log.info("Update count %d", updateCount);
|
||||||
m_updateReady = true;
|
m_updateReady = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,12 +22,11 @@ UpdateStatus::loop()
|
|||||||
void
|
void
|
||||||
UpdateStatus::render(Display* dpy) const
|
UpdateStatus::render(Display* dpy) const
|
||||||
{
|
{
|
||||||
int pos = m_pos % dpy->pixelCount();
|
|
||||||
if (m_updateReady) {
|
if (m_updateReady) {
|
||||||
for(int i = 0; i < 12; i+=3) {
|
for(int i = 0; i < 12; i+=3) {
|
||||||
dpy->pixelAt(pos + i) = CRGB(255, 0, 0);
|
dpy->pixelAt(m_pos + i) = CRGB(255, 0, 0);
|
||||||
dpy->pixelAt(pos + i + 1) = CRGB(0, 255, 0);
|
dpy->pixelAt(m_pos + i + 1) = CRGB(0, 255, 0);
|
||||||
dpy->pixelAt(pos + i + 2) = CRGB(0, 0, 255);
|
dpy->pixelAt(m_pos + i + 2) = CRGB(0, 0, 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,5 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_updateReady = false;
|
bool m_updateReady = false;
|
||||||
int m_pos = 0;
|
uint8_t m_pos = 0;
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
#include "./BPM.h"
|
#include "./BPM.h"
|
||||||
#include "../Static.h"
|
#include "../Static.h"
|
||||||
|
|
||||||
void
|
|
||||||
doBPM(Args& args, Print& out)
|
|
||||||
{
|
|
||||||
uint8_t newBPM(atoi(args[1].c_str()));
|
|
||||||
Static<BPM>::instance()->setBPM(newBPM);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Command> _commands = {
|
|
||||||
{"bpm", doBPM}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
|
||||||
BPM::commands() const
|
|
||||||
{
|
|
||||||
return _commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC_ALLOC(BPM);
|
STATIC_ALLOC(BPM);
|
||||||
STATIC_TASK(BPM);
|
STATIC_TASK(BPM);
|
||||||
|
@ -18,8 +18,6 @@ public:
|
|||||||
ConfigTaskMixin::handleEvent(evt);
|
ConfigTaskMixin::handleEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Command>& commands() const override;
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
InputSource::loop();
|
InputSource::loop();
|
||||||
ConfigTaskMixin::loop();
|
ConfigTaskMixin::loop();
|
||||||
@ -31,11 +29,6 @@ public:
|
|||||||
Log.notice("bpm: idle BPM set to %d (requested %d)", (int)msToBPM(m_msPerBeat), (int)requestedBPM);
|
Log.notice("bpm: idle BPM set to %d (requested %d)", (int)msToBPM(m_msPerBeat), (int)requestedBPM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBPM(double bpm) {
|
|
||||||
m_msPerBeat = 60000.0 / (double)bpm;
|
|
||||||
Log.notice("bpm: Command changed to %d (requested %d)", (int)msToBPM(m_msPerBeat), (int)bpm);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputEvent read() override {
|
InputEvent read() override {
|
||||||
if (m_msPerBeat > 0) {
|
if (m_msPerBeat > 0) {
|
||||||
uint16_t now = millis();
|
uint16_t now = millis();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Figments.h>
|
#include <Figments.h>
|
||||||
#include "../Platform.h"
|
|
||||||
|
|
||||||
struct ScheduleEntry {
|
struct ScheduleEntry {
|
||||||
uint8_t hour;
|
uint8_t hour;
|
||||||
@ -84,9 +83,7 @@ class CircadianRhythm : public InputSource {
|
|||||||
minute = 0;
|
minute = 0;
|
||||||
}
|
}
|
||||||
Log.notice("Current time: %d:%d", hour, minute);
|
Log.notice("Current time: %d:%d", hour, minute);
|
||||||
auto brightness = brightnessForTime(hour, minute);
|
return InputEvent{InputEvent::SetBrightness, brightnessForTime(hour, minute)};
|
||||||
Log.notice("Adjusting brightness to %d", brightness);
|
|
||||||
return InputEvent{InputEvent::SetBrightness, brightness};
|
|
||||||
}
|
}
|
||||||
return InputEvent{};
|
return InputEvent{};
|
||||||
}
|
}
|
||||||
|
@ -1,171 +1,33 @@
|
|||||||
#include "Serial.h"
|
#include "Serial.h"
|
||||||
#include "../Static.h"
|
|
||||||
#include <LittleFS.h>
|
|
||||||
#include "../Config.h"
|
|
||||||
#include "../Sequencer.h"
|
|
||||||
|
|
||||||
SerialInput::SerialInput() : InputSource("Serial"),
|
|
||||||
m_state(ParseState::Normal),
|
|
||||||
m_logPrinter(this)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SerialInput::redrawPrompt()
|
|
||||||
{
|
|
||||||
if (m_canRedraw) {
|
|
||||||
Serial.print((char)8);
|
|
||||||
Serial.print((char)27);
|
|
||||||
Serial.print("[2K");
|
|
||||||
Serial.print((char)8);
|
|
||||||
Serial.print((char)27);
|
|
||||||
Serial.print("[G");
|
|
||||||
Serial.print('\r');
|
|
||||||
Serial.print("> ");
|
|
||||||
Serial.print(m_buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InputEvent
|
InputEvent
|
||||||
SerialInput::parseNormal(char nextChar)
|
Serial::read()
|
||||||
{
|
|
||||||
if (nextChar == 27) {
|
|
||||||
m_state = ParseState::EscapeSequence;
|
|
||||||
return InputEvent::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextChar == 13) {
|
|
||||||
redrawPrompt();
|
|
||||||
Serial.println();
|
|
||||||
if (m_buf.length() > 0) {
|
|
||||||
m_canRedraw = false;
|
|
||||||
doCommand();
|
|
||||||
m_canRedraw = true;
|
|
||||||
m_history.insert(m_buf);
|
|
||||||
m_buf = "";
|
|
||||||
}
|
|
||||||
m_historyOffset = 0;
|
|
||||||
redrawPrompt();
|
|
||||||
return InputEvent{};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextChar == 8) {
|
|
||||||
if (m_buf.length() > 0) {
|
|
||||||
m_buf.remove(m_buf.length() - 1, 1);
|
|
||||||
}
|
|
||||||
Serial.print((char)8);
|
|
||||||
Serial.print((char)27);
|
|
||||||
Serial.print("[K");
|
|
||||||
redrawPrompt();
|
|
||||||
return InputEvent::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextChar >= 32 && nextChar <= 126) {
|
|
||||||
m_buf += nextChar;
|
|
||||||
Serial.print(nextChar);
|
|
||||||
}
|
|
||||||
return InputEvent::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputEvent
|
|
||||||
SerialInput::parseEscape(char nextChar)
|
|
||||||
{
|
|
||||||
if (nextChar == '[') {
|
|
||||||
m_state = ParseState::CSI;
|
|
||||||
} else {
|
|
||||||
m_state = ParseState::Normal;
|
|
||||||
}
|
|
||||||
return InputEvent::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputEvent
|
|
||||||
SerialInput::parseCSI(char nextChar)
|
|
||||||
{
|
|
||||||
if (nextChar == 'A') {
|
|
||||||
if (m_historyOffset < m_history.size()) {
|
|
||||||
m_historyOffset += 1;
|
|
||||||
m_buf = m_history.peek(m_historyOffset);
|
|
||||||
redrawPrompt();
|
|
||||||
} else {
|
|
||||||
Serial.print((char)7);
|
|
||||||
}
|
|
||||||
} else if (nextChar == 'B') {
|
|
||||||
if (m_historyOffset > 0) {
|
|
||||||
m_historyOffset -= 1;
|
|
||||||
m_buf = m_history.peek(m_historyOffset);
|
|
||||||
redrawPrompt();
|
|
||||||
} else {
|
|
||||||
Serial.print((char)7);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Serial.print((char)7);
|
|
||||||
}
|
|
||||||
m_state = ParseState::Normal;
|
|
||||||
return InputEvent::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputEvent
|
|
||||||
SerialInput::read()
|
|
||||||
{
|
{
|
||||||
while (Serial.available() > 0) {
|
while (Serial.available() > 0) {
|
||||||
char nextChar = Serial.read();
|
char nextChar = Serial.read();
|
||||||
InputEvent ret = InputEvent::None;
|
if (nextChar == '\n') {
|
||||||
switch (m_state) {
|
doCommand();
|
||||||
case ParseState::Normal:
|
m_buf = "";
|
||||||
ret = parseNormal(nextChar);break;
|
} else {
|
||||||
case ParseState::EscapeSequence:
|
m_buf += nextChar;
|
||||||
ret = parseEscape(nextChar);break;
|
|
||||||
case ParseState::CSI:
|
|
||||||
ret = parseCSI(nextChar);break;
|
|
||||||
}
|
|
||||||
if (ret != InputEvent::None) {
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return InputEvent::None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doHelp(Args& args, Print& out)
|
Serial::doCommand() {
|
||||||
{
|
if (command == "tasks") {
|
||||||
out.println("Available commands:");
|
Serial.println("Tasks:");
|
||||||
auto sched = MainLoop::instance()->scheduler;
|
auto sched = MainLoop::instance()->scheduler;
|
||||||
for(auto task : sched.tasks) {
|
for(auto task : sched.tasks) {
|
||||||
for(auto &command : task->commands()) {
|
bool isFigment = task->isFigment();
|
||||||
out.print(command.name);
|
if (isFigment) {
|
||||||
out.print(" ");
|
Serial.println("F " + task->name);
|
||||||
}
|
} else {
|
||||||
}
|
Serial.println("T " + task->name);
|
||||||
out.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Command> serialCommands = {
|
|
||||||
{"help", doHelp}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
|
||||||
SerialInput::commands() const
|
|
||||||
{
|
|
||||||
return serialCommands;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SerialInput::doCommand() {
|
|
||||||
auto sched = MainLoop::instance()->scheduler;
|
|
||||||
Args args = Args(&m_buf);
|
|
||||||
const auto cmdName = args[0];
|
|
||||||
|
|
||||||
for(auto task : sched.tasks) {
|
|
||||||
for(auto &command : task->commands()) {
|
|
||||||
if (cmdName == command.name) {
|
|
||||||
command.func(args, m_logPrinter);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_logPrinter.println("Unknown command");
|
|
||||||
doHelp(args, m_logPrinter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC_ALLOC(SerialInput);
|
STATIC_ALLOC(SerialInput);
|
||||||
|
@ -3,60 +3,14 @@
|
|||||||
|
|
||||||
class SerialInput: public InputSource {
|
class SerialInput: public InputSource {
|
||||||
public:
|
public:
|
||||||
SerialInput();
|
void onStart() override {
|
||||||
InputEvent read() override;
|
//Serial.begin();
|
||||||
|
|
||||||
class LogPrinter : public Print {
|
|
||||||
private:
|
|
||||||
SerialInput* serial;
|
|
||||||
Ringbuf<char, 512> buf;
|
|
||||||
public:
|
|
||||||
LogPrinter(SerialInput* serial) : serial(serial) {};
|
|
||||||
size_t write(uint8_t byte) {
|
|
||||||
if (byte == '\n') {
|
|
||||||
char c;
|
|
||||||
Serial.print('\r');
|
|
||||||
while (buf.take(c)) {
|
|
||||||
Serial.write(c);
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
serial->redrawPrompt();
|
|
||||||
} else {
|
|
||||||
buf.insert(byte);
|
|
||||||
}
|
|
||||||
return sizeof(byte);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void redrawPrompt();
|
|
||||||
|
|
||||||
Print* logPrinter() {
|
|
||||||
return &m_logPrinter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//static SerialInput::Command *s_root;
|
InputEvent read();
|
||||||
LogPrinter* printer() {
|
|
||||||
return &m_logPrinter;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Command> &commands() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum ParseState {
|
|
||||||
Normal,
|
|
||||||
EscapeSequence,
|
|
||||||
CSI
|
|
||||||
};
|
|
||||||
String m_buf;
|
String m_buf;
|
||||||
ParseState m_state;
|
|
||||||
char m_escapeSeq[3];
|
|
||||||
void doCommand();
|
void doCommand();
|
||||||
LogPrinter m_logPrinter;
|
|
||||||
bool m_canRedraw = true;
|
|
||||||
Ringbuf<String, 5> m_history;
|
|
||||||
int m_historyOffset = 0;
|
|
||||||
|
|
||||||
InputEvent parseNormal(char nextChar);
|
}
|
||||||
InputEvent parseEscape(char nextChar);
|
|
||||||
InputEvent parseCSI(char nextChar);
|
|
||||||
};
|
|
||||||
|
21
src/main.cpp
21
src/main.cpp
@ -87,6 +87,16 @@ void setup() {
|
|||||||
Log.notice(u8"🐞 I am built for %d LEDs on pin %d", HardwareConfig::MAX_LED_NUM, RENDERBUG_LED_PIN);
|
Log.notice(u8"🐞 I am built for %d LEDs on pin %d", HardwareConfig::MAX_LED_NUM, RENDERBUG_LED_PIN);
|
||||||
Log.notice(u8"📡 Platform %s version %s", Platform::name(), Platform::version());
|
Log.notice(u8"📡 Platform %s version %s", Platform::name(), Platform::version());
|
||||||
|
|
||||||
|
if (Platform::bootopts.crashCount > 0) {
|
||||||
|
Log.warning(u8"Previous crash detected!!!! We're on attempt %d", Platform::bootopts.crashCount);
|
||||||
|
char lastTaskBuf[16];
|
||||||
|
strncpy(lastTaskBuf, MainLoop::lastTaskName(), sizeof(lastTaskBuf));
|
||||||
|
lastTaskBuf[15] = 0;
|
||||||
|
Log.error(u8"Crash occurred in task %s", lastTaskBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.trace("Startup reason: %d", Platform::bootopts.resetReason);
|
||||||
|
|
||||||
Log.notice(u8"Setting timezone to +2 (CEST)");
|
Log.notice(u8"Setting timezone to +2 (CEST)");
|
||||||
Platform::setTimezone(+2);
|
Platform::setTimezone(+2);
|
||||||
|
|
||||||
@ -95,17 +105,14 @@ void setup() {
|
|||||||
Platform::setup();
|
Platform::setup();
|
||||||
Platform::bootSplash();
|
Platform::bootSplash();
|
||||||
|
|
||||||
Log.notice(u8"💡 Starting FastLED on %d LEDs...", HardwareConfig::MAX_LED_NUM);
|
Log.notice(u8"💡 Starting FastLED...");
|
||||||
Platform::addLEDs(leds, HardwareConfig::MAX_LED_NUM);
|
Platform::addLEDs(leds, HardwareConfig::MAX_LED_NUM);
|
||||||
|
|
||||||
// Tune in,
|
// Tune in,
|
||||||
if (Platform::bootopts.isSafeMode) {
|
if (Platform::bootopts.isSafeMode) {
|
||||||
Log.warning(u8"⚠️ Starting Figment in safe mode!!!");
|
Log.error(u8"⚠️ Starting Figment in safe mode!!!");
|
||||||
runner = &SafeMode::safeModeApp;
|
runner = &SafeMode::safeModeApp;
|
||||||
for(auto task : runner->scheduler.tasks) {
|
FastLED.showColor(CRGB(5, 0, 0));
|
||||||
task->state = Task::Running;
|
|
||||||
}
|
|
||||||
FastLED.showColor(CRGB(255, 0, 0));
|
|
||||||
FastLED.show();
|
FastLED.show();
|
||||||
} else {
|
} else {
|
||||||
Log.notice(u8"🌌 Starting Figment...");
|
Log.notice(u8"🌌 Starting Figment...");
|
||||||
@ -124,7 +131,7 @@ void setup() {
|
|||||||
Serial.flush();
|
Serial.flush();
|
||||||
runner->start();
|
runner->start();
|
||||||
|
|
||||||
Log.notice(u8"💽 %l bytes of free RAM", Platform::freeRam());
|
Log.notice(u8"💽 %lu bytes of free RAM", Platform::freeRam());
|
||||||
Log.notice(u8"🚀 Setup complete! Ready to rock and roll.");
|
Log.notice(u8"🚀 Setup complete! Ready to rock and roll.");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
@ -118,8 +118,6 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt)
|
|||||||
Log.notice("Connecting to MQTT as %s on %s...", Platform::deviceID(), Device.availabilityTopic.c_str());
|
Log.notice("Connecting to MQTT as %s on %s...", Platform::deviceID(), Device.availabilityTopic.c_str());
|
||||||
if (m_mqtt.connect(Platform::deviceID(), NULL, NULL, Device.availabilityTopic.c_str(), 0, true, "offline")) {
|
if (m_mqtt.connect(Platform::deviceID(), NULL, NULL, Device.availabilityTopic.c_str(), 0, true, "offline")) {
|
||||||
Log.notice("Connected to MQTT");
|
Log.notice("Connected to MQTT");
|
||||||
String logTopic = m_debugTopic + "/log";
|
|
||||||
Log.info("MQTT logs are available at %s", logTopic.c_str());
|
|
||||||
m_needHeartbeat = true;
|
m_needHeartbeat = true;
|
||||||
|
|
||||||
m_json.clear();
|
m_json.clear();
|
||||||
|
Loading…
Reference in New Issue
Block a user