Compare commits
45 Commits
9a3186edbd
...
6582bae0f2
Author | SHA1 | Date | |
---|---|---|---|
|
6582bae0f2 | ||
|
13a3dd5158 | ||
|
389da5b115 | ||
|
83b3af58f7 | ||
|
0d3bcb4267 | ||
|
e43b594637 | ||
|
89e943b767 | ||
|
3f3f9eb801 | ||
|
418e13b797 | ||
|
f224a1755e | ||
|
3dd84cfce1 | ||
|
3e9d4eb08f | ||
|
c4bbeccac0 | ||
|
19f2a4f35c | ||
|
cc9c719e3c | ||
|
7e1b3b9500 | ||
|
0106b09c9b | ||
|
a5d468efde | ||
|
04bdf5323c | ||
|
5bb29cc59c | ||
|
cd6c097b76 | ||
|
07e71ad4c0 | ||
|
9233a9113e | ||
|
949c90f207 | ||
|
3b2951db79 | ||
|
31e4072305 | ||
|
9561b3f4a7 | ||
|
1321693182 | ||
|
0826970374 | ||
|
924673ada3 | ||
|
6df7e938cb | ||
|
bb0f8619cb | ||
|
23993a09cf | ||
|
236795917a | ||
|
6edfb2d8e3 | ||
|
436950eef2 | ||
|
8c4e0e402c | ||
|
ce65e7e7f0 | ||
|
6797889b4c | ||
|
6e138175be | ||
|
214825c1d3 | ||
|
90055a07e2 | ||
|
b7495404b8 | ||
|
e436c9aaa3 | ||
|
c9363ba851 |
10
build-hal.py
Normal file
10
build-hal.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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>"])
|
||||||
|
env.Append(CPPDEFINES=[f"RENDERBUG_HAL=HAL_{board.upper()}"])
|
||||||
|
print(f"- platform/{framework}/{board}/")
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"strides": [
|
"strides": [
|
||||||
{"x": 0, "y": 0, "pixels": 255}
|
{"x": 0, "y": 0, "pixels": 512}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
6
data/maps/djstrip.json
Normal file
6
data/maps/djstrip.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"strides": [
|
||||||
|
{"x": 0, "y": 0, "pixels": 50}
|
||||||
|
]
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"tasks": [
|
"tasks": [
|
||||||
"Power",
|
|
||||||
"Renderer",
|
"Renderer",
|
||||||
"U8Display",
|
"U8Display",
|
||||||
"WiFi",
|
"WiFi",
|
||||||
|
24
data/profiles/djstrip.json
Normal file
24
data/profiles/djstrip.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"tasks": [
|
||||||
|
"Bluetooth",
|
||||||
|
"Renderer",
|
||||||
|
"Serial"
|
||||||
|
],
|
||||||
|
"scenes": {
|
||||||
|
"Rain": ["Rain", "Rainbow"],
|
||||||
|
"Test": ["Test"],
|
||||||
|
"Idle": ["Solid", "Pulse", "Rainbow", "CircadianRhythm"],
|
||||||
|
"Acid": ["Chimes", "Pulse", "IdleColors", "Rainbow"],
|
||||||
|
"Flashlight": ["Flashlight"]
|
||||||
|
},
|
||||||
|
"surfaceMap": "djstrip",
|
||||||
|
"defaults": {
|
||||||
|
"mqtt.ip": "10.0.0.2",
|
||||||
|
"power.volts": 0,
|
||||||
|
"power.milliamps": 0,
|
||||||
|
"power.useBPM": false,
|
||||||
|
"bpm.idle": 45
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,31 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"tasks": [
|
"tasks": [
|
||||||
"Bluetooth",
|
|
||||||
"WiFi",
|
"WiFi",
|
||||||
"Renderer",
|
"Renderer",
|
||||||
"Power",
|
|
||||||
"BPM",
|
|
||||||
"MQTT",
|
"MQTT",
|
||||||
"ArduinoOTA",
|
"ArduinoOTA",
|
||||||
"UpdateStatusAnimation",
|
"UpdateStatusAnimation",
|
||||||
"Serial"
|
"Serial",
|
||||||
|
"Weather",
|
||||||
|
"CircadianRhythm"
|
||||||
],
|
],
|
||||||
"scenes": {
|
"scenes": {
|
||||||
"Rain": ["Rain", "Rainbow"],
|
"Clear": ["Solid", "Rainbow"],
|
||||||
|
"Rain": ["Rain"],
|
||||||
|
"Drizzle": ["Rain"],
|
||||||
|
"Mist": ["Rain"],
|
||||||
|
"Snow": ["Solid"],
|
||||||
|
"UnknownWeather": ["Solid", "IdleColors"],
|
||||||
"Test": ["Test"],
|
"Test": ["Test"],
|
||||||
"Idle": ["Solid", "Pulse", "Rainbow", "CircadianRhythm"],
|
"Idle": ["Solid", "Rainbow"],
|
||||||
"Acid": ["Chimes", "Pulse", "IdleColors", "Rainbow"],
|
"Acid": ["Chimes", "IdleColors", "Rainbow"],
|
||||||
"Flashlight": ["Flashlight"]
|
"Flashlight": ["Flashlight"]
|
||||||
},
|
},
|
||||||
"surfaceMap": "ponder",
|
"surfaceMap": "ponder",
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"mqtt.ip": "10.0.0.2"
|
"mqtt.ip": "10.0.0.2",
|
||||||
|
"power.volts": 0,
|
||||||
|
"power.milliamps": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
default-partitions.csv
Normal file
7
default-partitions.csv
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xe000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x140000,
|
||||||
|
app1, app, ota_1, 0x150000,0x140000,
|
||||||
|
spiffs, data, spiffs, 0x290000,0x160000,
|
||||||
|
coredump, data, coredump,0x3F0000,0x10000,
|
|
@ -1,7 +1,2 @@
|
|||||||
#include "./Command.h"
|
#include "./Command.h"
|
||||||
|
|
||||||
void
|
|
||||||
doNothing(Args& args, Print& printer)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Command::Command() : func(doNothing) {}
|
|
||||||
|
@ -21,13 +21,25 @@ class Args {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CommandList;
|
struct Task;
|
||||||
|
|
||||||
struct Command {
|
struct Command {
|
||||||
using Executor = std::function<void(Args&, Print& output)>;
|
using Executor = void(Task::*)(Args&, Print&);
|
||||||
Executor func;
|
|
||||||
const char* name = NULL;
|
template<typename T>
|
||||||
|
using MemberExecutor = void(T::*)(Args&, Print&);
|
||||||
|
|
||||||
|
const char* name = NULL;
|
||||||
|
Executor func = NULL;
|
||||||
|
|
||||||
|
void invoke(Task* task, Args& args, Print& printer) const {
|
||||||
|
if (func) {
|
||||||
|
(*task.*func)(args, printer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Command();
|
|
||||||
Command(const char* name, Executor func) : name(name), func(func) {}
|
Command(const char* name, Executor func) : name(name), func(func) {}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
Command(const char* name, MemberExecutor<T> func) : name(name), func(static_cast<Executor>(func)) {}
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
#include "./Command.h"
|
#include "./Command.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
|
@ -98,3 +98,55 @@ BufferedInputSource::setEvent(InputEvent::Intent intent, Variant &&v)
|
|||||||
{
|
{
|
||||||
m_eventQueue.insert(InputEvent{intent, std::move(v)});
|
m_eventQueue.insert(InputEvent{intent, std::move(v)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
InputEvent::name() const
|
||||||
|
{
|
||||||
|
switch (intent) {
|
||||||
|
case InputEvent::BeatDetect:
|
||||||
|
return "beat-detection";
|
||||||
|
case InputEvent::Beat:
|
||||||
|
return "beat";
|
||||||
|
case InputEvent::ReadyToRoll:
|
||||||
|
return "ready-to-roll";
|
||||||
|
case InputEvent::PowerToggle:
|
||||||
|
return "power-toggle";
|
||||||
|
case InputEvent::SetPower:
|
||||||
|
return "set-power";
|
||||||
|
case InputEvent::SetPattern:
|
||||||
|
return "set-pattern";
|
||||||
|
case InputEvent::SetScene:
|
||||||
|
return "set-scene";
|
||||||
|
case InputEvent::SetColor:
|
||||||
|
return "set-color";
|
||||||
|
case InputEvent::Acceleration:
|
||||||
|
return "acceleration";
|
||||||
|
case InputEvent::SetBrightness:
|
||||||
|
return "set-brightness";
|
||||||
|
case InputEvent::FirmwareUpdate:
|
||||||
|
return "firmware-update";
|
||||||
|
case InputEvent::NetworkStatus:
|
||||||
|
return "network-status";
|
||||||
|
case InputEvent::NetworkActivity:
|
||||||
|
return "network-activity";
|
||||||
|
case InputEvent::StartThing:
|
||||||
|
return "start-thing";
|
||||||
|
case InputEvent::StopThing:
|
||||||
|
return "stop-thing";
|
||||||
|
case InputEvent::SaveConfigurationRequest:
|
||||||
|
return "save-configuration";
|
||||||
|
case InputEvent::ConfigurationChanged:
|
||||||
|
return "configuration-changed";
|
||||||
|
case InputEvent::IdleStart:
|
||||||
|
return "idle-start";
|
||||||
|
case InputEvent::IdleStop:
|
||||||
|
return "idle-stop";
|
||||||
|
case InputEvent::ButtonPress:
|
||||||
|
return "button";
|
||||||
|
case InputEvent::LoadConfigurationByName:
|
||||||
|
return "load-config";
|
||||||
|
case None:
|
||||||
|
return "none";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
@ -55,9 +55,10 @@ struct InputEvent: public Variant {
|
|||||||
// An empty non-event
|
// An empty non-event
|
||||||
None,
|
None,
|
||||||
|
|
||||||
// An input from the user, for other tasks to translate into canonical
|
// System activity
|
||||||
// types. Makes for easy button re-mapping on the fly.
|
ReadyToRoll,
|
||||||
UserInput,
|
IdleStart,
|
||||||
|
IdleStop,
|
||||||
|
|
||||||
//
|
//
|
||||||
// The canonical types
|
// The canonical types
|
||||||
@ -65,6 +66,8 @@ struct InputEvent: public Variant {
|
|||||||
// Hardware inputs
|
// Hardware inputs
|
||||||
ButtonPress,
|
ButtonPress,
|
||||||
Acceleration,
|
Acceleration,
|
||||||
|
|
||||||
|
// Network management
|
||||||
NetworkStatus,
|
NetworkStatus,
|
||||||
NetworkActivity,
|
NetworkActivity,
|
||||||
|
|
||||||
@ -74,15 +77,10 @@ struct InputEvent: public Variant {
|
|||||||
SetBrightness,
|
SetBrightness,
|
||||||
|
|
||||||
// Animation sequencing
|
// Animation sequencing
|
||||||
PreviousPattern,
|
|
||||||
NextPattern,
|
|
||||||
SetPattern,
|
SetPattern,
|
||||||
PreviousScene,
|
|
||||||
NextScene,
|
|
||||||
SetScene,
|
SetScene,
|
||||||
|
|
||||||
// Timekeeping
|
// Timekeeping
|
||||||
ScheduleChange,
|
|
||||||
Beat,
|
Beat,
|
||||||
BeatDetect,
|
BeatDetect,
|
||||||
|
|
||||||
@ -91,17 +89,13 @@ struct InputEvent: public Variant {
|
|||||||
StopThing,
|
StopThing,
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
SetDisplayOffset,
|
|
||||||
SetDisplayLength,
|
|
||||||
LoadConfigurationByName,
|
LoadConfigurationByName,
|
||||||
SetColor,
|
|
||||||
SaveConfigurationRequest,
|
SaveConfigurationRequest,
|
||||||
ConfigurationChanged,
|
ConfigurationChanged,
|
||||||
|
SetColor,
|
||||||
|
|
||||||
// Firmware events
|
// Firmware events
|
||||||
FirmwareUpdate,
|
FirmwareUpdate,
|
||||||
|
|
||||||
ReadyToRoll,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
@ -118,6 +112,8 @@ struct InputEvent: public Variant {
|
|||||||
return intent != otherIntent;
|
return intent != otherIntent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* name() const;
|
||||||
|
|
||||||
Intent intent;
|
Intent intent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
@ -104,13 +104,14 @@ MainLoop::start()
|
|||||||
{
|
{
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
Log.notice("Welcome to 🌕 Figment 0.3.0");
|
Log.notice("Welcome to 🌕 Figment 0.3.0");
|
||||||
Log.notice("*** Starting %d tasks...", scheduler.tasks.size());
|
Log.notice("*** Scheduling %d tasks...", scheduler.tasks.size());
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
for(auto task: scheduler) {
|
for(auto task: scheduler) {
|
||||||
Log.notice("** Starting %s", task->name);
|
Log.notice("** Starting %s", task->name);
|
||||||
task->start();
|
task->start();
|
||||||
}
|
}
|
||||||
loop();
|
loop();
|
||||||
|
Log.notice("*** Scheduler started.");
|
||||||
dispatch(InputEvent::ReadyToRoll);
|
dispatch(InputEvent::ReadyToRoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ struct Scheduler {
|
|||||||
|
|
||||||
struct iterator: public std::iterator<std::input_iterator_tag, Task*> {
|
struct iterator: public std::iterator<std::input_iterator_tag, Task*> {
|
||||||
Scheduler& queue;
|
Scheduler& queue;
|
||||||
int idx = 0;
|
size_t idx = 0;
|
||||||
explicit iterator(Scheduler& queue) : queue(queue), idx(nextEnabled(0)) {}
|
explicit iterator(Scheduler& queue) : queue(queue), idx(nextEnabled(0)) {}
|
||||||
iterator(Scheduler& queue, int start) : queue(queue), idx(nextEnabled(start)) {}
|
iterator(Scheduler& queue, int start) : queue(queue), idx(nextEnabled(start)) {}
|
||||||
iterator& operator++() {
|
iterator& operator++() {
|
||||||
@ -33,7 +33,7 @@ struct Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nextEnabled(int start) const {
|
int nextEnabled(int start) const {
|
||||||
for(int pos = start; pos < queue.tasks.size();pos++) {
|
for(size_t pos = start; pos < queue.tasks.size();pos++) {
|
||||||
if (queue.tasks[pos]->state == Task::Running) {
|
if (queue.tasks[pos]->state == Task::Running) {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ArduinoLog.h>
|
|
||||||
|
|
||||||
struct PerfCounter {
|
|
||||||
PerfCounter(const char* name) {}
|
|
||||||
~PerfCounter() {}
|
|
||||||
/*PerfCounter(const char* name) : start(millis()), name(name) {}
|
|
||||||
~PerfCounter() {Log.notice("%s: %d", name, millis() - start);}*/
|
|
||||||
uint16_t start;
|
|
||||||
const char* name;
|
|
||||||
};
|
|
@ -1,5 +1,6 @@
|
|||||||
#include "./Renderer.h"
|
#include "./Renderer.h"
|
||||||
#include "./Display.h"
|
#include "./Display.h"
|
||||||
|
#include "./MainLoop.h"
|
||||||
|
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
|
|
||||||
@ -18,7 +19,9 @@ Renderer::lastFigmentName()
|
|||||||
void
|
void
|
||||||
Renderer::loop()
|
Renderer::loop()
|
||||||
{
|
{
|
||||||
|
uint16_t totalPower = 0;
|
||||||
for(Display* dpy : m_displays) {
|
for(Display* dpy : m_displays) {
|
||||||
|
totalPower += calculate_unscaled_power_mW(dpy->pixelBacking(), dpy->pixelCount());
|
||||||
for(Figment* figment : m_figments) {
|
for(Figment* figment : m_figments) {
|
||||||
if (figment->state == Task::Running) {
|
if (figment->state == Task::Running) {
|
||||||
#if defined(BOARD_ESP32) or defined(BOARD_ESP8266)
|
#if defined(BOARD_ESP32) or defined(BOARD_ESP8266)
|
||||||
@ -38,10 +41,52 @@ Renderer::loop()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
FastLED.show();
|
static uint8_t videoBrightness = 255;
|
||||||
|
static uint8_t scaledBrightness = powerScale(videoBrightness, totalPower);
|
||||||
|
EVERY_N_MILLISECONDS(30) {
|
||||||
|
m_powerState.update();
|
||||||
|
m_brightness.update();
|
||||||
|
videoBrightness = brighten8_video(min((uint8_t)m_brightness, (uint8_t)m_powerState));
|
||||||
|
scaledBrightness = powerScale(videoBrightness, totalPower);
|
||||||
|
}
|
||||||
|
|
||||||
|
FastLED.show(scaledBrightness);
|
||||||
FastLED.countFPS();
|
FastLED.countFPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Renderer::handleEvent(const InputEvent& evt)
|
||||||
|
{
|
||||||
|
switch (evt.intent) {
|
||||||
|
case InputEvent::PowerToggle:
|
||||||
|
m_powerState = m_powerState.value() <= 128 ? 255 : 0;
|
||||||
|
Log.notice("Power toggled to %t", m_powerState);
|
||||||
|
break;
|
||||||
|
case InputEvent::SetPower:
|
||||||
|
m_powerState = evt.asInt() == 0 ? 0 : 255;
|
||||||
|
Log.notice("Power state is now %t", m_powerState);
|
||||||
|
break;
|
||||||
|
case InputEvent::SetBrightness:
|
||||||
|
m_brightness = evt.asInt();
|
||||||
|
Log.notice("Brightness is now %d (%d requested)", (uint8_t)m_brightness, evt.asInt());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
Renderer::powerScale(uint8_t target, uint32_t totalPower) const
|
||||||
|
{
|
||||||
|
if (m_powerManaged) {
|
||||||
|
const uint32_t maxPower = m_voltage * m_milliamps;
|
||||||
|
uint32_t requested = ((uint32_t)totalPower * target) / 256;
|
||||||
|
if (requested > maxPower) {
|
||||||
|
return (uint32_t)((uint8_t)(target) * (uint32_t)(maxPower)) / ((uint32_t)(requested));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Renderer::onStart()
|
Renderer::onStart()
|
||||||
{
|
{
|
||||||
@ -50,3 +95,33 @@ Renderer::onStart()
|
|||||||
}
|
}
|
||||||
FastLED.show();
|
FastLED.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Renderer::doOn(Args& args, Print& print)
|
||||||
|
{
|
||||||
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPower, 255});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Renderer::doOff(Args& args, Print& print)
|
||||||
|
{
|
||||||
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPower, 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Renderer::doBrightness(Args& args, Print& print)
|
||||||
|
{
|
||||||
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetBrightness, atoi(args[1].c_str())});
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Command>&
|
||||||
|
Renderer::commands() const
|
||||||
|
{
|
||||||
|
static const std::vector<Command> _commands = {
|
||||||
|
Command{"brightness", &Renderer::doBrightness},
|
||||||
|
Command{"on", &Renderer::doOn},
|
||||||
|
Command{"off", &Renderer::doOff}
|
||||||
|
};
|
||||||
|
|
||||||
|
return _commands;
|
||||||
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "./Figment.h"
|
#include "./Figment.h"
|
||||||
|
#include "./Animation.h"
|
||||||
|
#include "./Input.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class Display;
|
class Display;
|
||||||
@ -9,10 +11,26 @@ public:
|
|||||||
|
|
||||||
void loop() override;
|
void loop() override;
|
||||||
void onStart() override;
|
void onStart() override;
|
||||||
|
void handleEvent(const InputEvent& evt) override;
|
||||||
|
|
||||||
static const char* lastFigmentName();
|
static const char* lastFigmentName();
|
||||||
|
|
||||||
|
const std::vector<Command>& commands() const override;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
AnimatedNumber m_powerState = 255;
|
||||||
|
AnimatedNumber m_brightness = 255;
|
||||||
|
bool m_powerManaged = true;
|
||||||
|
|
||||||
|
uint16_t m_voltage = 5;
|
||||||
|
uint16_t m_milliamps = 500;
|
||||||
|
|
||||||
|
uint8_t powerScale(uint8_t target, uint32_t totalPower) const;
|
||||||
|
|
||||||
|
void doBrightness(Args& args, Print& print);
|
||||||
|
void doOn(Args& args, Print& print);
|
||||||
|
void doOff(Args& args, Print& print);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "./Surface.h"
|
#include "./Surface.h"
|
||||||
#include "./Display.h"
|
#include "./Display.h"
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
#include "Perfcounter.h"
|
|
||||||
|
|
||||||
Surface::Surface(Display* dpy, const VirtualCoordinates& start, const VirtualCoordinates& end)
|
Surface::Surface(Display* dpy, const VirtualCoordinates& start, const VirtualCoordinates& end)
|
||||||
: start(dpy->coordinateMapping()->virtualToPhysicalCoords(start)),
|
: start(dpy->coordinateMapping()->virtualToPhysicalCoords(start)),
|
||||||
@ -53,7 +52,6 @@ Surface::paintWith(std::function<void(CRGB&)> func)
|
|||||||
void
|
void
|
||||||
Surface::paintShader(Surface::Shader shader)
|
Surface::paintShader(Surface::Shader shader)
|
||||||
{
|
{
|
||||||
PerfCounter _("paintShader");
|
|
||||||
uint8_t startX = min(start.x, end.x);
|
uint8_t startX = min(start.x, end.x);
|
||||||
uint8_t startY = min(start.y, end.y);
|
uint8_t startY = min(start.y, end.y);
|
||||||
uint8_t endX = max(start.x, end.x);
|
uint8_t endX = max(start.x, end.x);
|
||||||
|
202
platformio.ini
202
platformio.ini
@ -8,110 +8,44 @@
|
|||||||
; 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
|
||||||
|
|
||||||
[common_env_data]
|
[env]
|
||||||
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
|
extra_scripts = pre:verify-configs.py, pre:build-hal.py
|
||||||
|
check_flags =
|
||||||
|
cppcheck: --inline-suppr --suppress=*:*/.pio/*
|
||||||
|
board_build.filesystem = littlefs
|
||||||
|
upload_speed = 115200
|
||||||
|
monitor_speed = 115200
|
||||||
|
build_type = debug
|
||||||
|
build_flags =
|
||||||
|
-DFASTLED_ALL_PINS_HARDWARE_SPI
|
||||||
src_build_flags =
|
src_build_flags =
|
||||||
|
-DFASTLED_ALL_PINS_HARDWARE_SPI
|
||||||
-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 =
|
||||||
fastled/FastLED@^3.5.0
|
fastled/FastLED@^3.6.0
|
||||||
thijse/ArduinoLog@^1.1.0
|
thijse/ArduinoLog@^1.1.0
|
||||||
bblanchon/ArduinoJson@^6.17.3
|
bblanchon/ArduinoJson@^6.21.4
|
||||||
|
JsonStreamingParser
|
||||||
LittleFS
|
LittleFS
|
||||||
|
|
||||||
[config_u8display]
|
|
||||||
src_build_flags =
|
|
||||||
-DCONFIG_U8DISPLAY
|
|
||||||
lib_deps =
|
|
||||||
olikraus/U8g2@^2.34.15
|
|
||||||
src_filter = "+<platform/arduino/U8Display.cpp>"
|
|
||||||
|
|
||||||
[config_mqtt]
|
|
||||||
src_build_flags =
|
|
||||||
-DCONFIG_MQTT
|
|
||||||
lib_deps =
|
|
||||||
knolleary/PubSubClient@^2.8.0
|
knolleary/PubSubClient@^2.8.0
|
||||||
src_filter = "+<platform/arduino/MQTTTelemetry.cpp>"
|
bblanchon/StreamUtils@^1.8.0
|
||||||
|
|
||||||
[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]
|
|
||||||
src_build_flags =
|
|
||||||
-DCONFIG_OTA
|
|
||||||
src_filter = "+<platform/arduino/OTA.cpp>"
|
|
||||||
lib_deps =
|
|
||||||
ArduinoOTA
|
|
||||||
ESP8266mDNS
|
|
||||||
|
|
||||||
[config_nocolor]
|
|
||||||
src_build_flags =
|
|
||||||
-DCONFIG_NO_COLORDATA
|
|
||||||
|
|
||||||
[config_buttons]
|
|
||||||
src_build_flags =
|
|
||||||
-DCONFIG_BUTTONS
|
|
||||||
src_filter = "+<inputs/Buttons.cpp>"
|
|
||||||
|
|
||||||
[config_mpu5060]
|
|
||||||
src_build_flags =
|
|
||||||
-DCONFIG_MPU5060
|
|
||||||
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
|
|
||||||
extra_scripts = verify-configs.py
|
|
||||||
board_build.filesystem = littlefs
|
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
board = featheresp32
|
board = featheresp32
|
||||||
framework = arduino
|
framework = arduino
|
||||||
check_flags =
|
board_build.partitions = default-partitions.csv
|
||||||
cppcheck: --inline-suppr --suppress=*:*/.pio/*
|
|
||||||
src_build_flags =
|
src_build_flags =
|
||||||
${common_env_data.src_build_flags}
|
${env.src_build_flags}
|
||||||
${config_nocolor.src_build_flags}
|
|
||||||
-DPLATFORM_ARDUINO
|
|
||||||
-DBOARD_ESP32
|
|
||||||
-DCONFIG_THREADED_INPUTS
|
-DCONFIG_THREADED_INPUTS
|
||||||
lib_deps =
|
|
||||||
${common_env_data.lib_deps_external}
|
|
||||||
src_filter = "${common_env_data.src_filter}"
|
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
monitor_speed = 115200
|
|
||||||
upload_speed = 115200
|
|
||||||
|
|
||||||
[env:esp8266-12f]
|
[env:esp8266-12f]
|
||||||
extends = env:esp8266
|
extends = env:esp8266
|
||||||
@ -121,104 +55,24 @@ board = esp12e
|
|||||||
platform = atmelavr
|
platform = atmelavr
|
||||||
board = uno
|
board = uno
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
|
||||||
${common_env_data.lib_deps_external}
|
|
||||||
|
|
||||||
[env:esp8266]
|
[env:esp8266]
|
||||||
check_flags =
|
|
||||||
cppcheck: --inline-suppr --suppress=*:*/.pio/*
|
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = huzzah
|
board = huzzah
|
||||||
framework = arduino
|
framework = arduino
|
||||||
board_build.filesystem = littlefs
|
monitor_filters = esp8266_exception_decoder
|
||||||
src_build_flags =
|
|
||||||
${common_env_data.src_build_flags}
|
|
||||||
-DPLATFORM_ARDUINO
|
|
||||||
-DBOARD_ESP8266
|
|
||||||
-DCORE_DEBUG_LEVEL=5
|
|
||||||
-fstack-protector
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common_env_data.lib_deps_external}
|
${env.lib_deps}
|
||||||
arduino-libraries/NTPClient@^3.1.0
|
arduino-libraries/NTPClient@^3.1.0
|
||||||
src_filter = "${common_env_data.src_filter}"
|
ESP8266WiFi
|
||||||
|
ESP8266mDNS
|
||||||
[env:esp32_bluetooth]
|
ArduinoOTA
|
||||||
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
|
||||||
src_filter = "${env:esp32.src_filter} ${config_u8display.src_filter}"
|
|
||||||
build_type = debug
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env:esp32.lib_deps}
|
${env:esp32.lib_deps}
|
||||||
${config_u8display.lib_deps}
|
olikraus/U8g2@^2.34.15
|
||||||
src_build_flags =
|
src_build_flags =
|
||||||
${env:esp32.src_build_flags}
|
${env:esp32.src_build_flags}
|
||||||
${config_u8display.src_build_flags}
|
-DCONFIG_U8DISPLAY
|
||||||
-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
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
@ -261,19 +256,18 @@ ConfigService::handleEvent(const InputEvent &evt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doMapList(Args& args, Print& out)
|
ConfigService::doMapList(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
static const auto conf = Static<ConfigService>::instance();
|
|
||||||
out.println("Available maps:");
|
out.println("Available maps:");
|
||||||
LittleFS.begin();
|
LittleFS.begin();
|
||||||
for(auto it = conf->mapsBegin();it != conf->mapsEnd(); it++) {
|
for(auto it = mapsBegin();it != mapsEnd(); it++) {
|
||||||
out.println(*it);
|
out.println(*it);
|
||||||
}
|
}
|
||||||
LittleFS.end();
|
LittleFS.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doSave(Args& args, Print& print)
|
ConfigService::doSave(Args& args, Print& print)
|
||||||
{
|
{
|
||||||
MainLoop::instance()->dispatch(InputEvent::SaveConfigurationRequest);
|
MainLoop::instance()->dispatch(InputEvent::SaveConfigurationRequest);
|
||||||
}
|
}
|
||||||
@ -281,17 +275,17 @@ doSave(Args& args, Print& print)
|
|||||||
static String s;
|
static String s;
|
||||||
|
|
||||||
void
|
void
|
||||||
doSetProfile(Args& args, Print& out)
|
ConfigService::doSetProfile(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
s = args[1];
|
s = args[1];
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::LoadConfigurationByName, s.c_str()});
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::LoadConfigurationByName, s.c_str()});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doCoordMap(Args& args, Print& out)
|
ConfigService::doCoordMap(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
VirtualCoordinates coords{atoi(args[1].c_str()), atoi(args[2].c_str())};
|
VirtualCoordinates coords{atoi(args[1].c_str()), atoi(args[2].c_str())};
|
||||||
auto map = Static<ConfigService>::instance()->coordMap();
|
auto map = coordMap();
|
||||||
auto pPos = map->virtualToPhysicalCoords(coords);
|
auto pPos = map->virtualToPhysicalCoords(coords);
|
||||||
auto idx = map->physicalCoordsToIndex(pPos);
|
auto idx = map->physicalCoordsToIndex(pPos);
|
||||||
char buf[32];
|
char buf[32];
|
||||||
@ -303,10 +297,10 @@ const std::vector<Command>&
|
|||||||
ConfigService::commands() const
|
ConfigService::commands() const
|
||||||
{
|
{
|
||||||
static const std::vector<Command> _commands = {
|
static const std::vector<Command> _commands = {
|
||||||
{"save", doSave},
|
{"save", &ConfigService::doSave},
|
||||||
{"profile", doSetProfile},
|
{"profile", &ConfigService::doSetProfile},
|
||||||
{"maps", doMapList},
|
{"maps", &ConfigService::doMapList},
|
||||||
{"coordmap", doCoordMap}
|
{"coordmap", &ConfigService::doCoordMap}
|
||||||
};
|
};
|
||||||
return _commands;
|
return _commands;
|
||||||
}
|
}
|
||||||
|
54
src/Config.h
54
src/Config.h
@ -2,7 +2,7 @@
|
|||||||
#include <Figments.h>
|
#include <Figments.h>
|
||||||
#include "JsonCoordinateMapping.h"
|
#include "JsonCoordinateMapping.h"
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <LittleFS.h>
|
#include "FsUtils.h"
|
||||||
|
|
||||||
class Configuration {
|
class Configuration {
|
||||||
public:
|
public:
|
||||||
@ -59,55 +59,8 @@ struct ConfigService: public Task {
|
|||||||
const CoordinateMapping* coordMap() const { return &m_jsonMap; }
|
const CoordinateMapping* coordMap() const { return &m_jsonMap; }
|
||||||
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 std::vector<Command>& commands() const override;
|
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 mapsBegin() const { return filename_iterator("/maps/", ".json"); }
|
||||||
filename_iterator mapsEnd() const { return filename_iterator(); }
|
filename_iterator mapsEnd() const { return filename_iterator(); }
|
||||||
|
|
||||||
@ -121,4 +74,9 @@ private:
|
|||||||
|
|
||||||
bool loadProfile(const char* name);
|
bool loadProfile(const char* name);
|
||||||
bool loadMap(const String& mapName);
|
bool loadMap(const String& mapName);
|
||||||
|
|
||||||
|
void doSave(Args& args, Print& print);
|
||||||
|
void doSetProfile(Args& args, Print& print);
|
||||||
|
void doCoordMap(Args& args, Print& print);
|
||||||
|
void doMapList(Args& args, Print& print);
|
||||||
};
|
};
|
||||||
|
57
src/FsUtils.cpp
Normal file
57
src/FsUtils.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "FsUtils.h"
|
||||||
|
|
||||||
|
filename_iterator::filename_iterator()
|
||||||
|
: suffix(NULL),
|
||||||
|
valid(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
filename_iterator::filename_iterator(const char* path, const char* suffix)
|
||||||
|
#ifdef ESP8266
|
||||||
|
: dir(LittleFS.openDir(path)),
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
: dir(LittleFS.open(path)),
|
||||||
|
#endif
|
||||||
|
valid(true),
|
||||||
|
suffix(suffix)
|
||||||
|
{
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
filename_iterator::next()
|
||||||
|
{
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int extPos = -1;
|
||||||
|
do {
|
||||||
|
#ifdef ESP8266
|
||||||
|
valid = dir.next();
|
||||||
|
if (valid) {
|
||||||
|
String fname = dir.fileName();
|
||||||
|
extPos = fname.lastIndexOf(suffix);
|
||||||
|
if (extPos != -1) {
|
||||||
|
ret = fname.substring(0, extPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
File next = dir.openNextFile();
|
||||||
|
valid = (bool)next;
|
||||||
|
if (valid && !next.isDirectory()) {
|
||||||
|
String fname = next.name();
|
||||||
|
extPos = fname.lastIndexOf(suffix);
|
||||||
|
if (extPos != -1) {
|
||||||
|
ret = fname.substring(0, extPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} while (valid && extPos == -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
filename_iterator& filename_iterator::operator++()
|
||||||
|
{
|
||||||
|
next();
|
||||||
|
return *this;
|
||||||
|
}
|
33
src/FsUtils.h
Normal file
33
src/FsUtils.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
struct filename_iterator: public std::iterator<std::input_iterator_tag, const char*> {
|
||||||
|
public:
|
||||||
|
filename_iterator();
|
||||||
|
filename_iterator(const char* path, const char* suffix);
|
||||||
|
void next();
|
||||||
|
filename_iterator& operator++();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
String ret;
|
||||||
|
bool valid;
|
||||||
|
const char* suffix;
|
||||||
|
|
||||||
|
#ifdef ESP8266
|
||||||
|
Dir dir;
|
||||||
|
#endif
|
||||||
|
#ifdef ESP32
|
||||||
|
File dir;
|
||||||
|
#endif
|
||||||
|
};
|
30
src/Hal.h
Normal file
30
src/Hal.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct BootOptions;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HAL_UNKNOWN,
|
||||||
|
HAL_ESP32,
|
||||||
|
HAL_ESP8266
|
||||||
|
} HalBackend;
|
||||||
|
|
||||||
|
constexpr HalBackend DefaultBackend = RENDERBUG_HAL;
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
@ -56,7 +56,7 @@ JsonCoordinateMapping::load(const JsonArray& strideList)
|
|||||||
int x = strideObj["x"];
|
int x = strideObj["x"];
|
||||||
int y = strideObj["y"];
|
int y = strideObj["y"];
|
||||||
displayMap[i] = Span{length, x, y};
|
displayMap[i] = Span{length, x, y};
|
||||||
Log.verbose("config: Found stride (%d, %d): %d", x, y, length);
|
Log.info("config: Found stride (%d, %d): %d", x, y, length);
|
||||||
maxStrideSize = length > maxStrideSize ? length : maxStrideSize;
|
maxStrideSize = length > maxStrideSize ? length : maxStrideSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,57 +4,6 @@
|
|||||||
|
|
||||||
static const char* eventValue(const InputEvent& evt);
|
static const char* eventValue(const InputEvent& evt);
|
||||||
|
|
||||||
const char*
|
|
||||||
LogService::intentName(InputEvent::Intent intent)
|
|
||||||
{
|
|
||||||
switch(intent) {
|
|
||||||
case InputEvent::BeatDetect:
|
|
||||||
return "beat-detection";
|
|
||||||
case InputEvent::Beat:
|
|
||||||
return "beat";
|
|
||||||
case InputEvent::ReadyToRoll:
|
|
||||||
return "ready-to-roll";
|
|
||||||
case InputEvent::PowerToggle:
|
|
||||||
return "power-toggle";
|
|
||||||
case InputEvent::SetPower:
|
|
||||||
return "set-power";
|
|
||||||
case InputEvent::PreviousPattern:
|
|
||||||
return "previous-pattern";
|
|
||||||
case InputEvent::NextPattern:
|
|
||||||
return "next-pattern";
|
|
||||||
case InputEvent::SetPattern:
|
|
||||||
return "set-pattern";
|
|
||||||
case InputEvent::SetColor:
|
|
||||||
return "set-color";
|
|
||||||
case InputEvent::Acceleration:
|
|
||||||
return "acceleration";
|
|
||||||
case InputEvent::UserInput:
|
|
||||||
return "user";
|
|
||||||
case InputEvent::SetBrightness:
|
|
||||||
return "set-brightness";
|
|
||||||
case InputEvent::FirmwareUpdate:
|
|
||||||
return "firmware-update";
|
|
||||||
case InputEvent::NetworkStatus:
|
|
||||||
return "network-status";
|
|
||||||
case InputEvent::NetworkActivity:
|
|
||||||
return "network-activity";
|
|
||||||
case InputEvent::StartThing:
|
|
||||||
return "start-thing";
|
|
||||||
case InputEvent::StopThing:
|
|
||||||
return "stop-thing";
|
|
||||||
case InputEvent::SetDisplayOffset:
|
|
||||||
return "set-display-offset";
|
|
||||||
case InputEvent::SetDisplayLength:
|
|
||||||
return "set-display-length";
|
|
||||||
case InputEvent::SaveConfigurationRequest:
|
|
||||||
return "save-configuration";
|
|
||||||
case InputEvent::ConfigurationChanged:
|
|
||||||
return "configuration-changed";
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char LogService::s_valueBuf[255];
|
char LogService::s_valueBuf[255];
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
@ -84,7 +33,7 @@ LogService::handleEvent(const InputEvent& evt) {
|
|||||||
if (m_duplicateEvents > 0) {
|
if (m_duplicateEvents > 0) {
|
||||||
Log.trace("Suppressed reporting %d duplicate events.", m_duplicateEvents);
|
Log.trace("Suppressed reporting %d duplicate events.", m_duplicateEvents);
|
||||||
}
|
}
|
||||||
const char* sourceName = intentName(evt.intent);;
|
const char* sourceName = evt.name();
|
||||||
const char* valueBuf = eventValue(evt);
|
const char* valueBuf = eventValue(evt);
|
||||||
if (sourceName == 0) {
|
if (sourceName == 0) {
|
||||||
Log.trace("Event: intent: %d value: %s", evt.intent, valueBuf);
|
Log.trace("Event: intent: %d value: %s", evt.intent, valueBuf);
|
||||||
|
@ -6,7 +6,6 @@ class LogService : public Task {
|
|||||||
void handleEvent(const InputEvent& event) override;
|
void handleEvent(const InputEvent& event) override;
|
||||||
void loop() override {}
|
void loop() override {}
|
||||||
|
|
||||||
static const char* intentName(InputEvent::Intent intent);
|
|
||||||
static const char* eventValue(const InputEvent& evt);
|
static const char* eventValue(const InputEvent& evt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
160
src/Platform.cpp
160
src/Platform.cpp
@ -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,29 +103,25 @@ 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;
|
||||||
Log.error(u8"Last Figment was %s", lastTaskBuf);
|
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()) {
|
||||||
|
if (!(*it)->isFigment()) {
|
||||||
|
Log.trace(" %s", (*it)->name);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
Log.trace("Registered Figments:");
|
||||||
|
it = beginTasks();
|
||||||
while (it != endTasks()) {
|
while (it != endTasks()) {
|
||||||
if ((*it)->isFigment()) {
|
if ((*it)->isFigment()) {
|
||||||
Log.trace(" Figment: %s", (*it)->name);
|
|
||||||
} else {
|
|
||||||
Log.trace(" %s", (*it)->name);
|
Log.trace(" %s", (*it)->name);
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
@ -180,16 +131,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 +144,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,50 +168,43 @@ Platform::model()
|
|||||||
|
|
||||||
void
|
void
|
||||||
Platform::restart() {
|
Platform::restart() {
|
||||||
#ifdef BOARD_ESP8266
|
PlatformImpl<>::restart();
|
||||||
ESP.wdtDisable();
|
|
||||||
ESP.restart();
|
|
||||||
#elif defined(BOARD_ESP32)
|
|
||||||
ESP.restart();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__attribute__((noreturn))
|
|
||||||
void
|
void
|
||||||
doReboot(Args& args, Print& out)
|
Platform::doReboot(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
out.println("Rebooting");
|
out.println("Rebooting");
|
||||||
Platform::restart();
|
restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn))
|
|
||||||
void
|
void
|
||||||
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;
|
||||||
|
|
||||||
void
|
void
|
||||||
doTaskStart(Args& args, Print& out)
|
Platform::doTaskStart(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
s = args[1];
|
s = args[1];
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::StartThing, s.c_str()});
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::StartThing, s.c_str()});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doTaskStop(Args& args, Print& out)
|
Platform::doTaskStop(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
s = args[1];
|
s = args[1];
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::StopThing, s.c_str()});
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::StopThing, s.c_str()});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doTaskList(Args& args, Print& out)
|
Platform::doTaskList(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
auto sched = MainLoop::instance()->scheduler;
|
auto sched = MainLoop::instance()->scheduler;
|
||||||
auto printer = Static<SerialInput>::instance()->printer();
|
auto printer = Static<SerialInput>::instance()->printer();
|
||||||
@ -312,18 +226,16 @@ doTaskList(Args& args, Print& out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const std::vector<Command> _commands = {
|
|
||||||
{"tasks", doTaskList},
|
|
||||||
{"safe-mode", doSafeMode},
|
|
||||||
{"reboot", doReboot},
|
|
||||||
{"stop", doTaskStop},
|
|
||||||
{"start", doTaskStart}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
const std::vector<Command>&
|
||||||
Platform::commands() const
|
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;
|
return _commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,17 @@
|
|||||||
#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;
|
||||||
static char s_deviceID[15];
|
static char s_deviceID[15];
|
||||||
|
|
||||||
|
void doTaskList(Args& args, Print& out);
|
||||||
|
void doTaskStop(Args& args, Print& out);
|
||||||
|
void doTaskStart(Args& args, Print& out);
|
||||||
|
__attribute__((noreturn)) void doSafeMode(Args& args, Print& out);
|
||||||
|
__attribute__((noreturn)) void doReboot(Args& args, Print& out);
|
||||||
public:
|
public:
|
||||||
Platform() : Task("Platform") {state = Task::Running;}
|
Platform() : Task("Platform") {state = Task::Running;}
|
||||||
static BootOptions bootopts;
|
static BootOptions bootopts;
|
||||||
@ -20,6 +27,10 @@ class Platform : public Task {
|
|||||||
static String devName = model() + " " + Platform::deviceID();
|
static String devName = model() + " " + Platform::deviceID();
|
||||||
return devName;
|
return devName;
|
||||||
}
|
}
|
||||||
|
static const String deviceHostname() {
|
||||||
|
static String devName = String("renderbug-") + Platform::deviceID();
|
||||||
|
return devName;
|
||||||
|
}
|
||||||
static void preSetup();
|
static void preSetup();
|
||||||
static void bootSplash();
|
static void bootSplash();
|
||||||
static void setup();
|
static void setup();
|
||||||
|
@ -63,42 +63,35 @@ Sequencer::handleEvent(const InputEvent& evt)
|
|||||||
Log.verbose("Starting pattern task %s", pattern);
|
Log.verbose("Starting pattern task %s", pattern);
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::StartThing, pattern});
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::StartThing, pattern});
|
||||||
}
|
}
|
||||||
} else if (evt.intent == InputEvent::SetPattern && evt.asString() == m_scenes[m_idx].name) {
|
} else if (evt.intent == InputEvent::SetScene && evt.asString() == m_scenes[m_idx].name) {
|
||||||
return;
|
return;
|
||||||
} else if (evt.intent == InputEvent::SetPattern || evt.intent == InputEvent::NextPattern || evt.intent == InputEvent::PreviousPattern) {
|
} else if (evt.intent == InputEvent::SetScene) {
|
||||||
Log.notice("Switching pattern!");
|
Log.notice("Switching scene to %s!", evt.asString());
|
||||||
|
|
||||||
m_scenes[m_idx].stop();
|
int newIdx = 0;
|
||||||
|
bool found = false;
|
||||||
if (evt.intent == InputEvent::NextPattern) {
|
for(newIdx = 0; newIdx < m_scenes.size(); newIdx++) {
|
||||||
m_idx++;
|
if (!strcmp(evt.asString(), m_scenes[newIdx].name)) {
|
||||||
} else if (evt.intent == InputEvent::PreviousPattern) {
|
found = true;
|
||||||
m_idx--;
|
|
||||||
} else {
|
|
||||||
for(m_idx = 0; m_idx < m_scenes.size(); m_idx++) {
|
|
||||||
if (!strcmp(evt.asString(), m_scenes[m_idx].name)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (m_idx < 0) {
|
|
||||||
m_idx = m_scenes.size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_idx >= m_scenes.size()) {
|
|
||||||
m_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
m_scenes[m_idx].stop();
|
||||||
|
m_idx = newIdx;
|
||||||
m_scenes[m_idx].start();
|
m_scenes[m_idx].start();
|
||||||
|
} else {
|
||||||
|
Log.notice("Scene not found!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doScenes(Args& args, Print& out)
|
Sequencer::doScenes(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
out.println("Available scenes: ");
|
out.println("Available scenes: ");
|
||||||
for (auto scene : Static<Sequencer>::instance()->scenes()) {
|
for (auto scene : scenes()) {
|
||||||
out.println(scene.name);
|
out.println(scene.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,20 +99,19 @@ doScenes(Args& args, Print& out)
|
|||||||
static String s;
|
static String s;
|
||||||
|
|
||||||
void
|
void
|
||||||
doScene(Args& args, Print& out)
|
Sequencer::doScene(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
s = args[1];
|
s = args[1];
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetPattern, s.c_str()});
|
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetScene, s.c_str()});
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Command> _commands = {
|
|
||||||
{"scene", doScene},
|
|
||||||
{"scenes", doScenes}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
const std::vector<Command>&
|
||||||
Sequencer::commands() const
|
Sequencer::commands() const
|
||||||
{
|
{
|
||||||
|
static const std::vector<Command> _commands = {
|
||||||
|
{"scene", &Sequencer::doScene},
|
||||||
|
{"scenes", &Sequencer::doScenes}
|
||||||
|
};
|
||||||
return _commands;
|
return _commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,4 +28,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
int m_idx;
|
int m_idx;
|
||||||
std::vector<Scene> m_scenes;
|
std::vector<Scene> m_scenes;
|
||||||
|
|
||||||
|
void doScene(Args& args, Print& out);
|
||||||
|
void doScenes(Args& args, Print& out);
|
||||||
};
|
};
|
||||||
|
@ -26,13 +26,7 @@ void ChimesAnimation::randomize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChimesAnimation::handleEvent(const InputEvent& evt) {
|
void ChimesAnimation::handleEvent(const InputEvent& evt) {
|
||||||
if (evt.intent == InputEvent::UserInput) {
|
if (evt.intent == InputEvent::SetColor) {
|
||||||
if (strcmp(evt.asString(), "blobs") == 0) {
|
|
||||||
m_blobs.toggle();
|
|
||||||
} else if (strcmp(evt.asString(), "chimes") == 0) {
|
|
||||||
m_chimes.toggle();
|
|
||||||
}
|
|
||||||
} else if (evt.intent == InputEvent::SetColor) {
|
|
||||||
m_flashBrightness.set(255, 0);
|
m_flashBrightness.set(255, 0);
|
||||||
m_flashColor = evt.asRGB();
|
m_flashColor = evt.asRGB();
|
||||||
uint8_t flashHue = rgb2hsv_approximate(m_flashColor).hue;
|
uint8_t flashHue = rgb2hsv_approximate(m_flashColor).hue;
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
#include "./Power.h"
|
|
||||||
#include "../Static.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
|
|
||||||
Power::handleConfigChange(const Configuration& config)
|
|
||||||
{
|
|
||||||
m_milliamps = config.get("power.milliamps", m_milliamps);
|
|
||||||
m_voltage = config.get("power.volts", m_voltage);
|
|
||||||
m_useBPM = config.get("power.useBPM", m_useBPM);
|
|
||||||
|
|
||||||
if (m_voltage == 0 || m_milliamps == 0) {
|
|
||||||
Log.notice("power: Impossible power config: %dma @ %dv", m_milliamps, m_voltage);
|
|
||||||
m_valid = false;
|
|
||||||
} else {
|
|
||||||
Log.notice("power: Configured to use %dma @ %dv", m_milliamps, m_voltage);
|
|
||||||
m_valid = true;
|
|
||||||
FastLED.setMaxPowerInVoltsAndMilliamps(m_voltage, m_milliamps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
STATIC_ALLOC(Power);
|
|
||||||
STATIC_TASK(Power);
|
|
@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <Figments.h>
|
|
||||||
#include "../Config.h"
|
|
||||||
|
|
||||||
class Power: public Figment, ConfigTaskMixin {
|
|
||||||
public:
|
|
||||||
Power() : Figment("Power") {state = Task::Running;}
|
|
||||||
|
|
||||||
void handleEvent(const InputEvent& evt) override {
|
|
||||||
switch (evt.intent) {
|
|
||||||
case InputEvent::PowerToggle:
|
|
||||||
m_powerState = m_powerState.value() <= 128 ? 255 : 0;
|
|
||||||
m_forced = false;
|
|
||||||
Log.notice("Power toggled to %t", m_powerState);
|
|
||||||
break;
|
|
||||||
case InputEvent::SetPower:
|
|
||||||
m_powerState = evt.asInt() == 0 ? 0 : 255;
|
|
||||||
m_forced = false;
|
|
||||||
Log.notice("Power state is now %t", m_powerState);
|
|
||||||
break;
|
|
||||||
case InputEvent::SetBrightness:
|
|
||||||
m_brightness = evt.asInt();
|
|
||||||
m_forced = false;
|
|
||||||
break;
|
|
||||||
case InputEvent::Beat:
|
|
||||||
m_beatDecay.set(0, 255);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ConfigTaskMixin::handleEvent(evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleConfigChange(const Configuration& config) override;
|
|
||||||
|
|
||||||
void loop() override {
|
|
||||||
ConfigTaskMixin::loop();
|
|
||||||
m_powerState.update();
|
|
||||||
m_brightness.update();
|
|
||||||
EVERY_N_MILLISECONDS(20) {
|
|
||||||
m_beatDecay.update(13);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(Display* dpy) const override {
|
|
||||||
if (F_LIKELY(m_valid && !m_forced)) {
|
|
||||||
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 scaledBrightness = scale8(m_powerState, clippedBrightness);
|
|
||||||
const uint8_t videoBrightness = brighten8_video(scaledBrightness);
|
|
||||||
const uint8_t powerBrightness = calculate_max_brightness_for_power_mW(videoBrightness, m_voltage * m_milliamps);
|
|
||||||
FastLED.setBrightness(powerBrightness);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void forceBrightness(uint8_t v);
|
|
||||||
|
|
||||||
const std::vector<Command>& commands() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
AnimatedNumber m_powerState = 255;
|
|
||||||
AnimatedNumber m_brightness = 255;
|
|
||||||
AnimatedNumber m_beatDecay = 255;
|
|
||||||
uint8_t m_voltage = 5;
|
|
||||||
uint16_t m_milliamps = 500;
|
|
||||||
bool m_valid = true;
|
|
||||||
bool m_useBPM = false;
|
|
||||||
bool m_forced = false;
|
|
||||||
};
|
|
@ -49,10 +49,7 @@ void SolidAnimation::loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Perfcounter.h>
|
|
||||||
|
|
||||||
void SolidAnimation::render(Display* dpy) const {
|
void SolidAnimation::render(Display* dpy) const {
|
||||||
PerfCounter _("solidRender");
|
|
||||||
CRGB color(m_red.value(), m_green.value(), m_blue.value());
|
CRGB color(m_red.value(), m_green.value(), m_blue.value());
|
||||||
CRGB scaledPrev = m_prevColor;
|
CRGB scaledPrev = m_prevColor;
|
||||||
scaledPrev = color.nscale8(30);
|
scaledPrev = color.nscale8(30);
|
||||||
|
816
src/colors.cpp
816
src/colors.cpp
@ -1,816 +0,0 @@
|
|||||||
#include "colors.h"
|
|
||||||
|
|
||||||
const ColorInfo color_data[] = {
|
|
||||||
#ifdef CONFIG_NO_COLORDATA
|
|
||||||
#else
|
|
||||||
{ "Air Superiority Blue", { 114, 160, 193 } },
|
|
||||||
{ "Alabama Crimson", { 163, 38, 56 } },
|
|
||||||
{ "Alice Blue", { 240, 248, 255 } },
|
|
||||||
{ "Alizarin Crimson", { 227, 38, 54 } },
|
|
||||||
{ "Alloy Orange", { 196, 98, 16 } },
|
|
||||||
{ "Almond", { 239, 222, 205 } },
|
|
||||||
{ "Amaranth", { 229, 43, 80 } },
|
|
||||||
{ "Amber", { 255, 191, 0 } },
|
|
||||||
{ "American Rose", { 255, 3, 62 } },
|
|
||||||
{ "Amethyst", { 153, 102, 204 } },
|
|
||||||
{ "Android Green", { 164, 198, 57 } },
|
|
||||||
{ "Anti-Flash White", { 242, 243, 244 } },
|
|
||||||
{ "Antique Brass", { 205, 149, 117 } },
|
|
||||||
{ "Antique Fuchsia", { 145, 92, 131 } },
|
|
||||||
{ "Antique Ruby", { 132, 27, 45 } },
|
|
||||||
{ "Antique White", { 250, 235, 215 } },
|
|
||||||
{ "Apple Green", { 141, 182, 0 } },
|
|
||||||
{ "Apricot", { 251, 206, 177 } },
|
|
||||||
{ "Aqua", { 0, 255, 255 } },
|
|
||||||
{ "Aquamarine", { 127, 255, 212 } },
|
|
||||||
{ "Army Green", { 75, 83, 32 } },
|
|
||||||
{ "Arsenic", { 59, 68, 75 } },
|
|
||||||
{ "Arylide Yellow", { 233, 214, 107 } },
|
|
||||||
{ "Ash Grey", { 178, 190, 181 } },
|
|
||||||
{ "Asparagus", { 135, 169, 107 } },
|
|
||||||
{ "Atomic Tangerine", { 255, 153, 102 } },
|
|
||||||
{ "Auburn", { 165, 42, 42 } },
|
|
||||||
{ "Aureolin", { 253, 238, 0 } },
|
|
||||||
{ "Aurometalsaurus", { 110, 127, 128 } },
|
|
||||||
{ "Avocado", { 86, 130, 3 } },
|
|
||||||
{ "Azure", { 0, 127, 255 } },
|
|
||||||
{ "Baby Blue", { 137, 207, 240 } },
|
|
||||||
{ "Baby Blue Eyes", { 161, 202, 241 } },
|
|
||||||
{ "Baby Pink", { 244, 194, 194 } },
|
|
||||||
{ "Ball Blue", { 33, 171, 205 } },
|
|
||||||
{ "Banana Mania", { 250, 231, 181 } },
|
|
||||||
{ "Banana Yellow", { 255, 225, 53 } },
|
|
||||||
{ "Barn Red", { 124, 10, 2 } },
|
|
||||||
{ "Battleship Grey", { 132, 132, 130 } },
|
|
||||||
{ "Bazaar", { 152, 119, 123 } },
|
|
||||||
{ "Beau Blue", { 188, 212, 230 } },
|
|
||||||
{ "Beaver", { 159, 129, 112 } },
|
|
||||||
{ "Beige", { 245, 245, 220 } },
|
|
||||||
{ "Big Dip O’Ruby", { 156, 37, 66 } },
|
|
||||||
{ "Bisque", { 255, 228, 196 } },
|
|
||||||
{ "Bistre", { 61, 43, 31 } },
|
|
||||||
{ "Bittersweet", { 254, 111, 94 } },
|
|
||||||
{ "Bittersweet Shimmer", { 191, 79, 81 } },
|
|
||||||
{ "Black", { 0, 0, 0 } },
|
|
||||||
{ "Black Bean", { 61, 12, 2 } },
|
|
||||||
{ "Black Leather Jacket", { 37, 53, 41 } },
|
|
||||||
{ "Black Olive", { 59, 60, 54 } },
|
|
||||||
{ "Blanched Almond", { 255, 235, 205 } },
|
|
||||||
{ "Blast-Off Bronze", { 165, 113, 100 } },
|
|
||||||
{ "Bleu De France", { 49, 140, 231 } },
|
|
||||||
{ "Blizzard Blue", { 172, 229, 238 } },
|
|
||||||
{ "Blond", { 250, 240, 190 } },
|
|
||||||
{ "Blue", { 0, 0, 255 } },
|
|
||||||
{ "Blue Gray", { 102, 153, 204 } },
|
|
||||||
{ "Blue-Green", { 13, 152, 186 } },
|
|
||||||
{ "Blue Sapphire", { 18, 97, 128 } },
|
|
||||||
{ "Blue-Violet", { 138, 43, 226 } },
|
|
||||||
{ "Blush", { 222, 93, 131 } },
|
|
||||||
{ "Bole", { 121, 68, 59 } },
|
|
||||||
{ "Bondi Blue", { 0, 149, 182 } },
|
|
||||||
{ "Bone", { 227, 218, 201 } },
|
|
||||||
{ "Boston University Red", { 204, 0, 0 } },
|
|
||||||
{ "Bottle Green", { 0, 106, 78 } },
|
|
||||||
{ "Boysenberry", { 135, 50, 96 } },
|
|
||||||
{ "Brandeis Blue", { 0, 112, 255 } },
|
|
||||||
{ "Brass", { 181, 166, 66 } },
|
|
||||||
{ "Brick Red", { 203, 65, 84 } },
|
|
||||||
{ "Bright Cerulean", { 29, 172, 214 } },
|
|
||||||
{ "Bright Green", { 102, 255, 0 } },
|
|
||||||
{ "Bright Lavender", { 191, 148, 228 } },
|
|
||||||
{ "Bright Maroon", { 195, 33, 72 } },
|
|
||||||
{ "Bright Pink", { 255, 0, 127 } },
|
|
||||||
{ "Bright Turquoise", { 8, 232, 222 } },
|
|
||||||
{ "Bright Ube", { 209, 159, 232 } },
|
|
||||||
{ "Brilliant Lavender", { 244, 187, 255 } },
|
|
||||||
{ "Brilliant Rose", { 255, 85, 163 } },
|
|
||||||
{ "Brink Pink", { 251, 96, 127 } },
|
|
||||||
{ "British Racing Green", { 0, 66, 37 } },
|
|
||||||
{ "Bronze", { 205, 127, 50 } },
|
|
||||||
{ "Brown", { 150, 75, 0 } },
|
|
||||||
{ "Bubble Gum", { 255, 193, 204 } },
|
|
||||||
{ "Bubbles", { 231, 254, 255 } },
|
|
||||||
{ "Buff", { 240, 220, 130 } },
|
|
||||||
{ "Bulgarian Rose", { 72, 6, 7 } },
|
|
||||||
{ "Burgundy", { 128, 0, 32 } },
|
|
||||||
{ "Burlywood", { 222, 184, 135 } },
|
|
||||||
{ "Burnt Orange", { 204, 85, 0 } },
|
|
||||||
{ "Burnt Sienna", { 233, 116, 81 } },
|
|
||||||
{ "Burnt Umber", { 138, 51, 36 } },
|
|
||||||
{ "Byzantine", { 189, 51, 164 } },
|
|
||||||
{ "Byzantium", { 112, 41, 99 } },
|
|
||||||
{ "Cadet", { 83, 104, 114 } },
|
|
||||||
{ "Cadet Blue", { 95, 158, 160 } },
|
|
||||||
{ "Cadet Grey", { 145, 163, 176 } },
|
|
||||||
{ "Cadmium Green", { 0, 107, 60 } },
|
|
||||||
{ "Cadmium Orange", { 237, 135, 45 } },
|
|
||||||
{ "Cadmium Red", { 227, 0, 34 } },
|
|
||||||
{ "Cadmium Yellow", { 255, 246, 0 } },
|
|
||||||
{ "Cal Poly Green", { 30, 77, 43 } },
|
|
||||||
{ "Cambridge Blue", { 163, 193, 173 } },
|
|
||||||
{ "Camel", { 193, 154, 107 } },
|
|
||||||
{ "Cameo Pink", { 239, 187, 204 } },
|
|
||||||
{ "Camouflage Green", { 120, 134, 107 } },
|
|
||||||
{ "Canary Yellow", { 255, 239, 0 } },
|
|
||||||
{ "Candy Apple Red", { 255, 8, 0 } },
|
|
||||||
{ "Candy Pink", { 228, 113, 122 } },
|
|
||||||
{ "Capri", { 0, 191, 255 } },
|
|
||||||
{ "Caput Mortuum", { 89, 39, 32 } },
|
|
||||||
{ "Cardinal", { 196, 30, 58 } },
|
|
||||||
{ "Caribbean Green", { 0, 204, 153 } },
|
|
||||||
{ "Carmine", { 150, 0, 24 } },
|
|
||||||
{ "Carmine Pink", { 235, 76, 66 } },
|
|
||||||
{ "Carmine Red", { 255, 0, 56 } },
|
|
||||||
{ "Carnation Pink", { 255, 166, 201 } },
|
|
||||||
{ "Carnelian", { 179, 27, 27 } },
|
|
||||||
{ "Carolina Blue", { 153, 186, 221 } },
|
|
||||||
{ "Carrot Orange", { 237, 145, 33 } },
|
|
||||||
{ "Catalina Blue", { 6, 42, 120 } },
|
|
||||||
{ "Ceil", { 146, 161, 207 } },
|
|
||||||
{ "Celadon", { 172, 225, 175 } },
|
|
||||||
{ "Celadon Blue", { 0, 123, 167 } },
|
|
||||||
{ "Celadon Green", { 47, 132, 124 } },
|
|
||||||
{ "Celeste", { 178, 255, 255 } },
|
|
||||||
{ "Celestial Blue", { 73, 151, 208 } },
|
|
||||||
{ "Cerise", { 222, 49, 99 } },
|
|
||||||
{ "Cerise Pink", { 236, 59, 131 } },
|
|
||||||
{ "Cerulean", { 0, 123, 167 } },
|
|
||||||
{ "Cerulean Blue", { 42, 82, 190 } },
|
|
||||||
{ "Cerulean Frost", { 109, 155, 195 } },
|
|
||||||
{ "Cg Blue", { 0, 122, 165 } },
|
|
||||||
{ "Cg Red", { 224, 60, 49 } },
|
|
||||||
{ "Chamoisee", { 160, 120, 90 } },
|
|
||||||
{ "Champagne", { 250, 214, 165 } },
|
|
||||||
{ "Charcoal", { 54, 69, 79 } },
|
|
||||||
{ "Charm Pink", { 230, 143, 172 } },
|
|
||||||
{ "Chartreuse", { 223, 255, 0 } },
|
|
||||||
{ "Cherry", { 222, 49, 99 } },
|
|
||||||
{ "Cherry Blossom Pink", { 255, 183, 197 } },
|
|
||||||
{ "Chestnut", { 205, 92, 92 } },
|
|
||||||
{ "China Pink", { 222, 111, 161 } },
|
|
||||||
{ "China Rose", { 168, 81, 110 } },
|
|
||||||
{ "Chinese Red", { 170, 56, 30 } },
|
|
||||||
{ "Chocolate", { 123, 63, 0 } },
|
|
||||||
{ "Chrome Yellow", { 255, 167, 0 } },
|
|
||||||
{ "Cinereous", { 152, 129, 123 } },
|
|
||||||
{ "Cinnabar", { 227, 66, 52 } },
|
|
||||||
{ "Cinnamon", { 210, 105, 30 } },
|
|
||||||
{ "Citrine", { 228, 208, 10 } },
|
|
||||||
{ "Classic Rose", { 251, 204, 231 } },
|
|
||||||
{ "Cobalt", { 0, 71, 171 } },
|
|
||||||
{ "Cocoa Brown", { 210, 105, 30 } },
|
|
||||||
{ "Coffee", { 111, 78, 55 } },
|
|
||||||
{ "Columbia Blue", { 155, 221, 255 } },
|
|
||||||
{ "Congo Pink", { 248, 131, 121 } },
|
|
||||||
{ "Cool Black", { 0, 46, 99 } },
|
|
||||||
{ "Cool Grey", { 140, 146, 172 } },
|
|
||||||
{ "Copper", { 184, 115, 51 } },
|
|
||||||
{ "Copper Penny", { 173, 111, 105 } },
|
|
||||||
{ "Copper Red", { 203, 109, 81 } },
|
|
||||||
{ "Copper Rose", { 153, 102, 102 } },
|
|
||||||
{ "Coquelicot", { 255, 56, 0 } },
|
|
||||||
{ "Coral", { 255, 127, 80 } },
|
|
||||||
{ "Coral Pink", { 248, 131, 121 } },
|
|
||||||
{ "Coral Red", { 255, 64, 64 } },
|
|
||||||
{ "Cordovan", { 137, 63, 69 } },
|
|
||||||
{ "Corn", { 251, 236, 93 } },
|
|
||||||
{ "Cornell Red", { 179, 27, 27 } },
|
|
||||||
{ "Cornflower Blue", { 100, 149, 237 } },
|
|
||||||
{ "Cornsilk", { 255, 248, 220 } },
|
|
||||||
{ "Cosmic Latte", { 255, 248, 231 } },
|
|
||||||
{ "Cotton Candy", { 255, 188, 217 } },
|
|
||||||
{ "Cream", { 255, 253, 208 } },
|
|
||||||
{ "Crimson", { 220, 20, 60 } },
|
|
||||||
{ "Crimson Glory", { 190, 0, 50 } },
|
|
||||||
{ "Cyan", { 0, 255, 255 } },
|
|
||||||
{ "Daffodil", { 255, 255, 49 } },
|
|
||||||
{ "Dandelion", { 240, 225, 48 } },
|
|
||||||
{ "Dark Blue", { 0, 0, 139 } },
|
|
||||||
{ "Dark Brown", { 101, 67, 33 } },
|
|
||||||
{ "Dark Byzantium", { 93, 57, 84 } },
|
|
||||||
{ "Dark Candy Apple Red", { 164, 0, 0 } },
|
|
||||||
{ "Dark Cerulean", { 8, 69, 126 } },
|
|
||||||
{ "Dark Chestnut", { 152, 105, 96 } },
|
|
||||||
{ "Dark Coral", { 205, 91, 69 } },
|
|
||||||
{ "Dark Cyan", { 0, 139, 139 } },
|
|
||||||
{ "Dark Electric Blue", { 83, 104, 120 } },
|
|
||||||
{ "Dark Goldenrod", { 184, 134, 11 } },
|
|
||||||
{ "Dark Gray", { 169, 169, 169 } },
|
|
||||||
{ "Dark Green", { 1, 50, 32 } },
|
|
||||||
{ "Dark Imperial Blue", { 0, 65, 106 } },
|
|
||||||
{ "Dark Jungle Green", { 26, 36, 33 } },
|
|
||||||
{ "Dark Khaki", { 189, 183, 107 } },
|
|
||||||
{ "Dark Lava", { 72, 60, 50 } },
|
|
||||||
{ "Dark Lavender", { 115, 79, 150 } },
|
|
||||||
{ "Dark Magenta", { 139, 0, 139 } },
|
|
||||||
{ "Dark Midnight Blue", { 0, 51, 102 } },
|
|
||||||
{ "Dark Olive Green", { 85, 107, 47 } },
|
|
||||||
{ "Dark Orange", { 255, 140, 0 } },
|
|
||||||
{ "Dark Orchid", { 153, 50, 204 } },
|
|
||||||
{ "Dark Pastel Blue", { 119, 158, 203 } },
|
|
||||||
{ "Dark Pastel Green", { 3, 192, 60 } },
|
|
||||||
{ "Dark Pastel Purple", { 150, 111, 214 } },
|
|
||||||
{ "Dark Pastel Red", { 194, 59, 34 } },
|
|
||||||
{ "Dark Pink", { 231, 84, 128 } },
|
|
||||||
{ "Dark Powder Blue", { 0, 51, 153 } },
|
|
||||||
{ "Dark Raspberry", { 135, 38, 87 } },
|
|
||||||
{ "Dark Red", { 139, 0, 0 } },
|
|
||||||
{ "Dark Salmon", { 233, 150, 122 } },
|
|
||||||
{ "Dark Scarlet", { 86, 3, 25 } },
|
|
||||||
{ "Dark Sea Green", { 143, 188, 143 } },
|
|
||||||
{ "Dark Sienna", { 60, 20, 20 } },
|
|
||||||
{ "Dark Slate Blue", { 72, 61, 139 } },
|
|
||||||
{ "Dark Slate Gray", { 47, 79, 79 } },
|
|
||||||
{ "Dark Spring Green", { 23, 114, 69 } },
|
|
||||||
{ "Dark Tan", { 145, 129, 81 } },
|
|
||||||
{ "Dark Tangerine", { 255, 168, 18 } },
|
|
||||||
{ "Dark Taupe", { 72, 60, 50 } },
|
|
||||||
{ "Dark Terra Cotta", { 204, 78, 92 } },
|
|
||||||
{ "Dark Turquoise", { 0, 206, 209 } },
|
|
||||||
{ "Dark Violet", { 148, 0, 211 } },
|
|
||||||
{ "Dark Yellow", { 155, 135, 12 } },
|
|
||||||
{ "Dartmouth Green", { 0, 112, 60 } },
|
|
||||||
{ "Deep Carmine", { 169, 32, 62 } },
|
|
||||||
{ "Deep Carmine Pink", { 239, 48, 56 } },
|
|
||||||
{ "Deep Carrot Orange", { 233, 105, 44 } },
|
|
||||||
{ "Deep Cerise", { 218, 50, 135 } },
|
|
||||||
{ "Deep Champagne", { 250, 214, 165 } },
|
|
||||||
{ "Deep Chestnut", { 185, 78, 72 } },
|
|
||||||
{ "Deep Coffee", { 112, 66, 65 } },
|
|
||||||
{ "Deep Fuchsia", { 193, 84, 193 } },
|
|
||||||
{ "Deep Jungle Green", { 0, 75, 73 } },
|
|
||||||
{ "Deep Lilac", { 153, 85, 187 } },
|
|
||||||
{ "Deep Magenta", { 204, 0, 204 } },
|
|
||||||
{ "Deep Peach", { 255, 203, 164 } },
|
|
||||||
{ "Deep Pink", { 255, 20, 147 } },
|
|
||||||
{ "Deep Ruby", { 132, 63, 91 } },
|
|
||||||
{ "Deep Saffron", { 255, 153, 51 } },
|
|
||||||
{ "Deep Sky Blue", { 0, 191, 255 } },
|
|
||||||
{ "Deep Tuscan Red", { 102, 66, 77 } },
|
|
||||||
{ "Denim", { 21, 96, 189 } },
|
|
||||||
{ "Desert", { 193, 154, 107 } },
|
|
||||||
{ "Desert Sand", { 237, 201, 175 } },
|
|
||||||
{ "Dim Gray", { 105, 105, 105 } },
|
|
||||||
{ "Dodger Blue", { 30, 144, 255 } },
|
|
||||||
{ "Dogwood Rose", { 215, 24, 104 } },
|
|
||||||
{ "Dollar Bill", { 133, 187, 101 } },
|
|
||||||
{ "Drab", { 150, 113, 23 } },
|
|
||||||
{ "Duke Blue", { 0, 0, 156 } },
|
|
||||||
{ "Earth Yellow", { 225, 169, 95 } },
|
|
||||||
{ "Ebony", { 85, 93, 80 } },
|
|
||||||
{ "Ecru", { 194, 178, 128 } },
|
|
||||||
{ "Eggplant", { 97, 64, 81 } },
|
|
||||||
{ "Eggshell", { 240, 234, 214 } },
|
|
||||||
{ "Egyptian Blue", { 16, 52, 166 } },
|
|
||||||
{ "Electric Blue", { 125, 249, 255 } },
|
|
||||||
{ "Electric Crimson", { 255, 0, 63 } },
|
|
||||||
{ "Electric Cyan", { 0, 255, 255 } },
|
|
||||||
{ "Electric Green", { 0, 255, 0 } },
|
|
||||||
{ "Electric Indigo", { 111, 0, 255 } },
|
|
||||||
{ "Electric Lavender", { 244, 187, 255 } },
|
|
||||||
{ "Electric Lime", { 204, 255, 0 } },
|
|
||||||
{ "Electric Purple", { 191, 0, 255 } },
|
|
||||||
{ "Electric Ultramarine", { 63, 0, 255 } },
|
|
||||||
{ "Electric Violet", { 143, 0, 255 } },
|
|
||||||
{ "Electric Yellow", { 255, 255, 0 } },
|
|
||||||
{ "Emerald", { 80, 200, 120 } },
|
|
||||||
{ "English Lavender", { 180, 131, 149 } },
|
|
||||||
{ "Eton Blue", { 150, 200, 162 } },
|
|
||||||
{ "Fallow", { 193, 154, 107 } },
|
|
||||||
{ "Falu Red", { 128, 24, 24 } },
|
|
||||||
{ "Fandango", { 181, 51, 137 } },
|
|
||||||
{ "Fashion Fuchsia", { 244, 0, 161 } },
|
|
||||||
{ "Fawn", { 229, 170, 112 } },
|
|
||||||
{ "Feldgrau", { 77, 93, 83 } },
|
|
||||||
{ "Fern Green", { 79, 121, 66 } },
|
|
||||||
{ "Ferrari Red", { 255, 40, 0 } },
|
|
||||||
{ "Field Drab", { 108, 84, 30 } },
|
|
||||||
{ "Fire Engine Red", { 206, 32, 41 } },
|
|
||||||
{ "Firebrick", { 178, 34, 34 } },
|
|
||||||
{ "Flame", { 226, 88, 34 } },
|
|
||||||
{ "Flamingo Pink", { 252, 142, 172 } },
|
|
||||||
{ "Flavescent", { 247, 233, 142 } },
|
|
||||||
{ "Flax", { 238, 220, 130 } },
|
|
||||||
{ "Floral White", { 255, 250, 240 } },
|
|
||||||
{ "Fluorescent Orange", { 255, 191, 0 } },
|
|
||||||
{ "Fluorescent Pink", { 255, 20, 147 } },
|
|
||||||
{ "Fluorescent Yellow", { 204, 255, 0 } },
|
|
||||||
{ "Folly", { 255, 0, 79 } },
|
|
||||||
{ "Forest Green", { 1, 68, 33 } },
|
|
||||||
{ "French Beige", { 166, 123, 91 } },
|
|
||||||
{ "French Blue", { 0, 114, 187 } },
|
|
||||||
{ "French Lilac", { 134, 96, 142 } },
|
|
||||||
{ "French Lime", { 204, 255, 0 } },
|
|
||||||
{ "French Raspberry", { 199, 44, 72 } },
|
|
||||||
{ "French Rose", { 246, 74, 138 } },
|
|
||||||
{ "Fuchsia", { 255, 0, 255 } },
|
|
||||||
{ "Fuchsia Pink", { 255, 119, 255 } },
|
|
||||||
{ "Fuchsia Rose", { 199, 67, 117 } },
|
|
||||||
{ "Fulvous", { 228, 132, 0 } },
|
|
||||||
{ "Fuzzy Wuzzy", { 204, 102, 102 } },
|
|
||||||
{ "Gainsboro", { 220, 220, 220 } },
|
|
||||||
{ "Gamboge", { 228, 155, 15 } },
|
|
||||||
{ "Ghost White", { 248, 248, 255 } },
|
|
||||||
{ "Ginger", { 176, 101, 0 } },
|
|
||||||
{ "Glaucous", { 96, 130, 182 } },
|
|
||||||
{ "Glitter", { 230, 232, 250 } },
|
|
||||||
{ "Gold", { 212, 175, 55 } },
|
|
||||||
{ "Golden Brown", { 153, 101, 21 } },
|
|
||||||
{ "Golden Poppy", { 252, 194, 0 } },
|
|
||||||
{ "Golden Yellow", { 255, 223, 0 } },
|
|
||||||
{ "Goldenrod", { 218, 165, 32 } },
|
|
||||||
{ "Granny Smith Apple", { 168, 228, 160 } },
|
|
||||||
{ "Gray", { 128, 128, 128 } },
|
|
||||||
{ "Gray-Asparagus", { 70, 89, 69 } },
|
|
||||||
{ "Green", { 0, 255, 0 } },
|
|
||||||
{ "Green-Yellow", { 173, 255, 47 } },
|
|
||||||
{ "Grullo", { 169, 154, 134 } },
|
|
||||||
{ "Guppie Green", { 0, 255, 127 } },
|
|
||||||
{ "Halayà úBe", { 102, 56, 84 } },
|
|
||||||
{ "Han Blue", { 68, 108, 207 } },
|
|
||||||
{ "Han Purple", { 82, 24, 250 } },
|
|
||||||
{ "Hansa Yellow", { 233, 214, 107 } },
|
|
||||||
{ "Harlequin", { 63, 255, 0 } },
|
|
||||||
{ "Harvard Crimson", { 201, 0, 22 } },
|
|
||||||
{ "Harvest Gold", { 218, 145, 0 } },
|
|
||||||
{ "Heart Gold", { 128, 128, 0 } },
|
|
||||||
{ "Heliotrope", { 223, 115, 255 } },
|
|
||||||
{ "Hollywood Cerise", { 244, 0, 161 } },
|
|
||||||
{ "Honeydew", { 240, 255, 240 } },
|
|
||||||
{ "Honolulu Blue", { 0, 127, 191 } },
|
|
||||||
{ "Hooker'S Green", { 73, 121, 107 } },
|
|
||||||
{ "Hot Magenta", { 255, 29, 206 } },
|
|
||||||
{ "Hot Pink", { 255, 105, 180 } },
|
|
||||||
{ "Hunter Green", { 53, 94, 59 } },
|
|
||||||
{ "Iceberg", { 113, 166, 210 } },
|
|
||||||
{ "Icterine", { 252, 247, 94 } },
|
|
||||||
{ "Imperial Blue", { 0, 35, 149 } },
|
|
||||||
{ "Inchworm", { 178, 236, 93 } },
|
|
||||||
{ "India Green", { 19, 136, 8 } },
|
|
||||||
{ "Indian Red", { 205, 92, 92 } },
|
|
||||||
{ "Indian Yellow", { 227, 168, 87 } },
|
|
||||||
{ "Indigo", { 111, 0, 255 } },
|
|
||||||
{ "International Klein Blue", { 0, 47, 167 } },
|
|
||||||
{ "International Orange", { 186, 22, 12 } },
|
|
||||||
{ "Iris", { 90, 79, 207 } },
|
|
||||||
{ "Isabelline", { 244, 240, 236 } },
|
|
||||||
{ "Islamic Green", { 0, 144, 0 } },
|
|
||||||
{ "Ivory", { 255, 255, 240 } },
|
|
||||||
{ "Jade", { 0, 168, 107 } },
|
|
||||||
{ "Jasmine", { 248, 222, 126 } },
|
|
||||||
{ "Jasper", { 215, 59, 62 } },
|
|
||||||
{ "Jazzberry Jam", { 165, 11, 94 } },
|
|
||||||
{ "Jet", { 52, 52, 52 } },
|
|
||||||
{ "Jonquil", { 250, 218, 94 } },
|
|
||||||
{ "June Bud", { 189, 218, 87 } },
|
|
||||||
{ "Jungle Green", { 41, 171, 135 } },
|
|
||||||
{ "Kelly Green", { 76, 187, 23 } },
|
|
||||||
{ "Kenyan Copper", { 124, 28, 5 } },
|
|
||||||
{ "Khaki", { 195, 176, 145 } },
|
|
||||||
{ "Ku Crimson", { 232, 0, 13 } },
|
|
||||||
{ "La Salle Green", { 8, 120, 48 } },
|
|
||||||
{ "Languid Lavender", { 214, 202, 221 } },
|
|
||||||
{ "Lapis Lazuli", { 38, 97, 156 } },
|
|
||||||
{ "Laser Lemon", { 254, 254, 34 } },
|
|
||||||
{ "Laurel Green", { 169, 186, 157 } },
|
|
||||||
{ "Lava", { 207, 16, 32 } },
|
|
||||||
{ "Lavender Blue", { 204, 204, 255 } },
|
|
||||||
{ "Lavender Blush", { 255, 240, 245 } },
|
|
||||||
{ "Lavender Gray", { 196, 195, 208 } },
|
|
||||||
{ "Lavender Indigo", { 148, 87, 235 } },
|
|
||||||
{ "Lavender Magenta", { 238, 130, 238 } },
|
|
||||||
{ "Lavender Mist", { 230, 230, 250 } },
|
|
||||||
{ "Lavender Pink", { 251, 174, 210 } },
|
|
||||||
{ "Lavender Purple", { 150, 123, 182 } },
|
|
||||||
{ "Lavender Rose", { 251, 160, 227 } },
|
|
||||||
{ "Lawn Green", { 124, 252, 0 } },
|
|
||||||
{ "Lemon", { 255, 247, 0 } },
|
|
||||||
{ "Lemon Chiffon", { 255, 250, 205 } },
|
|
||||||
{ "Lemon Lime", { 227, 255, 0 } },
|
|
||||||
{ "Licorice", { 26, 17, 16 } },
|
|
||||||
{ "Light Apricot", { 253, 213, 177 } },
|
|
||||||
{ "Light Blue", { 173, 216, 230 } },
|
|
||||||
{ "Light Brown", { 181, 101, 29 } },
|
|
||||||
{ "Light Carmine Pink", { 230, 103, 113 } },
|
|
||||||
{ "Light Coral", { 240, 128, 128 } },
|
|
||||||
{ "Light Cornflower Blue", { 147, 204, 234 } },
|
|
||||||
{ "Light Crimson", { 245, 105, 145 } },
|
|
||||||
{ "Light Cyan", { 224, 255, 255 } },
|
|
||||||
{ "Light Fuchsia Pink", { 249, 132, 239 } },
|
|
||||||
{ "Light Goldenrod Yellow", { 250, 250, 210 } },
|
|
||||||
{ "Light Gray", { 211, 211, 211 } },
|
|
||||||
{ "Light Green", { 144, 238, 144 } },
|
|
||||||
{ "Light Khaki", { 240, 230, 140 } },
|
|
||||||
{ "Light Pastel Purple", { 177, 156, 217 } },
|
|
||||||
{ "Light Pink", { 255, 182, 193 } },
|
|
||||||
{ "Light Red Ochre", { 233, 116, 81 } },
|
|
||||||
{ "Light Salmon", { 255, 160, 122 } },
|
|
||||||
{ "Light Salmon Pink", { 255, 153, 153 } },
|
|
||||||
{ "Light Sea Green", { 32, 178, 170 } },
|
|
||||||
{ "Light Sky Blue", { 135, 206, 250 } },
|
|
||||||
{ "Light Slate Gray", { 119, 136, 153 } },
|
|
||||||
{ "Light Taupe", { 179, 139, 109 } },
|
|
||||||
{ "Light Thulian Pink", { 230, 143, 172 } },
|
|
||||||
{ "Light Yellow", { 255, 255, 224 } },
|
|
||||||
{ "Lilac", { 200, 162, 200 } },
|
|
||||||
{ "Lime Green", { 50, 205, 50 } },
|
|
||||||
{ "Limerick", { 157, 194, 9 } },
|
|
||||||
{ "Lincoln Green", { 25, 89, 5 } },
|
|
||||||
{ "Linen", { 250, 240, 230 } },
|
|
||||||
{ "Lion", { 193, 154, 107 } },
|
|
||||||
{ "Little Boy Blue", { 108, 160, 220 } },
|
|
||||||
{ "Liver", { 83, 75, 79 } },
|
|
||||||
{ "Lust", { 230, 32, 32 } },
|
|
||||||
{ "Magenta", { 255, 0, 255 } },
|
|
||||||
{ "Magic Mint", { 170, 240, 209 } },
|
|
||||||
{ "Magnolia", { 248, 244, 255 } },
|
|
||||||
{ "Mahogany", { 192, 64, 0 } },
|
|
||||||
{ "Maize", { 251, 236, 93 } },
|
|
||||||
{ "Majorelle Blue", { 96, 80, 220 } },
|
|
||||||
{ "Malachite", { 11, 218, 81 } },
|
|
||||||
{ "Manatee", { 151, 154, 170 } },
|
|
||||||
{ "Mango Tango", { 255, 130, 67 } },
|
|
||||||
{ "Mantis", { 116, 195, 101 } },
|
|
||||||
{ "Mardi Gras", { 136, 0, 133 } },
|
|
||||||
{ "Maroon", { 128, 0, 0 } },
|
|
||||||
{ "Mauve", { 224, 176, 255 } },
|
|
||||||
{ "Mauve Taupe", { 145, 95, 109 } },
|
|
||||||
{ "Mauvelous", { 239, 152, 170 } },
|
|
||||||
{ "Maya Blue", { 115, 194, 251 } },
|
|
||||||
{ "Meat Brown", { 229, 183, 59 } },
|
|
||||||
{ "Medium Aquamarine", { 102, 221, 170 } },
|
|
||||||
{ "Medium Blue", { 0, 0, 205 } },
|
|
||||||
{ "Medium Candy Apple Red", { 226, 6, 44 } },
|
|
||||||
{ "Medium Carmine", { 175, 64, 53 } },
|
|
||||||
{ "Medium Champagne", { 243, 229, 171 } },
|
|
||||||
{ "Medium Electric Blue", { 3, 80, 150 } },
|
|
||||||
{ "Medium Jungle Green", { 28, 53, 45 } },
|
|
||||||
{ "Medium Lavender Magenta", { 221, 160, 221 } },
|
|
||||||
{ "Medium Orchid", { 186, 85, 211 } },
|
|
||||||
{ "Medium Persian Blue", { 0, 103, 165 } },
|
|
||||||
{ "Medium Purple", { 147, 112, 219 } },
|
|
||||||
{ "Medium Red-Violet", { 187, 51, 133 } },
|
|
||||||
{ "Medium Ruby", { 170, 64, 105 } },
|
|
||||||
{ "Medium Sea Green", { 60, 179, 113 } },
|
|
||||||
{ "Medium Slate Blue", { 123, 104, 238 } },
|
|
||||||
{ "Medium Spring Bud", { 201, 220, 135 } },
|
|
||||||
{ "Medium Spring Green", { 0, 250, 154 } },
|
|
||||||
{ "Medium Taupe", { 103, 76, 71 } },
|
|
||||||
{ "Medium Turquoise", { 72, 209, 204 } },
|
|
||||||
{ "Medium Tuscan Red", { 121, 68, 59 } },
|
|
||||||
{ "Medium Vermilion", { 217, 96, 59 } },
|
|
||||||
{ "Medium Violet-Red", { 199, 21, 133 } },
|
|
||||||
{ "Mellow Apricot", { 248, 184, 120 } },
|
|
||||||
{ "Mellow Yellow", { 248, 222, 126 } },
|
|
||||||
{ "Melon", { 253, 188, 180 } },
|
|
||||||
{ "Midnight Blue", { 25, 25, 112 } },
|
|
||||||
{ "Mikado Yellow", { 255, 196, 12 } },
|
|
||||||
{ "Mint", { 62, 180, 137 } },
|
|
||||||
{ "Mint Cream", { 245, 255, 250 } },
|
|
||||||
{ "Mint Green", { 152, 255, 152 } },
|
|
||||||
{ "Misty Rose", { 255, 228, 225 } },
|
|
||||||
{ "Moccasin", { 250, 235, 215 } },
|
|
||||||
{ "Mode Beige", { 150, 113, 23 } },
|
|
||||||
{ "Moonstone Blue", { 115, 169, 194 } },
|
|
||||||
{ "Mordant Red 19", { 174, 12, 0 } },
|
|
||||||
{ "Moss Green", { 173, 223, 173 } },
|
|
||||||
{ "Mountain Meadow", { 48, 186, 143 } },
|
|
||||||
{ "Mountbatten Pink", { 153, 122, 141 } },
|
|
||||||
{ "Msu Green", { 24, 69, 59 } },
|
|
||||||
{ "Mulberry", { 197, 75, 140 } },
|
|
||||||
{ "Mustard", { 255, 219, 88 } },
|
|
||||||
{ "Myrtle", { 33, 66, 30 } },
|
|
||||||
{ "Nadeshiko Pink", { 246, 173, 198 } },
|
|
||||||
{ "Napier Green", { 42, 128, 0 } },
|
|
||||||
{ "Naples Yellow", { 250, 218, 94 } },
|
|
||||||
{ "Navajo White", { 255, 222, 173 } },
|
|
||||||
{ "Navy Blue", { 0, 0, 128 } },
|
|
||||||
{ "Neon Carrot", { 255, 163, 67 } },
|
|
||||||
{ "Neon Fuchsia", { 254, 65, 100 } },
|
|
||||||
{ "Neon Green", { 57, 255, 20 } },
|
|
||||||
{ "New York Pink", { 215, 131, 127 } },
|
|
||||||
{ "Non-Photo Blue", { 164, 221, 237 } },
|
|
||||||
{ "North Texas Green", { 5, 144, 51 } },
|
|
||||||
{ "Ocean Boat Blue", { 0, 119, 190 } },
|
|
||||||
{ "Ochre", { 204, 119, 34 } },
|
|
||||||
{ "Office Green", { 0, 128, 0 } },
|
|
||||||
{ "Old Gold", { 207, 181, 59 } },
|
|
||||||
{ "Old Lace", { 253, 245, 230 } },
|
|
||||||
{ "Old Lavender", { 121, 104, 120 } },
|
|
||||||
{ "Old Mauve", { 103, 49, 71 } },
|
|
||||||
{ "Old Rose", { 192, 128, 129 } },
|
|
||||||
{ "Olive", { 128, 128, 0 } },
|
|
||||||
{ "Olivine", { 154, 185, 115 } },
|
|
||||||
{ "Onyx", { 53, 56, 57 } },
|
|
||||||
{ "Opera Mauve", { 183, 132, 167 } },
|
|
||||||
{ "Orange", { 255, 127, 0 } },
|
|
||||||
{ "Orchid", { 218, 112, 214 } },
|
|
||||||
{ "Otter Brown", { 101, 67, 33 } },
|
|
||||||
{ "Ou Crimson Red", { 153, 0, 0 } },
|
|
||||||
{ "Outer Space", { 65, 74, 76 } },
|
|
||||||
{ "Outrageous Orange", { 255, 110, 74 } },
|
|
||||||
{ "Oxford Blue", { 0, 33, 71 } },
|
|
||||||
{ "Pakistan Green", { 0, 102, 0 } },
|
|
||||||
{ "Palatinate Blue", { 39, 59, 226 } },
|
|
||||||
{ "Palatinate Purple", { 104, 40, 96 } },
|
|
||||||
{ "Pale Aqua", { 188, 212, 230 } },
|
|
||||||
{ "Pale Blue", { 175, 238, 238 } },
|
|
||||||
{ "Pale Brown", { 152, 118, 84 } },
|
|
||||||
{ "Pale Carmine", { 175, 64, 53 } },
|
|
||||||
{ "Pale Cerulean", { 155, 196, 226 } },
|
|
||||||
{ "Pale Chestnut", { 221, 173, 175 } },
|
|
||||||
{ "Pale Copper", { 218, 138, 103 } },
|
|
||||||
{ "Pale Cornflower Blue", { 171, 205, 239 } },
|
|
||||||
{ "Pale Gold", { 230, 190, 138 } },
|
|
||||||
{ "Pale Goldenrod", { 238, 232, 170 } },
|
|
||||||
{ "Pale Green", { 152, 251, 152 } },
|
|
||||||
{ "Pale Lavender", { 220, 208, 255 } },
|
|
||||||
{ "Pale Magenta", { 249, 132, 229 } },
|
|
||||||
{ "Pale Pink", { 250, 218, 221 } },
|
|
||||||
{ "Pale Plum", { 221, 160, 221 } },
|
|
||||||
{ "Pale Red-Violet", { 219, 112, 147 } },
|
|
||||||
{ "Pale Robin Egg Blue", { 150, 222, 209 } },
|
|
||||||
{ "Pale Silver", { 201, 192, 187 } },
|
|
||||||
{ "Pale Spring Bud", { 236, 235, 189 } },
|
|
||||||
{ "Pale Taupe", { 188, 152, 126 } },
|
|
||||||
{ "Pale Violet-Red", { 219, 112, 147 } },
|
|
||||||
{ "Pansy Purple", { 120, 24, 74 } },
|
|
||||||
{ "Papaya Whip", { 255, 239, 213 } },
|
|
||||||
{ "Paris Green", { 80, 200, 120 } },
|
|
||||||
{ "Pastel Blue", { 174, 198, 207 } },
|
|
||||||
{ "Pastel Brown", { 131, 105, 83 } },
|
|
||||||
{ "Pastel Gray", { 207, 207, 196 } },
|
|
||||||
{ "Pastel Green", { 119, 221, 119 } },
|
|
||||||
{ "Pastel Magenta", { 244, 154, 194 } },
|
|
||||||
{ "Pastel Orange", { 255, 179, 71 } },
|
|
||||||
{ "Pastel Pink", { 222, 165, 164 } },
|
|
||||||
{ "Pastel Purple", { 179, 158, 181 } },
|
|
||||||
{ "Pastel Red", { 255, 105, 97 } },
|
|
||||||
{ "Pastel Violet", { 203, 153, 201 } },
|
|
||||||
{ "Pastel Yellow", { 253, 253, 150 } },
|
|
||||||
{ "Patriarch", { 128, 0, 128 } },
|
|
||||||
{ "Payne'S Grey", { 83, 104, 120 } },
|
|
||||||
{ "Peach", { 255, 229, 180 } },
|
|
||||||
{ "Peach-Orange", { 255, 204, 153 } },
|
|
||||||
{ "Peach Puff", { 255, 218, 185 } },
|
|
||||||
{ "Peach-Yellow", { 250, 223, 173 } },
|
|
||||||
{ "Pear", { 209, 226, 49 } },
|
|
||||||
{ "Pearl", { 234, 224, 200 } },
|
|
||||||
{ "Pearl Aqua", { 136, 216, 192 } },
|
|
||||||
{ "Pearly Purple", { 183, 104, 162 } },
|
|
||||||
{ "Peridot", { 230, 226, 0 } },
|
|
||||||
{ "Periwinkle", { 204, 204, 255 } },
|
|
||||||
{ "Persian Blue", { 28, 57, 187 } },
|
|
||||||
{ "Persian Green", { 0, 166, 147 } },
|
|
||||||
{ "Persian Indigo", { 50, 18, 122 } },
|
|
||||||
{ "Persian Orange", { 217, 144, 88 } },
|
|
||||||
{ "Persian Pink", { 247, 127, 190 } },
|
|
||||||
{ "Persian Plum", { 112, 28, 28 } },
|
|
||||||
{ "Persian Red", { 204, 51, 51 } },
|
|
||||||
{ "Persian Rose", { 254, 40, 162 } },
|
|
||||||
{ "Persimmon", { 236, 88, 0 } },
|
|
||||||
{ "Peru", { 205, 133, 63 } },
|
|
||||||
{ "Phlox", { 223, 0, 255 } },
|
|
||||||
{ "Phthalo Blue", { 0, 15, 137 } },
|
|
||||||
{ "Phthalo Green", { 18, 53, 36 } },
|
|
||||||
{ "Piggy Pink", { 253, 221, 230 } },
|
|
||||||
{ "Pine Green", { 1, 121, 111 } },
|
|
||||||
{ "Pink", { 255, 192, 203 } },
|
|
||||||
{ "Pink Lace", { 255, 221, 244 } },
|
|
||||||
{ "Pink-Orange", { 255, 153, 102 } },
|
|
||||||
{ "Pink Pearl", { 231, 172, 207 } },
|
|
||||||
{ "Pink Sherbet", { 247, 143, 167 } },
|
|
||||||
{ "Pistachio", { 147, 197, 114 } },
|
|
||||||
{ "Platinum", { 229, 228, 226 } },
|
|
||||||
{ "Plum", { 142, 69, 133 } },
|
|
||||||
{ "Portland Orange", { 255, 90, 54 } },
|
|
||||||
{ "Powder Blue", { 176, 224, 230 } },
|
|
||||||
{ "Princeton Orange", { 255, 143, 0 } },
|
|
||||||
{ "Prune", { 112, 28, 28 } },
|
|
||||||
{ "Prussian Blue", { 0, 49, 83 } },
|
|
||||||
{ "Psychedelic Purple", { 223, 0, 255 } },
|
|
||||||
{ "Puce", { 204, 136, 153 } },
|
|
||||||
{ "Pumpkin", { 255, 117, 24 } },
|
|
||||||
{ "Purple Heart", { 105, 53, 156 } },
|
|
||||||
{ "Purple", { 128, 0, 128 } },
|
|
||||||
{ "Purple Mountain Majesty", { 150, 120, 182 } },
|
|
||||||
{ "Purple Pizzazz", { 254, 78, 218 } },
|
|
||||||
{ "Purple Taupe", { 80, 64, 77 } },
|
|
||||||
{ "Quartz", { 81, 72, 79 } },
|
|
||||||
{ "Rackley", { 93, 138, 168 } },
|
|
||||||
{ "Radical Red", { 255, 53, 94 } },
|
|
||||||
{ "Rajah", { 251, 171, 96 } },
|
|
||||||
{ "Raspberry", { 227, 11, 93 } },
|
|
||||||
{ "Raspberry Glace", { 145, 95, 109 } },
|
|
||||||
{ "Raspberry Pink", { 226, 80, 152 } },
|
|
||||||
{ "Raspberry Rose", { 179, 68, 108 } },
|
|
||||||
{ "Raw Umber", { 130, 102, 68 } },
|
|
||||||
{ "Razzle Dazzle Rose", { 255, 51, 204 } },
|
|
||||||
{ "Razzmatazz", { 227, 37, 107 } },
|
|
||||||
{ "Red", { 255, 0, 0 } },
|
|
||||||
{ "Red-Brown", { 165, 42, 42 } },
|
|
||||||
{ "Red Devil", { 134, 1, 17 } },
|
|
||||||
{ "Red-Orange", { 255, 83, 73 } },
|
|
||||||
{ "Red-Violet", { 199, 21, 133 } },
|
|
||||||
{ "Redwood", { 171, 78, 82 } },
|
|
||||||
{ "Regalia", { 82, 45, 128 } },
|
|
||||||
{ "Resolution Blue", { 0, 35, 135 } },
|
|
||||||
{ "Rich Black", { 0, 64, 64 } },
|
|
||||||
{ "Rich Brilliant Lavender", { 241, 167, 254 } },
|
|
||||||
{ "Rich Carmine", { 215, 0, 64 } },
|
|
||||||
{ "Rich Electric Blue", { 8, 146, 208 } },
|
|
||||||
{ "Rich Lavender", { 167, 107, 207 } },
|
|
||||||
{ "Rich Lilac", { 182, 102, 210 } },
|
|
||||||
{ "Rich Maroon", { 176, 48, 96 } },
|
|
||||||
{ "Rifle Green", { 65, 72, 51 } },
|
|
||||||
{ "Robin Egg Blue", { 0, 204, 204 } },
|
|
||||||
{ "Rose", { 255, 0, 127 } },
|
|
||||||
{ "Rose Bonbon", { 249, 66, 158 } },
|
|
||||||
{ "Rose Ebony", { 103, 72, 70 } },
|
|
||||||
{ "Rose Gold", { 183, 110, 121 } },
|
|
||||||
{ "Rose Madder", { 227, 38, 54 } },
|
|
||||||
{ "Rose Pink", { 255, 102, 204 } },
|
|
||||||
{ "Rose Quartz", { 170, 152, 169 } },
|
|
||||||
{ "Rose Taupe", { 144, 93, 93 } },
|
|
||||||
{ "Rose Vale", { 171, 78, 82 } },
|
|
||||||
{ "Rosewood", { 101, 0, 11 } },
|
|
||||||
{ "Rosso Corsa", { 212, 0, 0 } },
|
|
||||||
{ "Rosy Brown", { 188, 143, 143 } },
|
|
||||||
{ "Royal Azure", { 0, 56, 168 } },
|
|
||||||
{ "Royal Blue", { 0, 35, 102 } },
|
|
||||||
{ "Royal Fuchsia", { 202, 44, 146 } },
|
|
||||||
{ "Royal Purple", { 120, 81, 169 } },
|
|
||||||
{ "Royal Yellow", { 250, 218, 94 } },
|
|
||||||
{ "Rubine Red", { 209, 0, 86 } },
|
|
||||||
{ "Ruby", { 224, 17, 95 } },
|
|
||||||
{ "Ruby Red", { 155, 17, 30 } },
|
|
||||||
{ "Ruddy", { 255, 0, 40 } },
|
|
||||||
{ "Ruddy Brown", { 187, 101, 40 } },
|
|
||||||
{ "Ruddy Pink", { 225, 142, 150 } },
|
|
||||||
{ "Rufous", { 168, 28, 7 } },
|
|
||||||
{ "Russet", { 128, 70, 27 } },
|
|
||||||
{ "Rust", { 183, 65, 14 } },
|
|
||||||
{ "Rusty Red", { 218, 44, 67 } },
|
|
||||||
{ "Sacramento State Green", { 0, 86, 63 } },
|
|
||||||
{ "Saddle Brown", { 139, 69, 19 } },
|
|
||||||
{ "Safety Orange", { 255, 103, 0 } },
|
|
||||||
{ "Saffron", { 244, 196, 48 } },
|
|
||||||
{ "Salmon", { 255, 140, 105 } },
|
|
||||||
{ "Salmon Pink", { 255, 145, 164 } },
|
|
||||||
{ "Sand", { 194, 178, 128 } },
|
|
||||||
{ "Sand Dune", { 150, 113, 23 } },
|
|
||||||
{ "Sandstorm", { 236, 213, 64 } },
|
|
||||||
{ "Sandy Brown", { 244, 164, 96 } },
|
|
||||||
{ "Sandy Taupe", { 150, 113, 23 } },
|
|
||||||
{ "Sangria", { 146, 0, 10 } },
|
|
||||||
{ "Sap Green", { 80, 125, 42 } },
|
|
||||||
{ "Sapphire", { 15, 82, 186 } },
|
|
||||||
{ "Sapphire Blue", { 0, 103, 165 } },
|
|
||||||
{ "Satin Sheen Gold", { 203, 161, 53 } },
|
|
||||||
{ "Scarlet", { 255, 36, 0 } },
|
|
||||||
{ "School Bus Yellow", { 255, 216, 0 } },
|
|
||||||
{ "Screamin' Green", { 118, 255, 122 } },
|
|
||||||
{ "Sea Blue", { 0, 105, 148 } },
|
|
||||||
{ "Sea Green", { 46, 139, 87 } },
|
|
||||||
{ "Seal Brown", { 50, 20, 20 } },
|
|
||||||
{ "Seashell", { 255, 245, 238 } },
|
|
||||||
{ "Selective Yellow", { 255, 186, 0 } },
|
|
||||||
{ "Sepia", { 112, 66, 20 } },
|
|
||||||
{ "Shadow", { 138, 121, 93 } },
|
|
||||||
{ "Shamrock Green", { 0, 158, 96 } },
|
|
||||||
{ "Shocking Pink", { 252, 15, 192 } },
|
|
||||||
{ "Sienna", { 136, 45, 23 } },
|
|
||||||
{ "Silver", { 192, 192, 192 } },
|
|
||||||
{ "Sinopia", { 203, 65, 11 } },
|
|
||||||
{ "Skobeloff", { 0, 116, 116 } },
|
|
||||||
{ "Sky Blue", { 135, 206, 235 } },
|
|
||||||
{ "Sky Magenta", { 207, 113, 175 } },
|
|
||||||
{ "Slate Blue", { 106, 90, 205 } },
|
|
||||||
{ "Slate Gray", { 112, 128, 144 } },
|
|
||||||
{ "Smokey Topaz", { 147, 61, 65 } },
|
|
||||||
{ "Smoky Black", { 16, 12, 8 } },
|
|
||||||
{ "Snow", { 255, 250, 250 } },
|
|
||||||
{ "Spiro Disco Ball", { 15, 192, 252 } },
|
|
||||||
{ "Spring Bud", { 167, 252, 0 } },
|
|
||||||
{ "Spring Green", { 0, 255, 127 } },
|
|
||||||
{ "St. Patrick'S Blue", { 35, 41, 122 } },
|
|
||||||
{ "Steel Blue", { 70, 130, 180 } },
|
|
||||||
{ "Stil De Grain Yellow", { 250, 218, 94 } },
|
|
||||||
{ "Stizza", { 153, 0, 0 } },
|
|
||||||
{ "Stormcloud", { 79, 102, 106 } },
|
|
||||||
{ "Straw", { 228, 217, 111 } },
|
|
||||||
{ "Sunglow", { 255, 204, 51 } },
|
|
||||||
{ "Sunset", { 250, 214, 165 } },
|
|
||||||
{ "Tan", { 210, 180, 140 } },
|
|
||||||
{ "Tangelo", { 249, 77, 0 } },
|
|
||||||
{ "Tangerine", { 242, 133, 0 } },
|
|
||||||
{ "Tangerine Yellow", { 255, 204, 0 } },
|
|
||||||
{ "Tango Pink", { 228, 113, 122 } },
|
|
||||||
{ "Taupe", { 72, 60, 50 } },
|
|
||||||
{ "Taupe Gray", { 139, 133, 137 } },
|
|
||||||
{ "Tea Green", { 208, 240, 192 } },
|
|
||||||
{ "Teal", { 0, 128, 128 } },
|
|
||||||
{ "Teal Blue", { 54, 117, 136 } },
|
|
||||||
{ "Teal Green", { 0, 130, 127 } },
|
|
||||||
{ "Telemagenta", { 207, 52, 118 } },
|
|
||||||
{ "Terra Cotta", { 226, 114, 91 } },
|
|
||||||
{ "Thistle", { 216, 191, 216 } },
|
|
||||||
{ "Thulian Pink", { 222, 111, 161 } },
|
|
||||||
{ "Tickle Me Pink", { 252, 137, 172 } },
|
|
||||||
{ "Tiffany Blue", { 10, 186, 181 } },
|
|
||||||
{ "Tiger'S Eye", { 224, 141, 60 } },
|
|
||||||
{ "Timberwolf", { 219, 215, 210 } },
|
|
||||||
{ "Titanium Yellow", { 238, 230, 0 } },
|
|
||||||
{ "Tomato", { 255, 99, 71 } },
|
|
||||||
{ "Toolbox", { 116, 108, 192 } },
|
|
||||||
{ "Topaz", { 255, 200, 124 } },
|
|
||||||
{ "Tractor Red", { 253, 14, 53 } },
|
|
||||||
{ "Trolley Grey", { 128, 128, 128 } },
|
|
||||||
{ "Tropical Rain Forest", { 0, 117, 94 } },
|
|
||||||
{ "True Blue", { 0, 115, 207 } },
|
|
||||||
{ "Tufts Blue", { 65, 125, 193 } },
|
|
||||||
{ "Tumbleweed", { 222, 170, 136 } },
|
|
||||||
{ "Turkish Rose", { 181, 114, 129 } },
|
|
||||||
{ "Turquoise", { 48, 213, 200 } },
|
|
||||||
{ "Turquoise Blue", { 0, 255, 239 } },
|
|
||||||
{ "Turquoise Green", { 160, 214, 180 } },
|
|
||||||
{ "Tuscan Red", { 124, 72, 72 } },
|
|
||||||
{ "Twilight Lavender", { 138, 73, 107 } },
|
|
||||||
{ "Tyrian Purple", { 102, 2, 60 } },
|
|
||||||
{ "Ua Blue", { 0, 51, 170 } },
|
|
||||||
{ "Ua Red", { 217, 0, 76 } },
|
|
||||||
{ "Ube", { 136, 120, 195 } },
|
|
||||||
{ "Ucla Blue", { 83, 104, 149 } },
|
|
||||||
{ "Ucla Gold", { 255, 179, 0 } },
|
|
||||||
{ "Ufo Green", { 60, 208, 112 } },
|
|
||||||
{ "Ultra Pink", { 255, 111, 255 } },
|
|
||||||
{ "Ultramarine", { 18, 10, 143 } },
|
|
||||||
{ "Ultramarine Blue", { 65, 102, 245 } },
|
|
||||||
{ "Umber", { 99, 81, 71 } },
|
|
||||||
{ "Unbleached Silk", { 255, 221, 202 } },
|
|
||||||
{ "United Nations Blue", { 91, 146, 229 } },
|
|
||||||
{ "University Of California Gold", { 183, 135, 39 } },
|
|
||||||
{ "Unmellow Yellow", { 255, 255, 102 } },
|
|
||||||
{ "Up Forest Green", { 1, 68, 33 } },
|
|
||||||
{ "Up Maroon", { 123, 17, 19 } },
|
|
||||||
{ "Upsdell Red", { 174, 32, 41 } },
|
|
||||||
{ "Urobilin", { 225, 173, 33 } },
|
|
||||||
{ "Usafa Blue", { 0, 79, 152 } },
|
|
||||||
{ "Usc Cardinal", { 153, 0, 0 } },
|
|
||||||
{ "Usc Gold", { 255, 204, 0 } },
|
|
||||||
{ "Utah Crimson", { 211, 0, 63 } },
|
|
||||||
{ "Vanilla", { 243, 229, 171 } },
|
|
||||||
{ "Vegas Gold", { 197, 179, 88 } },
|
|
||||||
{ "Venetian Red", { 200, 8, 21 } },
|
|
||||||
{ "Verdigris", { 67, 179, 174 } },
|
|
||||||
{ "Vermilion", { 227, 66, 52 } },
|
|
||||||
{ "Veronica", { 160, 32, 240 } },
|
|
||||||
{ "Violet", { 143, 0, 255 } },
|
|
||||||
{ "Violet-Blue", { 50, 74, 178 } },
|
|
||||||
{ "Violet (Color Wheel)", { 127, 0, 255 } },
|
|
||||||
{ "Viridian", { 64, 130, 109 } },
|
|
||||||
{ "Vivid Auburn", { 146, 39, 36 } },
|
|
||||||
{ "Vivid Burgundy", { 159, 29, 53 } },
|
|
||||||
{ "Vivid Cerise", { 218, 29, 129 } },
|
|
||||||
{ "Vivid Tangerine", { 255, 160, 137 } },
|
|
||||||
{ "Vivid Violet", { 159, 0, 255 } },
|
|
||||||
{ "Warm Black", { 0, 66, 66 } },
|
|
||||||
{ "Waterspout", { 164, 244, 249 } },
|
|
||||||
{ "Wenge", { 100, 84, 82 } },
|
|
||||||
{ "Wheat", { 245, 222, 179 } },
|
|
||||||
{ "White", { 255, 255, 255 } },
|
|
||||||
{ "White Smoke", { 245, 245, 245 } },
|
|
||||||
{ "Wild Blue Yonder", { 162, 173, 208 } },
|
|
||||||
{ "Wild Strawberry", { 255, 67, 164 } },
|
|
||||||
{ "Wild Watermelon", { 252, 108, 133 } },
|
|
||||||
{ "Wine", { 114, 47, 55 } },
|
|
||||||
{ "Wine Dregs", { 103, 49, 71 } },
|
|
||||||
{ "Wisteria", { 201, 160, 220 } },
|
|
||||||
{ "Wood Brown", { 193, 154, 107 } },
|
|
||||||
{ "Xanadu", { 115, 134, 120 } },
|
|
||||||
{ "Yale Blue", { 15, 77, 146 } },
|
|
||||||
{ "Yellow", { 255, 255, 0 } },
|
|
||||||
{ "Yellow-Green", { 154, 205, 50 } },
|
|
||||||
{ "Yellow Orange", { 255, 174, 66 } },
|
|
||||||
{ "Zaffre", { 0, 20, 168 } },
|
|
||||||
{ "Zinnwaldite Brown", { 44, 22, 8 } },
|
|
||||||
#endif
|
|
||||||
{0, {0, 0, 0}},
|
|
||||||
};
|
|
||||||
|
|
||||||
ColorInfo colorForName(const char *name) {
|
|
||||||
String needleName(name);
|
|
||||||
needleName.toLowerCase();
|
|
||||||
for (int i = 0; color_data[i].name != 0; i++) {
|
|
||||||
String colorName(color_data[i].name);
|
|
||||||
colorName.toLowerCase();
|
|
||||||
if (colorName == needleName) {
|
|
||||||
return color_data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ColorInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ColorInfo* allColors() {
|
|
||||||
return color_data;
|
|
||||||
}
|
|
10
src/colors.h
10
src/colors.h
@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <FastLED.h>
|
|
||||||
|
|
||||||
typedef struct ColorInfo {
|
|
||||||
const char *name;
|
|
||||||
CRGB rgb;
|
|
||||||
} ColorInfo;
|
|
||||||
|
|
||||||
ColorInfo colorForName(const char *name);
|
|
||||||
const ColorInfo* allColors();
|
|
@ -2,19 +2,19 @@
|
|||||||
#include "../Static.h"
|
#include "../Static.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
doBPM(Args& args, Print& out)
|
BPM::doSetBPM(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
uint8_t newBPM(atoi(args[1].c_str()));
|
uint8_t newBPM(atoi(args[1].c_str()));
|
||||||
Static<BPM>::instance()->setBPM(newBPM);
|
setBPM(newBPM);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Command> _commands = {
|
|
||||||
{"bpm", doBPM}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
const std::vector<Command>&
|
||||||
BPM::commands() const
|
BPM::commands() const
|
||||||
{
|
{
|
||||||
|
static const std::vector<Command> _commands = {
|
||||||
|
{"bpm", &BPM::doSetBPM}
|
||||||
|
};
|
||||||
return _commands;
|
return _commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,4 +77,6 @@ private:
|
|||||||
uint16_t trash;
|
uint16_t trash;
|
||||||
m_timings.take(trash);
|
m_timings.take(trash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void doSetBPM(Args& args, Print& print);
|
||||||
};
|
};
|
||||||
|
@ -31,7 +31,7 @@ Buttons::read()
|
|||||||
//Log.info("Not emitting release from previous chord");
|
//Log.info("Not emitting release from previous chord");
|
||||||
m_wasChord[i] = false;
|
m_wasChord[i] = false;
|
||||||
} else {
|
} else {
|
||||||
return InputEvent{InputEvent::UserInput, buttonID};
|
return InputEvent{InputEvent::ButtonPress, buttonID};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,14 +10,14 @@ struct ScheduleEntry {
|
|||||||
std::array<ScheduleEntry, 10> schedule{{
|
std::array<ScheduleEntry, 10> schedule{{
|
||||||
{0, 0},
|
{0, 0},
|
||||||
{5, 0},
|
{5, 0},
|
||||||
{6, 0},
|
{6, 10},
|
||||||
{7, 10},
|
{7, 20},
|
||||||
{8, 80},
|
{8, 80},
|
||||||
{11, 120},
|
{11, 120},
|
||||||
{18, 200},
|
{18, 200},
|
||||||
{19, 255},
|
{19, 255},
|
||||||
{22, 120},
|
{22, 120},
|
||||||
{23, 20}
|
{23, 5}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
class CircadianRhythm : public InputSource {
|
class CircadianRhythm : public InputSource {
|
||||||
@ -37,14 +37,9 @@ class CircadianRhythm : public InputSource {
|
|||||||
// Find the last hour that is prior to or equal to now
|
// Find the last hour that is prior to or equal to now
|
||||||
if (cur.hour <= hour) {
|
if (cur.hour <= hour) {
|
||||||
start = cur;
|
start = cur;
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(ScheduleEntry cur : schedule) {
|
|
||||||
// Find the first hour that is after now
|
// Find the first hour that is after now
|
||||||
// If no such hour exists, we should automatically wrap back to hour 0
|
// If no such hour exists, we should automatically wrap back to hour 0
|
||||||
if (cur.hour > hour) {
|
} else if (cur.hour > hour) {
|
||||||
end = cur;
|
end = cur;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -83,9 +78,9 @@ class CircadianRhythm : public InputSource {
|
|||||||
hour = 0;
|
hour = 0;
|
||||||
minute = 0;
|
minute = 0;
|
||||||
}
|
}
|
||||||
Log.notice("Current time: %d:%d", hour, minute);
|
Log.notice(F("Current time: %d:%d"), hour, minute);
|
||||||
auto brightness = brightnessForTime(hour, minute);
|
auto brightness = brightnessForTime(hour, minute);
|
||||||
Log.notice("Adjusting brightness to %d", brightness);
|
Log.notice(F("Adjusting brightness to %d"), brightness);
|
||||||
return InputEvent{InputEvent::SetBrightness, brightness};
|
return InputEvent{InputEvent::SetBrightness, brightness};
|
||||||
}
|
}
|
||||||
return InputEvent{};
|
return InputEvent{};
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
#include "./ConfigInput.h"
|
|
||||||
#include "./Static.h"
|
|
||||||
|
|
||||||
STATIC_ALLOC(ConfigInput);
|
|
||||||
STATIC_TASK(ConfigInput);
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
41
src/inputs/Idle.cpp
Normal file
41
src/inputs/Idle.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "Idle.h"
|
||||||
|
#include "../Static.h"
|
||||||
|
|
||||||
|
IdleTimer::IdleTimer()
|
||||||
|
: InputSource("IdleTimer"),
|
||||||
|
m_idleTime(60), m_secondsRemaining(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InputEvent
|
||||||
|
IdleTimer::read()
|
||||||
|
{
|
||||||
|
EVERY_N_SECONDS(1) {
|
||||||
|
if (m_secondsRemaining > 0) {
|
||||||
|
m_secondsRemaining -= 1;
|
||||||
|
if (m_secondsRemaining == 0) {
|
||||||
|
return InputEvent::IdleStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return InputEvent::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IdleTimer::handleEvent(const InputEvent& evt)
|
||||||
|
{
|
||||||
|
switch(evt.intent) {
|
||||||
|
case InputEvent::IdleStart:
|
||||||
|
m_secondsRemaining = 0;
|
||||||
|
break;
|
||||||
|
case InputEvent::IdleStop:
|
||||||
|
m_secondsRemaining = m_idleTime;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_ALLOC(IdleTimer);
|
||||||
|
STATIC_TASK(IdleTimer);
|
12
src/inputs/Idle.h
Normal file
12
src/inputs/Idle.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Figments.h>
|
||||||
|
|
||||||
|
class IdleTimer : public InputSource {
|
||||||
|
public:
|
||||||
|
IdleTimer();
|
||||||
|
void handleEvent(const InputEvent& evt);
|
||||||
|
virtual InputEvent read() override;
|
||||||
|
private:
|
||||||
|
uint16_t m_idleTime;
|
||||||
|
uint16_t m_secondsRemaining;
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
|
#ifdef CONFIG_MPU6050
|
||||||
#include "MPU6050.h"
|
#include "MPU6050.h"
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include "../Config.h"
|
#include "../Config.h"
|
||||||
@ -64,3 +65,4 @@ MPU5060::read()
|
|||||||
|
|
||||||
STATIC_ALLOC(MPU5060);
|
STATIC_ALLOC(MPU5060);
|
||||||
STATIC_TASK(MPU5060);
|
STATIC_TASK(MPU5060);
|
||||||
|
#endif
|
||||||
|
@ -126,7 +126,7 @@ SerialInput::read()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
doHelp(Args& args, Print& out)
|
SerialInput::doHelp(Args& args, Print& out)
|
||||||
{
|
{
|
||||||
out.println("Available commands:");
|
out.println("Available commands:");
|
||||||
auto sched = MainLoop::instance()->scheduler;
|
auto sched = MainLoop::instance()->scheduler;
|
||||||
@ -139,14 +139,13 @@ doHelp(Args& args, Print& out)
|
|||||||
out.println();
|
out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<Command> serialCommands = {
|
|
||||||
{"help", doHelp}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::vector<Command>&
|
const std::vector<Command>&
|
||||||
SerialInput::commands() const
|
SerialInput::commands() const
|
||||||
{
|
{
|
||||||
return serialCommands;
|
static const std::vector<Command> _commands = {
|
||||||
|
{"help", &SerialInput::doHelp}
|
||||||
|
};
|
||||||
|
return _commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -158,7 +157,7 @@ SerialInput::doCommand() {
|
|||||||
for(auto task : sched.tasks) {
|
for(auto task : sched.tasks) {
|
||||||
for(auto &command : task->commands()) {
|
for(auto &command : task->commands()) {
|
||||||
if (cmdName == command.name) {
|
if (cmdName == command.name) {
|
||||||
command.func(args, m_logPrinter);
|
command.invoke(task, args, m_logPrinter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,18 @@ private:
|
|||||||
EscapeSequence,
|
EscapeSequence,
|
||||||
CSI
|
CSI
|
||||||
};
|
};
|
||||||
|
|
||||||
String m_buf;
|
String m_buf;
|
||||||
ParseState m_state;
|
ParseState m_state;
|
||||||
char m_escapeSeq[3];
|
|
||||||
void doCommand();
|
|
||||||
LogPrinter m_logPrinter;
|
LogPrinter m_logPrinter;
|
||||||
bool m_canRedraw = true;
|
bool m_canRedraw = true;
|
||||||
Ringbuf<String, 5> m_history;
|
Ringbuf<String, 5> m_history;
|
||||||
int m_historyOffset = 0;
|
int m_historyOffset = 0;
|
||||||
|
|
||||||
|
void doCommand();
|
||||||
InputEvent parseNormal(char nextChar);
|
InputEvent parseNormal(char nextChar);
|
||||||
InputEvent parseEscape(char nextChar);
|
InputEvent parseEscape(char nextChar);
|
||||||
InputEvent parseCSI(char nextChar);
|
InputEvent parseCSI(char nextChar);
|
||||||
|
|
||||||
|
void doHelp(Args& args, Print& out);
|
||||||
};
|
};
|
||||||
|
46
src/main.cpp
46
src/main.cpp
@ -34,28 +34,6 @@ Display dpy(leds, HardwareConfig::MAX_LED_NUM, Static<ConfigService>::instance()
|
|||||||
}
|
}
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
InputMapper keyMap([](const InputEvent& evt) {
|
|
||||||
if (evt.intent == InputEvent::UserInput) {
|
|
||||||
Buttons::Chord chord = (Buttons::Chord)evt.asInt();
|
|
||||||
switch(chord) {
|
|
||||||
case Buttons::Circle:
|
|
||||||
return InputEvent::PowerToggle;
|
|
||||||
break;
|
|
||||||
case Buttons::Triangle:
|
|
||||||
return InputEvent::NextPattern;
|
|
||||||
break;
|
|
||||||
case Buttons::Cross:
|
|
||||||
return InputEvent::UserInput;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return InputEvent::None;
|
|
||||||
}, "Keymap");
|
|
||||||
|
|
||||||
REGISTER_TASK(keyMap);
|
|
||||||
|
|
||||||
// Cycle some random colors
|
// Cycle some random colors
|
||||||
ColorSequenceInput<9> idleCycle{{
|
ColorSequenceInput<9> idleCycle{{
|
||||||
CRGB(0, 123, 167), // Cerulean
|
CRGB(0, 123, 167), // Cerulean
|
||||||
@ -83,24 +61,24 @@ MainLoop* runner = &SafeMode::safeModeApp;
|
|||||||
void setup() {
|
void setup() {
|
||||||
// Turn on,
|
// Turn on,
|
||||||
Platform::preSetup();
|
Platform::preSetup();
|
||||||
Log.notice(u8"🐛 Booting Renderbug!");
|
Log.notice(F(u8"\n\n\n🐛 Booting Renderbug!"));
|
||||||
Log.notice(u8"🐞 I am built for %d LEDs on pin %d", HardwareConfig::MAX_LED_NUM, RENDERBUG_LED_PIN);
|
Log.notice(F(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(F(u8"📡 Platform %s version %s"), Platform::name(), Platform::version());
|
||||||
|
|
||||||
Log.notice(u8"Setting timezone to +2 (CEST)");
|
Log.notice(F(u8"Setting timezone to +2 (CEST)"));
|
||||||
Platform::setTimezone(+2);
|
Platform::setTimezone(+1);
|
||||||
|
|
||||||
Log.trace(u8"Setting up platform...");
|
Log.trace(F(u8"Setting up platform..."));
|
||||||
|
|
||||||
Platform::setup();
|
Platform::setup();
|
||||||
Platform::bootSplash();
|
Platform::bootSplash();
|
||||||
|
|
||||||
Log.notice(u8"💡 Starting FastLED on %d LEDs...", HardwareConfig::MAX_LED_NUM);
|
Log.notice(F(u8"💡 Starting FastLED on %d LEDs..."), HardwareConfig::MAX_LED_NUM);
|
||||||
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.warning(F(u8"⚠️ Starting Figment in safe mode!!!"));
|
||||||
runner = &SafeMode::safeModeApp;
|
runner = &SafeMode::safeModeApp;
|
||||||
for(auto task : runner->scheduler.tasks) {
|
for(auto task : runner->scheduler.tasks) {
|
||||||
task->state = Task::Running;
|
task->state = Task::Running;
|
||||||
@ -108,10 +86,10 @@ void setup() {
|
|||||||
FastLED.showColor(CRGB(255, 0, 0));
|
FastLED.showColor(CRGB(255, 0, 0));
|
||||||
FastLED.show();
|
FastLED.show();
|
||||||
} else {
|
} else {
|
||||||
Log.notice(u8"🌌 Starting Figment...");
|
Log.notice(F(u8"🌌 Starting Figment..."));
|
||||||
|
|
||||||
if (Platform::bootopts.isSetup) {
|
if (Platform::bootopts.isSetup) {
|
||||||
Log.warning(u8"🔧 Booting up into setup profile!!!");
|
Log.warning(F(u8"🔧 Booting up into setup profile!!!"));
|
||||||
Static<ConfigService>::instance()->overrideProfile("setup");
|
Static<ConfigService>::instance()->overrideProfile("setup");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,8 +102,8 @@ void setup() {
|
|||||||
Serial.flush();
|
Serial.flush();
|
||||||
runner->start();
|
runner->start();
|
||||||
|
|
||||||
Log.notice(u8"💽 %l bytes of free RAM", Platform::freeRam());
|
Log.notice(F(u8"💽 %l bytes of free RAM"), Platform::freeRam());
|
||||||
Log.notice(u8"🚀 Setup complete! Ready to rock and roll.");
|
Log.notice(F(u8"🚀 Setup complete! Ready to rock and roll."));
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
#include "MQTTTelemetry.h"
|
#include "MQTTTelemetry.h"
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#include <StreamUtils.h>
|
||||||
|
|
||||||
#include "../../Static.h"
|
#include "../../Static.h"
|
||||||
#include "../../Config.h"
|
#include "../../Config.h"
|
||||||
#include "../../Platform.h"
|
#include "../../Platform.h"
|
||||||
|
|
||||||
StaticJsonDocument<1024> m_json;
|
static StaticJsonDocument<1024> m_json;
|
||||||
|
|
||||||
struct MQTTDevice {
|
struct MQTTDevice {
|
||||||
const String id;
|
const String id;
|
||||||
@ -31,7 +32,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,8 +96,8 @@ const MQTTEntity Lightswitch {
|
|||||||
"light", Device, "lightswitch"
|
"light", Device, "lightswitch"
|
||||||
};
|
};
|
||||||
|
|
||||||
const MQTTEntity flashlightSwitch {
|
const MQTTEntity IdleSwitch {
|
||||||
"switch", Device, "flashlight"
|
"switch", Device, "idle"
|
||||||
};
|
};
|
||||||
|
|
||||||
const MQTTEntity FPSSensor {
|
const MQTTEntity FPSSensor {
|
||||||
@ -112,11 +113,29 @@ MQTTTelemetry::MQTTTelemetry() : BufferedInputSource("MQTT"),
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MQTTTelemetry::handleEventOnline(const InputEvent& evt)
|
MQTTTelemetry::publishScenes()
|
||||||
|
{
|
||||||
|
for(auto scene : Static<Sequencer>::instance()->scenes()) {
|
||||||
|
m_json.clear();
|
||||||
|
String strName{scene.name};
|
||||||
|
MQTTEntity sceneObj {
|
||||||
|
"scene",
|
||||||
|
Device,
|
||||||
|
strName
|
||||||
|
};
|
||||||
|
sceneObj.toJson(m_json, false);
|
||||||
|
m_json["cmd_t"] = "~/set";
|
||||||
|
m_json["ret"] = false;
|
||||||
|
m_json["payload_on"] = "active";
|
||||||
|
publishDoc(sceneObj.configTopic().c_str(), false);
|
||||||
|
m_mqtt.subscribe(sceneObj.commandTopic().c_str());
|
||||||
|
Log.info("Published scene %s", sceneObj.configTopic().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MQTTTelemetry::onMQTTOnline()
|
||||||
{
|
{
|
||||||
if (!m_mqtt.connected()) {
|
|
||||||
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")) {
|
|
||||||
Log.notice("Connected to MQTT");
|
Log.notice("Connected to MQTT");
|
||||||
String logTopic = m_debugTopic + "/log";
|
String logTopic = m_debugTopic + "/log";
|
||||||
Log.info("MQTT logs are available at %s", logTopic.c_str());
|
Log.info("MQTT logs are available at %s", logTopic.c_str());
|
||||||
@ -124,38 +143,26 @@ 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());
|
||||||
|
|
||||||
m_json.clear();
|
m_json.clear();
|
||||||
flashlightSwitch.toJson(m_json, false);
|
IdleSwitch.toJson(m_json);
|
||||||
m_json["cmd_t"] = "~/set";
|
|
||||||
m_json["ret"] = true;
|
publishDoc(IdleSwitch.configTopic().c_str(), true);
|
||||||
publishDoc(flashlightSwitch.configTopic().c_str(), true);
|
m_mqtt.subscribe(IdleSwitch.commandTopic().c_str());
|
||||||
//m_mqtt.publish(flashlightSwitch.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
|
||||||
m_mqtt.subscribe(flashlightSwitch.commandTopic().c_str());
|
publishScenes();
|
||||||
|
|
||||||
m_json.clear();
|
m_json.clear();
|
||||||
FPSSensor.toJson(m_json, false);
|
FPSSensor.toJson(m_json, false);
|
||||||
m_json["unit_of_meas"] = "Frames/s";
|
m_json["unit_of_meas"] = "Frames/s";
|
||||||
publishDoc(FPSSensor.configTopic().c_str(), true);
|
publishDoc(FPSSensor.configTopic().c_str(), true);
|
||||||
|
|
||||||
//Log.verbose("Publish %s %s", FPSSensor.configTopic().c_str(), buf);
|
#ifdef ESP8266
|
||||||
//m_mqtt.publish(FPSSensor.configTopic().c_str(), (uint8_t*)buf, strlen(buf), true);
|
|
||||||
m_mqtt.subscribe(FPSSensor.commandTopic().c_str());
|
|
||||||
|
|
||||||
#ifdef BOARD_ESP8266
|
|
||||||
struct rst_info resetInfo = *ESP.getResetInfoPtr();
|
struct rst_info resetInfo = *ESP.getResetInfoPtr();
|
||||||
if (resetInfo.reason != 0) {
|
if (resetInfo.reason != 0) {
|
||||||
char buff[200];
|
char buff[200];
|
||||||
@ -163,18 +170,22 @@ MQTTTelemetry::handleEventOnline(const InputEvent& evt)
|
|||||||
Log.warning("Previous crash detected! %s", buff);
|
Log.warning("Previous crash detected! %s", buff);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MQTTTelemetry::handleEventOnline(const InputEvent& evt)
|
||||||
|
{
|
||||||
|
if (!m_mqtt.connected()) {
|
||||||
|
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")) {
|
||||||
|
onMQTTOnline();
|
||||||
} else {
|
} else {
|
||||||
Log.warning("Could not connect to MQTT");
|
Log.warning("Could not connect to MQTT");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String statTopic = Lightswitch.statTopic();
|
String statTopic = Lightswitch.statTopic();
|
||||||
if (evt.intent == InputEvent::StopThing && String(evt.asString()) == "Flashlight") {
|
String idleTopic = IdleSwitch.statTopic();
|
||||||
String flashlightStatTopic = flashlightSwitch.statTopic();
|
if (evt.intent == InputEvent::SetPower) {
|
||||||
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,11 +203,18 @@ 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["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::IdleStart) {
|
||||||
|
m_json.clear();
|
||||||
|
m_json["state"] = "ON";
|
||||||
|
publishDoc(idleTopic.c_str());
|
||||||
|
} else if (evt.intent == InputEvent::IdleStop) {
|
||||||
|
m_json.clear();
|
||||||
|
m_json["state"] = "OFF";
|
||||||
|
publishDoc(idleTopic.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,42 +273,37 @@ MQTTTelemetry::loopOnline()
|
|||||||
m_needHeartbeat = true;
|
m_needHeartbeat = true;
|
||||||
}
|
}
|
||||||
if (m_needHeartbeat) {
|
if (m_needHeartbeat) {
|
||||||
m_json.clear();
|
publishHeartbeat();
|
||||||
m_json["device_id"] = Platform::deviceID();
|
|
||||||
m_json["sketch_version"] = ESP.getSketchMD5();
|
|
||||||
m_json["os_version"] = ESP.getSdkVersion();
|
|
||||||
m_json["localip"] = WiFi.localIP().toString();
|
|
||||||
m_json["pixelCount"] = Static<ConfigService>::instance()->coordMap()->physicalPixelCount();
|
|
||||||
m_json["loadedProfile"] = Static<ConfigService>::instance()->loadedProfile();
|
|
||||||
m_json["RSSI"] = WiFi.RSSI();
|
|
||||||
m_json["free_ram"] = ESP.getFreeHeap();
|
|
||||||
m_json["fps"] = FastLED.getFPS();
|
|
||||||
String availTopic = m_rootTopic + "/available";
|
|
||||||
publishDoc(Lightswitch.heartbeatTopic().c_str());
|
|
||||||
m_mqtt.publish(Device.availabilityTopic.c_str(), "online");
|
|
||||||
|
|
||||||
String fpsCounter = String(FastLED.getFPS());
|
|
||||||
m_mqtt.publish(FPSSensor.statTopic().c_str(), fpsCounter.c_str());
|
|
||||||
|
|
||||||
m_needHeartbeat = false;
|
m_needHeartbeat = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MQTTTelemetry::publishHeartbeat()
|
||||||
|
{
|
||||||
|
m_json.clear();
|
||||||
|
m_json["device_id"] = Platform::deviceID();
|
||||||
|
m_json["sketch_version"] = ESP.getSketchMD5();
|
||||||
|
m_json["os_version"] = Platform::version();
|
||||||
|
m_json["localip"] = WiFi.localIP().toString();
|
||||||
|
m_json["pixelCount"] = Static<ConfigService>::instance()->coordMap()->physicalPixelCount();
|
||||||
|
m_json["loadedProfile"] = Static<ConfigService>::instance()->loadedProfile();
|
||||||
|
m_json["RSSI"] = WiFi.RSSI();
|
||||||
|
m_json["free_ram"] = Platform::freeRam();
|
||||||
|
m_json["fps"] = FastLED.getFPS();
|
||||||
|
publishDoc(Lightswitch.heartbeatTopic().c_str());
|
||||||
|
m_mqtt.publish(Device.availabilityTopic.c_str(), "online");
|
||||||
|
|
||||||
|
String fpsCounter = String(FastLED.getFPS());
|
||||||
|
m_mqtt.publish(FPSSensor.statTopic().c_str(), fpsCounter.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MQTTTelemetry::callback(char* topic, const char* payload)
|
MQTTTelemetry::callback(char* topic, const char* payload)
|
||||||
{
|
{
|
||||||
|
Log.notice("MQTT: %s", topic);
|
||||||
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,62 +312,11 @@ 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::IdleStart);
|
||||||
setEvent(InputEvent{InputEvent::SetPower, false});
|
setEvent(InputEvent{InputEvent::SetPower, false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_json.containsKey("start")) {
|
|
||||||
strcpy(m_patternBuf, m_json["start"].as<const char*>());
|
|
||||||
setEvent(InputEvent{InputEvent::StartThing, m_patternBuf});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("stop")) {
|
|
||||||
if (m_json["stop"] == name) {
|
|
||||||
Log.warning("You can't kill an idea, or stop the MQTT Task via MQTT.");
|
|
||||||
} else {
|
|
||||||
strcpy(m_patternBuf, m_json["stop"].as<const char*>());
|
|
||||||
setEvent(InputEvent{InputEvent::StopThing, m_patternBuf});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("pixelCount")) {
|
|
||||||
Log.notice("Pixel count changed");
|
|
||||||
setEvent(InputEvent{InputEvent::SetDisplayLength, m_json["pixelCount"].as<int>()});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("startPixel")) {
|
|
||||||
Log.notice("Start pixel changed");
|
|
||||||
setEvent(InputEvent{InputEvent::SetDisplayOffset, m_json["startPixel"].as<int>()});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("loadConfig")) {
|
|
||||||
Log.notice("Loading new config");
|
|
||||||
setEvent(InputEvent{InputEvent::LoadConfigurationByName, m_json["loadConfig"].as<const char*>()});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("save")) {
|
|
||||||
setEvent(InputEvent{InputEvent::SaveConfigurationRequest});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("restart")) {
|
|
||||||
Platform::restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("reconnect")) {
|
|
||||||
m_mqtt.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("ping")) {
|
|
||||||
m_needHeartbeat = true;
|
|
||||||
Log.notice("Queuing up heartbeat");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("effect")) {
|
|
||||||
strcpy(m_patternBuf, m_json["effect"].as<const char*>());
|
|
||||||
setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_json.containsKey("color")) {
|
if (m_json.containsKey("color")) {
|
||||||
uint8_t r = m_json["color"]["r"];
|
uint8_t r = m_json["color"]["r"];
|
||||||
uint8_t g = m_json["color"]["g"];
|
uint8_t g = m_json["color"]["g"];
|
||||||
@ -366,7 +328,26 @@ MQTTTelemetry::callback(char* topic, const char* payload)
|
|||||||
setEvent(InputEvent{InputEvent::SetBrightness, m_json["brightness"].as<int>()});
|
setEvent(InputEvent{InputEvent::SetBrightness, m_json["brightness"].as<int>()});
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.notice("Event done.");
|
} else if (IdleSwitch.isCommandTopic(topic)) {
|
||||||
|
if (strcmp(payload, "ON") == 0) {
|
||||||
|
Log.notice("Activating idle switch");
|
||||||
|
setEvent(InputEvent::IdleStart);
|
||||||
|
} else if (strcmp(payload, "OFF") == 0) {
|
||||||
|
Log.notice("Deactivating idle switch");
|
||||||
|
setEvent(InputEvent::IdleStop);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(auto scene : Static<Sequencer>::instance()->scenes()) {
|
||||||
|
MQTTEntity sceneObj {
|
||||||
|
"scene",
|
||||||
|
Device,
|
||||||
|
scene.name
|
||||||
|
};
|
||||||
|
if (sceneObj.isCommandTopic(topic)) {
|
||||||
|
setEvent(InputEvent{InputEvent::SetScene, scene.name.c_str()});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +367,9 @@ void
|
|||||||
MQTTTelemetry::publishDoc(const char* topic, bool retain)
|
MQTTTelemetry::publishDoc(const char* topic, bool retain)
|
||||||
{
|
{
|
||||||
m_mqtt.beginPublish(topic, measureJson(m_json), retain);
|
m_mqtt.beginPublish(topic, measureJson(m_json), retain);
|
||||||
serializeJson(m_json, m_mqtt);
|
BufferingPrint buf(m_mqtt, 64);
|
||||||
|
serializeJson(m_json, buf);
|
||||||
|
buf.flush();
|
||||||
m_mqtt.endPublish();
|
m_mqtt.endPublish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -73,6 +73,10 @@ class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin, ConfigTaskMix
|
|||||||
void publishDoc(const char* topic);
|
void publishDoc(const char* topic);
|
||||||
void publishDoc(const char* topic, bool retain);
|
void publishDoc(const char* topic, bool retain);
|
||||||
|
|
||||||
|
void onMQTTOnline();
|
||||||
|
void publishScenes();
|
||||||
|
void publishHeartbeat();
|
||||||
|
|
||||||
Sequencer *m_sequencer = 0;
|
Sequencer *m_sequencer = 0;
|
||||||
WiFiClient m_wifi;
|
WiFiClient m_wifi;
|
||||||
PubSubClient m_mqtt;
|
PubSubClient m_mqtt;
|
||||||
|
@ -4,10 +4,13 @@
|
|||||||
ArduinoOTAUpdater::ArduinoOTAUpdater() : BufferedInputSource("ArduinoOTA") {
|
ArduinoOTAUpdater::ArduinoOTAUpdater() : BufferedInputSource("ArduinoOTA") {
|
||||||
ArduinoOTA.onStart(&ArduinoOTAUpdater::s_onStart);
|
ArduinoOTA.onStart(&ArduinoOTAUpdater::s_onStart);
|
||||||
ArduinoOTA.onProgress(&ArduinoOTAUpdater::s_onProgress);
|
ArduinoOTA.onProgress(&ArduinoOTAUpdater::s_onProgress);
|
||||||
|
ArduinoOTA.onError(&ArduinoOTAUpdater::s_onError);
|
||||||
|
ArduinoOTA.onEnd(&ArduinoOTAUpdater::s_onFinished);
|
||||||
|
ArduinoOTA.setRebootOnSuccess(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoOTAUpdater::loop() {
|
void ArduinoOTAUpdater::loop() {
|
||||||
if (m_online) {
|
if (m_online && !m_updating) {
|
||||||
ArduinoOTA.handle();
|
ArduinoOTA.handle();
|
||||||
}
|
}
|
||||||
BufferedInputSource::loop();
|
BufferedInputSource::loop();
|
||||||
@ -20,14 +23,32 @@ void ArduinoOTAUpdater::handleEvent(const InputEvent& evt) {
|
|||||||
ArduinoOTA.begin();
|
ArduinoOTA.begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArduinoOTAUpdater::s_onFinished()
|
||||||
|
{
|
||||||
|
Log.notice("OTA complete!");
|
||||||
|
Static<ArduinoOTAUpdater>::instance()->m_updating = false;
|
||||||
|
Platform::restart();
|
||||||
|
}
|
||||||
|
|
||||||
void ArduinoOTAUpdater::s_onStart() {
|
void ArduinoOTAUpdater::s_onStart() {
|
||||||
Log.notice("OTA Start!");
|
Log.notice("OTA Start!");
|
||||||
|
Static<ArduinoOTAUpdater>::instance()->m_updating = true;
|
||||||
Static<ArduinoOTAUpdater>::instance()->setEvent(InputEvent::FirmwareUpdate);
|
Static<ArduinoOTAUpdater>::instance()->setEvent(InputEvent::FirmwareUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArduinoOTAUpdater::s_onError(ota_error_t err)
|
||||||
|
{
|
||||||
|
Log.notice("OTA failure: %d", (int)err);
|
||||||
|
Static<ArduinoOTAUpdater>::instance()->m_updating = false;
|
||||||
|
}
|
||||||
|
|
||||||
void ArduinoOTAUpdater::s_onProgress(unsigned int progress, unsigned int total) {
|
void ArduinoOTAUpdater::s_onProgress(unsigned int progress, unsigned int total) {
|
||||||
Log.notice("OTA Progress! %d / %d", progress, total);
|
Log.notice("OTA Progress! %d / %d", progress, total);
|
||||||
Static<ArduinoOTAUpdater>::instance()->setEvent(InputEvent{InputEvent::FirmwareUpdate, progress});
|
Static<ArduinoOTAUpdater>::instance()->setEvent(InputEvent{InputEvent::FirmwareUpdate, progress});
|
||||||
|
// Try to run the main loop in case we're not in a threaded updater
|
||||||
|
// environment. This keeps rendering running, and pets the watchdog.
|
||||||
|
MainLoop::instance()->loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC_ALLOC(ArduinoOTAUpdater);
|
STATIC_ALLOC(ArduinoOTAUpdater);
|
||||||
|
@ -9,6 +9,9 @@ class ArduinoOTAUpdater : public BufferedInputSource {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_online = false;
|
bool m_online = false;
|
||||||
|
bool m_updating = false;
|
||||||
static void s_onStart();
|
static void s_onStart();
|
||||||
static void s_onProgress(unsigned int progress, unsigned int total);
|
static void s_onProgress(unsigned int progress, unsigned int total);
|
||||||
|
static void s_onError(ota_error_t err);
|
||||||
|
static void s_onFinished();
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
#include <Input.h>
|
#include <Input.h>
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
|
|
||||||
#ifdef BOARD_ESP8266
|
#ifdef ESP8266
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef BOARD_ESP32
|
#ifdef ESP32
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
#include "ESPmDNS.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Static.h"
|
#include "Static.h"
|
||||||
#include "WiFiTask.h"
|
#include "WiFiTask.h"
|
||||||
|
|
||||||
@ -18,6 +21,11 @@ WiFiTask::onStart()
|
|||||||
Log.notice("Starting wifi...");
|
Log.notice("Starting wifi...");
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin("The Frequency", "thepasswordkenneth");
|
WiFi.begin("The Frequency", "thepasswordkenneth");
|
||||||
|
if (MDNS.begin(Platform::deviceHostname().c_str())) {
|
||||||
|
Log.notice("mDNS started with hostname %s", Platform::deviceHostname().c_str());
|
||||||
|
} else {
|
||||||
|
Log.error("mDNS failed to start!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputEvent
|
InputEvent
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
#if 0
|
||||||
#include "BluetoothSerialTelemetry.h"
|
#include "BluetoothSerialTelemetry.h"
|
||||||
#include "../../Static.h"
|
#include "../../../Static.h"
|
||||||
#include "../../Platform.h"
|
#include "../../../Platform.h"
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
#include "../../inputs/Buttons.h"
|
#include "../../../inputs/Buttons.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
@ -91,3 +92,4 @@ BluetoothSerialTelemetry::onStart()
|
|||||||
|
|
||||||
STATIC_ALLOC(BluetoothSerialTelemetry);
|
STATIC_ALLOC(BluetoothSerialTelemetry);
|
||||||
STATIC_TASK(BluetoothSerialTelemetry);
|
STATIC_TASK(BluetoothSerialTelemetry);
|
||||||
|
#endif
|
133
src/platform/arduino/esp32/Platform.cpp
Normal file
133
src/platform/arduino/esp32/Platform.cpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#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>::forceSafeMode()
|
||||||
|
{
|
||||||
|
s_forceSafeMode = SAFE_MODE_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
PlatformImpl<HAL_ESP32>::bootSplash()
|
||||||
|
{
|
||||||
|
Log.trace("ESP32 startup reason: %d", Platform::bootopts.resetReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
PlatformImpl<HAL_ESP32>::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_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.
|
||||||
|
opts.isSafeMode = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opts.crashCount = 0;
|
||||||
|
}
|
||||||
|
s_rebootCount = opts.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()
|
||||||
|
{
|
||||||
|
static char s_deviceID[15];
|
||||||
|
uint64_t 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));
|
||||||
|
timedata->tm_hour += timezone;
|
||||||
|
return (timedata->tm_year > (2016-1990));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
PlatformImpl<HAL_ESP32>::restart()
|
||||||
|
{
|
||||||
|
ESP.restart();
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
|
#ifdef CONFIG_U8DISPLAY
|
||||||
#include <Figments.h>
|
#include <Figments.h>
|
||||||
#include <U8g2lib.h>
|
#include <U8g2lib.h>
|
||||||
#include "../../Static.h"
|
#include "../../../Static.h"
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
#include "../../LogService.h"
|
#include "../../../LogService.h"
|
||||||
|
|
||||||
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, 16, 15, 4);
|
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, 16, 15, 4);
|
||||||
|
|
||||||
@ -236,3 +237,4 @@ class U8Display : public Task {
|
|||||||
|
|
||||||
STATIC_ALLOC(U8Display);
|
STATIC_ALLOC(U8Display);
|
||||||
STATIC_TASK(U8Display);
|
STATIC_TASK(U8Display);
|
||||||
|
#endif
|
134
src/platform/arduino/esp8266/Platform.cpp
Normal file
134
src/platform/arduino/esp8266/Platform.cpp
Normal 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", 0);
|
||||||
|
|
||||||
|
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.trace("ESP8266 startup reason: %d", Platform::bootopts.resetReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <Figments.h>
|
#include <Figments.h>
|
||||||
#include <ArduinoLog.h>
|
#include <ArduinoLog.h>
|
||||||
#include <Perfcounter.h>
|
|
||||||
|
|
||||||
class Blob {
|
class Blob {
|
||||||
uint8_t m_pos;
|
uint8_t m_pos;
|
||||||
@ -51,7 +50,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void render(Display* display) const {
|
void render(Display* display) const {
|
||||||
PerfCounter _("blobRender");
|
|
||||||
const uint8_t width = 25;
|
const uint8_t width = 25;
|
||||||
auto map = display->coordinateMapping();
|
auto map = display->coordinateMapping();
|
||||||
// Grab the physical pixel we'll start with
|
// Grab the physical pixel we'll start with
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user