bump
This commit is contained in:
parent
cadfd40b61
commit
92d5e73bd8
@ -29,19 +29,19 @@ InputSource::loop()
|
|||||||
InputEvent
|
InputEvent
|
||||||
BufferedInputSource::read()
|
BufferedInputSource::read()
|
||||||
{
|
{
|
||||||
InputEvent ret = m_lastEvent;
|
InputEvent ret;
|
||||||
m_lastEvent = InputEvent{};
|
m_eventQueue.take(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BufferedInputSource::setEvent(InputEvent &&evt)
|
BufferedInputSource::setEvent(InputEvent &&evt)
|
||||||
{
|
{
|
||||||
m_lastEvent = std::move(evt);
|
m_eventQueue.insert(std::move(evt));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BufferedInputSource::setEvent(InputEvent::Intent intent, Variant &&v)
|
BufferedInputSource::setEvent(InputEvent::Intent intent, Variant &&v)
|
||||||
{
|
{
|
||||||
m_lastEvent = InputEvent{intent, std::move(v)};
|
m_eventQueue.insert(InputEvent{intent, std::move(v)});
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "./Geometry.h"
|
#include "./Geometry.h"
|
||||||
#include "./Figment.h"
|
#include "./Figment.h"
|
||||||
|
#include "./Ringbuf.h"
|
||||||
#include "FastLED/FastLED.h"
|
#include "FastLED/FastLED.h"
|
||||||
|
|
||||||
typedef Vector3d<int> MotionVec;
|
typedef Vector3d<int> MotionVec;
|
||||||
@ -136,7 +137,7 @@ protected:
|
|||||||
void setEvent(InputEvent::Intent intent, Variant &&v);
|
void setEvent(InputEvent::Intent intent, Variant &&v);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InputEvent m_lastEvent;
|
Ringbuf<InputEvent, 5> m_eventQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class InputMapper: public BufferedInputSource {
|
class InputMapper: public BufferedInputSource {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "./Input.h"
|
#include "./Input.h"
|
||||||
|
#include "./Ringbuf.h"
|
||||||
|
|
||||||
class Task;
|
class Task;
|
||||||
class InputSource;
|
class InputSource;
|
||||||
@ -50,42 +51,6 @@ struct Scheduler {
|
|||||||
iterator end() { return iterator(*this, tasks.size()); }
|
iterator end() { return iterator(*this, tasks.size()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, int Size>
|
|
||||||
struct Ringbuf {
|
|
||||||
Ringbuf() : m_head(0), m_tail(0) {}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
m_head = 0;
|
|
||||||
m_tail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool take(T& dest) {
|
|
||||||
if (m_head == m_tail) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const int cur = m_head;
|
|
||||||
const int nextHead = (m_head + 1) % Size;
|
|
||||||
m_head = nextHead;
|
|
||||||
dest = m_items[cur];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert(const T& src) {
|
|
||||||
const int cur = m_tail;
|
|
||||||
const int nextTail = (m_tail + 1) % Size;
|
|
||||||
if (nextTail == m_head) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
m_tail = nextTail;
|
|
||||||
}
|
|
||||||
m_items[cur] = src;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
int m_head = 0;
|
|
||||||
int m_tail = 0;
|
|
||||||
std::array<T, Size> m_items;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MainLoop {
|
struct MainLoop {
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
|
|
||||||
|
39
firmware/Figments/Ringbuf.h
Normal file
39
firmware/Figments/Ringbuf.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
template<typename T, int Size>
|
||||||
|
struct Ringbuf {
|
||||||
|
Ringbuf() : m_head(0), m_tail(0) {}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
m_head = 0;
|
||||||
|
m_tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool take(T& dest) {
|
||||||
|
if (m_head == m_tail) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const int cur = m_head;
|
||||||
|
const int nextHead = (m_head + 1) % Size;
|
||||||
|
m_head = nextHead;
|
||||||
|
dest = m_items[cur];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const T& src) {
|
||||||
|
const int cur = m_tail;
|
||||||
|
const int nextTail = (m_tail + 1) % Size;
|
||||||
|
if (nextTail == m_head) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
m_tail = nextTail;
|
||||||
|
}
|
||||||
|
m_items[cur] = src;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int m_head = 0;
|
||||||
|
int m_tail = 0;
|
||||||
|
std::array<T, Size> m_items;
|
||||||
|
};
|
||||||
|
|
@ -36,7 +36,12 @@ Sequencer::handleEvent(const InputEvent& evt)
|
|||||||
} else if (evt.intent == InputEvent::PreviousPattern) {
|
} else if (evt.intent == InputEvent::PreviousPattern) {
|
||||||
m_idx--;
|
m_idx--;
|
||||||
} else {
|
} else {
|
||||||
m_idx = evt.asInt();
|
//m_idx = evt.asInt();
|
||||||
|
for(m_idx = 0; m_idx < m_scenes.size(); m_idx++) {
|
||||||
|
if (!strcmp(evt.asString(), m_scenes[m_idx].name)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_idx < 0) {
|
if (m_idx < 0) {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
#include "../Figments/Figments.h"
|
#include "../Figments/Figments.h"
|
||||||
|
|
||||||
|
using CRGB = NSFastLED::CRGB;
|
||||||
|
|
||||||
template<int Period>
|
template<int Period>
|
||||||
class ColorSequenceInput: public InputSource {
|
class ColorSequenceInput: public InputSource {
|
||||||
public:
|
public:
|
||||||
ColorSequenceInput(const std::vector<NSFastLED::CRGB> &colors, const char* name, Task::State initialState)
|
ColorSequenceInput(const std::vector<CRGB> &colors, const char* name, Task::State initialState)
|
||||||
: InputSource(name, initialState), m_colors(colors) {}
|
: InputSource(name, initialState), m_colors(colors) {}
|
||||||
|
|
||||||
InputEvent read() override {
|
InputEvent read() override {
|
||||||
@ -32,7 +34,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<NSFastLED::CRGB> m_colors;
|
std::vector<CRGB> m_colors;
|
||||||
int m_idx = 0;
|
int m_idx = 0;
|
||||||
bool m_reset = true;
|
bool m_reset = true;
|
||||||
bool m_override = false;
|
bool m_override = false;
|
||||||
|
@ -76,7 +76,7 @@ FigmentFunc configDisplay([](Display* dpy) {
|
|||||||
|
|
||||||
class InputBlip: public Figment {
|
class InputBlip: public Figment {
|
||||||
public:
|
public:
|
||||||
InputBlip() : Figment("InputBlip") {}
|
InputBlip() : Figment("InputBlip", Task::Stopped) {}
|
||||||
|
|
||||||
void handleEvent(const InputEvent& evt) override {
|
void handleEvent(const InputEvent& evt) override {
|
||||||
if (evt.intent != InputEvent::None) {
|
if (evt.intent != InputEvent::None) {
|
||||||
@ -139,13 +139,13 @@ DrainAnimation drain{Task::Stopped};
|
|||||||
Flashlight flashlight{Task::Stopped};
|
Flashlight flashlight{Task::Stopped};
|
||||||
|
|
||||||
Sequencer sequencer{{
|
Sequencer sequencer{{
|
||||||
{"Solid", {"Solid"}},
|
{"Idle", {"Solid", "MPU5060", "Pulse", "Hackerbots", "Kieryn", "CircadianRhythm"}},
|
||||||
{"Drain", {"Drain"}},
|
{"Solid", {"Solid", "MPU5060", "Pulse", "CircadianRhythm"}},
|
||||||
|
{"Interactive", {"Drain", "CircadianRhythm"}},
|
||||||
{"Flashlight", {"Flashlight"}},
|
{"Flashlight", {"Flashlight"}},
|
||||||
{"Fiercewater", {"Solid", "Kieryn", "Hackerbots"}},
|
{"Nightlight", {"Drain", "Pulse", "Noisebridge"}},
|
||||||
{"Nightlight", {"Drain", "Noisebridge"}},
|
{"Gay", {"Solid", "Pulse", "Rainbow", "Hackerbots", "Kieryn"}},
|
||||||
{"Gay", {"Solid", "Rainbow", "Hackerbots", "Kieryn"}},
|
{"Acid", {"Chimes", "Pulse", "MPU5060", "Hackerbots", "Rainbow"}},
|
||||||
{"Acid", {"Chimes", "Hackerbots", "Rainbow"}},
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ class OnlineTaskMixin : public virtual Loopable {
|
|||||||
public:
|
public:
|
||||||
void handleEvent(const InputEvent &evt) override {
|
void handleEvent(const InputEvent &evt) override {
|
||||||
if (evt.intent == InputEvent::NetworkStatus) {
|
if (evt.intent == InputEvent::NetworkStatus) {
|
||||||
m_online = true;
|
m_online = evt.asInt();
|
||||||
}
|
}
|
||||||
if (m_online) {
|
if (m_online) {
|
||||||
handleEventOnline(evt);
|
handleEventOnline(evt);
|
||||||
@ -199,13 +199,17 @@ class OnlineTaskMixin : public virtual Loopable {
|
|||||||
|
|
||||||
#include "MQTT/MQTT.h"
|
#include "MQTT/MQTT.h"
|
||||||
|
|
||||||
class MQTTTelemetry : public Task, OnlineTaskMixin {
|
class MQTTTelemetry : public BufferedInputSource, OnlineTaskMixin {
|
||||||
public:
|
public:
|
||||||
MQTTTelemetry() : Task("MQTT"), m_client("relay.malloc.hackerbots.net", 1883, 512, 15, MQTTTelemetry::s_callback, true) {
|
MQTTTelemetry() : BufferedInputSource("MQTT"), m_client("relay.malloc.hackerbots.net", 1883, 512, 15, MQTTTelemetry::s_callback, true) {
|
||||||
s_instance = this;
|
|
||||||
strcpy(m_deviceName, System.deviceID().c_str());
|
strcpy(m_deviceName, System.deviceID().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() override {
|
||||||
|
BufferedInputSource::loop();
|
||||||
|
OnlineTaskMixin::loop();
|
||||||
|
}
|
||||||
|
|
||||||
void handleEventOnline(const InputEvent& event) override {
|
void handleEventOnline(const InputEvent& event) override {
|
||||||
char response[255];
|
char response[255];
|
||||||
if (event.intent == InputEvent::SetPower) {
|
if (event.intent == InputEvent::SetPower) {
|
||||||
@ -234,20 +238,23 @@ class MQTTTelemetry : public Task, OnlineTaskMixin {
|
|||||||
writer.endObject();
|
writer.endObject();
|
||||||
writer.buffer()[std::min(writer.bufferSize(), writer.dataSize())] = 0;
|
writer.buffer()[std::min(writer.bufferSize(), writer.dataSize())] = 0;
|
||||||
m_client.publish(m_statTopic, response, MQTT::QOS1);
|
m_client.publish(m_statTopic, response, MQTT::QOS1);
|
||||||
|
} else if (event.intent == InputEvent::SetPattern) {
|
||||||
|
JSONBufferWriter writer(response, sizeof(response));
|
||||||
|
writer.beginObject();
|
||||||
|
writer.name("effect").value(event.asString());
|
||||||
|
writer.endObject();
|
||||||
|
writer.buffer()[std::min(writer.bufferSize(), writer.dataSize())] = 0;
|
||||||
|
m_client.publish(m_statTopic, response, MQTT::QOS1);
|
||||||
} else {
|
} else {
|
||||||
/*root["intent"] = event.intent;
|
if (m_lastIntent != event.intent) {
|
||||||
switch(event.type) {
|
m_lastIntent = event.intent;
|
||||||
case InputEvent::Null:
|
JSONBufferWriter writer(response, sizeof(response));
|
||||||
root["value"] = 0;break;
|
writer.beginObject();
|
||||||
case InputEvent::Integer:
|
writer.name("intent").value(event.intent);
|
||||||
root["value"] = event.asInt();break;
|
writer.endObject();
|
||||||
case InputEvent::String:
|
writer.buffer()[std::min(writer.bufferSize(), writer.dataSize())] = 0;
|
||||||
root["value"] = event.asString();break;
|
m_client.publish("renderbug/events", response, MQTT::QOS1);
|
||||||
case InputEvent::Color:
|
|
||||||
root["value"] = "RGB";break;
|
|
||||||
}
|
}
|
||||||
//root.printTo(response, sizeof(response));
|
|
||||||
//m_client.publish("renderbug/event", response);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +265,7 @@ class MQTTTelemetry : public Task, OnlineTaskMixin {
|
|||||||
char heartbeatBuf[255];
|
char heartbeatBuf[255];
|
||||||
JSONBufferWriter writer(heartbeatBuf, sizeof(heartbeatBuf));
|
JSONBufferWriter writer(heartbeatBuf, sizeof(heartbeatBuf));
|
||||||
writer.beginObject();
|
writer.beginObject();
|
||||||
writer.name("fps").value(NSFastLED::FastLED.getFPS());
|
writer.name("fps").value(FastLED.getFPS());
|
||||||
writer.name("os_version").value(System.version());
|
writer.name("os_version").value(System.version());
|
||||||
writer.name("free_ram").value((unsigned int)System.freeMemory());
|
writer.name("free_ram").value((unsigned int)System.freeMemory());
|
||||||
//writer.name("uptime").value(System.uptime());
|
//writer.name("uptime").value(System.uptime());
|
||||||
@ -329,13 +336,13 @@ class MQTTTelemetry : public Task, OnlineTaskMixin {
|
|||||||
void callback(char* topic, byte* payload, unsigned int length) {
|
void callback(char* topic, byte* payload, unsigned int length) {
|
||||||
MainLoop::instance()->dispatch(InputEvent::NetworkActivity);
|
MainLoop::instance()->dispatch(InputEvent::NetworkActivity);
|
||||||
if (!strcmp(topic, m_cmdTopic)) {
|
if (!strcmp(topic, m_cmdTopic)) {
|
||||||
JSONValue cmd = JSONValue::parse((char*)payload, length);
|
JSONValue cmd = JSONValue::parseCopy((char*)payload, length);
|
||||||
JSONObjectIterator cmdIter(cmd);
|
JSONObjectIterator cmdIter(cmd);
|
||||||
while(cmdIter.next()) {
|
while(cmdIter.next()) {
|
||||||
if (cmdIter.name() == "state" && cmdIter.value().toString() == "ON") {
|
if (cmdIter.name() == "state" && cmdIter.value().toString() == "ON") {
|
||||||
MainLoop::instance()->dispatch({InputEvent::SetPower, 1});
|
setEvent({InputEvent::SetPower, 1});
|
||||||
} else if (cmdIter.name() == "state" && cmdIter.value().toString() == "OFF") {
|
} else if (cmdIter.name() == "state" && cmdIter.value().toString() == "OFF") {
|
||||||
MainLoop::instance()->dispatch({InputEvent::SetPower, 0});
|
setEvent({InputEvent::SetPower, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdIter.name() == "color") {
|
if (cmdIter.name() == "color") {
|
||||||
@ -350,31 +357,36 @@ class MQTTTelemetry : public Task, OnlineTaskMixin {
|
|||||||
b = colorIter.value().toInt();
|
b = colorIter.value().toInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetColor, CRGB{r, g, b}});
|
setEvent(InputEvent{InputEvent::SetColor, CRGB{r, g, b}});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdIter.name() == "brightness") {
|
if (cmdIter.name() == "brightness") {
|
||||||
uint8_t brightness = cmdIter.value().toInt();
|
uint8_t brightness = cmdIter.value().toInt();
|
||||||
MainLoop::instance()->dispatch(InputEvent{InputEvent::SetBrightness, brightness});
|
setEvent(InputEvent{InputEvent::SetBrightness, brightness});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdIter.name() == "effect") {
|
||||||
|
strcpy(m_patternBuf, (const char*) cmdIter.value().toString());
|
||||||
|
setEvent(InputEvent{InputEvent::SetPattern, m_patternBuf});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s_callback(char* topic, byte* payload, unsigned int length) {
|
static void s_callback(char* topic, byte* payload, unsigned int length) {
|
||||||
s_instance->callback(topic, payload, length);
|
Static<MQTTTelemetry>::instance()->callback(topic, payload, length);
|
||||||
};
|
};
|
||||||
static MQTTTelemetry* s_instance;
|
|
||||||
MQTT m_client;
|
MQTT m_client;
|
||||||
|
InputEvent::Intent m_lastIntent;
|
||||||
char m_deviceName[100];
|
char m_deviceName[100];
|
||||||
char m_statTopic[100];
|
char m_statTopic[100];
|
||||||
char m_attrTopic[100];
|
char m_attrTopic[100];
|
||||||
char m_cmdTopic[100];
|
char m_cmdTopic[100];
|
||||||
|
char m_patternBuf[48];
|
||||||
};
|
};
|
||||||
|
|
||||||
MQTTTelemetry mqttTelemetry;
|
STATIC_ALLOC(MQTTTelemetry);
|
||||||
|
|
||||||
MQTTTelemetry* MQTTTelemetry::s_instance = 0;
|
|
||||||
|
|
||||||
WebTelemetry webTelemetry(sequencer);
|
WebTelemetry webTelemetry(sequencer);
|
||||||
|
|
||||||
@ -386,7 +398,7 @@ ColorSequenceInput<13> kierynCycle{{
|
|||||||
colorForName("Electric Purple").rgb,
|
colorForName("Electric Purple").rgb,
|
||||||
colorForName("Emerald").rgb,
|
colorForName("Emerald").rgb,
|
||||||
colorForName("Sky Magenta").rgb
|
colorForName("Sky Magenta").rgb
|
||||||
}, "Kieryn", Task::Running};
|
}, "Kieryn", Task::Stopped};
|
||||||
|
|
||||||
ColorSequenceInput<7> rainbowCycle{{
|
ColorSequenceInput<7> rainbowCycle{{
|
||||||
colorForName("Red").rgb,
|
colorForName("Red").rgb,
|
||||||
@ -402,7 +414,7 @@ ColorSequenceInput<7> hackerbotsCycle{{
|
|||||||
colorForName("Purple").rgb,
|
colorForName("Purple").rgb,
|
||||||
colorForName("White").rgb,
|
colorForName("White").rgb,
|
||||||
colorForName("Cyan").rgb,
|
colorForName("Cyan").rgb,
|
||||||
}, "Hackerbots", Task::Running};
|
}, "Hackerbots", Task::Stopped};
|
||||||
|
|
||||||
struct ConfigInputTask: public BufferedInputSource {
|
struct ConfigInputTask: public BufferedInputSource {
|
||||||
public:
|
public:
|
||||||
@ -540,8 +552,11 @@ uint8_t brightnessForTime(uint8_t hour, uint8_t minute) {
|
|||||||
InputFunc circadianRhythm([]() {
|
InputFunc circadianRhythm([]() {
|
||||||
static Phase lastPhase = Null;
|
static Phase lastPhase = Null;
|
||||||
static bool needsUpdate = true;
|
static bool needsUpdate = true;
|
||||||
EVERY_N_SECONDS(60) {
|
|
||||||
if (Time.isValid()) {
|
if (Time.isValid()) {
|
||||||
|
EVERY_N_SECONDS(60) {
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
|
if (needsUpdate) {
|
||||||
return InputEvent{InputEvent::SetBrightness, brightnessForTime(Time.hour(), Time.minute())};
|
return InputEvent{InputEvent::SetBrightness, brightnessForTime(Time.hour(), Time.minute())};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -561,15 +576,11 @@ MainLoop configApp{{
|
|||||||
|
|
||||||
// Read hardware inputs
|
// Read hardware inputs
|
||||||
new Buttons(),
|
new Buttons(),
|
||||||
&randomPulse,
|
|
||||||
//new MPU5060(),
|
|
||||||
|
|
||||||
// Map input buttons to configuration commands
|
// Map input buttons to configuration commands
|
||||||
new ConfigInputTask(),
|
new ConfigInputTask(),
|
||||||
|
|
||||||
// Fill the entire display with a color, to see size
|
// Fill the entire display with a color, to see size
|
||||||
&rainbowCycle,
|
|
||||||
&drain,
|
|
||||||
&configDisplay,
|
&configDisplay,
|
||||||
// Render some basic input feedback
|
// Render some basic input feedback
|
||||||
&inputBlip,
|
&inputBlip,
|
||||||
@ -638,7 +649,7 @@ MainLoop renderbugApp{{
|
|||||||
&webTelemetry,
|
&webTelemetry,
|
||||||
|
|
||||||
// MQTT telemetry
|
// MQTT telemetry
|
||||||
&mqttTelemetry,
|
Static<MQTTTelemetry>::instance(),
|
||||||
|
|
||||||
// Network discovery
|
// Network discovery
|
||||||
&mdnsService,
|
&mdnsService,
|
||||||
@ -647,15 +658,24 @@ MainLoop renderbugApp{{
|
|||||||
|
|
||||||
MainLoop &runner = renderbugApp;
|
MainLoop &runner = renderbugApp;
|
||||||
|
|
||||||
|
retained bool LAST_BOOT_WAS_FLASH;
|
||||||
|
retained bool LAST_BOOT_WAS_SERIAL;
|
||||||
|
|
||||||
struct BootOptions {
|
struct BootOptions {
|
||||||
BootOptions() {
|
static void initPins() {
|
||||||
pinMode(2, INPUT_PULLDOWN);
|
pinMode(2, INPUT_PULLDOWN);
|
||||||
pinMode(3, INPUT_PULLDOWN);
|
pinMode(3, INPUT_PULLDOWN);
|
||||||
pinMode(4, INPUT_PULLDOWN);
|
pinMode(4, INPUT_PULLDOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
BootOptions() {
|
||||||
isSetup = digitalRead(2) == HIGH;
|
isSetup = digitalRead(2) == HIGH;
|
||||||
isSerial = digitalRead(3) == HIGH;
|
isSerial = digitalRead(3) == HIGH || LAST_BOOT_WAS_SERIAL;
|
||||||
isFlash = digitalRead(4) == HIGH;
|
isFlash = digitalRead(4) == HIGH;
|
||||||
|
|
||||||
|
LAST_BOOT_WAS_FLASH = isFlash;
|
||||||
|
LAST_BOOT_WAS_SERIAL |= isSerial;
|
||||||
|
|
||||||
configStatus.setActive(isSetup);
|
configStatus.setActive(isSetup);
|
||||||
serialStatus.setActive(isSerial);
|
serialStatus.setActive(isSerial);
|
||||||
}
|
}
|
||||||
@ -672,16 +692,27 @@ struct BootOptions {
|
|||||||
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
BootOptions bootopts;
|
STARTUP(BootOptions::initPins());
|
||||||
|
|
||||||
|
retained BootOptions bootopts;
|
||||||
|
|
||||||
ApplicationWatchdog *wd;
|
ApplicationWatchdog *wd;
|
||||||
|
|
||||||
void watchdogHandler() {
|
void watchdogHandler() {
|
||||||
|
for(int i = 0; i < 8; i++) {
|
||||||
|
leds[i] = CRGB(i % 3 ? 35 : 255, 0, 0);
|
||||||
|
}
|
||||||
|
FastLED.show();
|
||||||
|
if (LAST_BOOT_WAS_FLASH) {
|
||||||
|
System.dfu();
|
||||||
|
} else {
|
||||||
System.enterSafeMode();
|
System.enterSafeMode();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tune in,
|
// Tune in,
|
||||||
void setup() {
|
void setup() {
|
||||||
|
System.enableFeature(FEATURE_RETAINED_MEMORY);
|
||||||
wd = new ApplicationWatchdog(5000, watchdogHandler, 1536);
|
wd = new ApplicationWatchdog(5000, watchdogHandler, 1536);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
if (bootopts.isFlash) {
|
if (bootopts.isFlash) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
using namespace NSFastLED;
|
||||||
|
|
||||||
class Blob {
|
class Blob {
|
||||||
uint16_t m_pos;
|
uint16_t m_pos;
|
||||||
int8_t m_velocity;
|
int8_t m_velocity;
|
||||||
@ -56,12 +58,12 @@ public:
|
|||||||
|
|
||||||
for(uint8_t i = 0;i < scaledWidth; i++) {
|
for(uint8_t i = 0;i < scaledWidth; i++) {
|
||||||
// Blobs desaturate towards their tail
|
// Blobs desaturate towards their tail
|
||||||
NSFastLED::CHSV blobColor(m_hue, m_saturation, NSFastLED::quadwave8((i / (double)scaledWidth) * m_brightness));
|
CHSV blobColor(m_hue, m_saturation, quadwave8((i / (double)scaledWidth) * m_brightness));
|
||||||
|
|
||||||
PhysicalCoordinates pos{startPos.x + (i*m_fadeDir), 0};
|
PhysicalCoordinates pos{startPos.x + (i*m_fadeDir), 0};
|
||||||
|
|
||||||
NSFastLED::CRGB src(display->pixelAt(pos));
|
CRGB src(display->pixelAt(pos));
|
||||||
display->pixelAt(pos) = NSFastLED::blend(NSFastLED::CRGB(blobColor), src, 200);
|
display->pixelAt(pos) = blend(CRGB(blobColor), src, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -67,7 +67,7 @@ public:
|
|||||||
dpy->pixelAt(i + m_offset) = CHSV(0, 0, 0);
|
dpy->pixelAt(i + m_offset) = CHSV(0, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
uint8_t distance = m_pos - i;
|
uint8_t distance = m_pos - i;
|
||||||
uint8_t brightness = NSFastLED::scale8(NSFastLED::quadwave8((ChimeLength / (double)distance) * 255), m_brightness);
|
uint8_t brightness = scale8(quadwave8((ChimeLength / (double)distance) * 255), m_brightness);
|
||||||
if (brightness <= 0.2)
|
if (brightness <= 0.2)
|
||||||
brightness = 0;
|
brightness = 0;
|
||||||
dpy->pixelAt(VirtualCoordinates{i + m_offset, 0}) = CHSV(m_hue, min(m_saturation, brightness), brightness);
|
dpy->pixelAt(VirtualCoordinates{i + m_offset, 0}) = CHSV(m_hue, min(m_saturation, brightness), brightness);
|
||||||
|
Loading…
Reference in New Issue
Block a user