port to platformio
This commit is contained in:
10
lib/Figments/Animation.cpp
Normal file
10
lib/Figments/Animation.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "./Animation.h"
|
||||
#include "./Input.h"
|
||||
#include "./Display.h"
|
||||
#include <algorithm>
|
||||
|
||||
uint8_t
|
||||
AnimatedNumber::value() const
|
||||
{
|
||||
return lerp8by8(m_start, m_end, m_idx);
|
||||
}
|
147
lib/Figments/Animation.h
Normal file
147
lib/Figments/Animation.h
Normal file
@ -0,0 +1,147 @@
|
||||
#pragma once
|
||||
#include <FastLED.h>
|
||||
#include "./Figment.h"
|
||||
#include <vector>
|
||||
|
||||
class Display;
|
||||
|
||||
struct AnimatedNumber {
|
||||
void set(uint8_t v) {
|
||||
set(value(), v);
|
||||
}
|
||||
|
||||
void set(uint8_t start, uint8_t end) {
|
||||
m_start = start;
|
||||
m_end = end;
|
||||
m_idx = 0;
|
||||
}
|
||||
|
||||
uint8_t value() const;
|
||||
|
||||
void update() {
|
||||
if (m_idx < 255) {
|
||||
m_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedNumber() {}
|
||||
AnimatedNumber(uint8_t v) : m_end(v) {}
|
||||
|
||||
AnimatedNumber& operator=(uint8_t v) {
|
||||
set(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AnimatedNumber& operator+=(uint8_t v) {
|
||||
set(value()+v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator uint8_t() const {
|
||||
return value();
|
||||
}
|
||||
|
||||
operator int() const {
|
||||
return value();
|
||||
}
|
||||
|
||||
operator unsigned int() const {
|
||||
return value();
|
||||
}
|
||||
|
||||
bool operator==(int other) const {
|
||||
return value() == other;
|
||||
}
|
||||
|
||||
uint8_t operator+(uint8_t other) const {
|
||||
return value() + other;
|
||||
}
|
||||
|
||||
int operator+(int other) const {
|
||||
return value() + other;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t m_idx = 255;
|
||||
uint8_t m_start = 0;
|
||||
uint8_t m_end = 0;
|
||||
};
|
||||
|
||||
struct AnimatedRGB {
|
||||
CRGB start;
|
||||
CRGB end;
|
||||
AnimatedNumber pos;
|
||||
|
||||
AnimatedRGB(const CRGB& color)
|
||||
: start(color), end(color) {}
|
||||
|
||||
AnimatedRGB() {}
|
||||
|
||||
AnimatedRGB& operator=(const CRGB& rgb) {
|
||||
start = *this;
|
||||
end = rgb;
|
||||
pos.set(0, 255);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void update() {
|
||||
pos.update();
|
||||
}
|
||||
|
||||
operator CRGB() const {
|
||||
uint8_t red = lerp8by8(start.red, end.red, pos);
|
||||
uint8_t green = lerp8by8(start.green, end.green, pos);
|
||||
uint8_t blue = lerp8by8(start.blue, end.blue, pos);
|
||||
return CRGB(red, green, blue);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, int Size>
|
||||
struct SpriteList {
|
||||
void update() {
|
||||
if (!m_enabled) return;
|
||||
for(int i = 0; i < size; i++) {
|
||||
animations[i].update();
|
||||
}
|
||||
}
|
||||
|
||||
void render(Display* dpy) const {
|
||||
if (!m_enabled) return;
|
||||
for(int i = 0; i < size; i++) {
|
||||
animations[i].render(dpy);
|
||||
}
|
||||
}
|
||||
|
||||
void forEach(std::function<void(T&)> func) {
|
||||
for(int i = 0; i < size; i++) {
|
||||
func(animations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void forEach(std::function<void(const T&)> func) const {
|
||||
for(int i = 0; i < size; i++) {
|
||||
func(animations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void disable() {
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
void enable() {
|
||||
m_enabled = true;
|
||||
}
|
||||
|
||||
void toggle() {
|
||||
m_enabled = !m_enabled;
|
||||
}
|
||||
|
||||
T& operator[](int idx) {
|
||||
return animations[idx];
|
||||
}
|
||||
|
||||
T animations[Size];
|
||||
bool m_enabled = true;
|
||||
static constexpr int size = Size;
|
||||
using Type = T;
|
||||
};
|
57
lib/Figments/Display.cpp
Normal file
57
lib/Figments/Display.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "Display.h"
|
||||
#include <math.h>
|
||||
|
||||
int
|
||||
Display::pixelCount() const
|
||||
{
|
||||
return m_pixelCount;
|
||||
}
|
||||
|
||||
CRGB*
|
||||
Display::pixelBacking() const
|
||||
{
|
||||
return m_pixels;
|
||||
}
|
||||
|
||||
void
|
||||
Display::clear()
|
||||
{
|
||||
clear(CRGB(0, 0, 0));
|
||||
}
|
||||
|
||||
void
|
||||
Display::clear(const CRGB& color)
|
||||
{
|
||||
for(int i = 0; i < m_pixelCount;i++) {
|
||||
m_pixels[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
CRGB&
|
||||
Display::pixelAt(const PhysicalCoordinates coords)
|
||||
{
|
||||
return pixelAt(m_coordMap->physicalCoordsToIndex(coords));
|
||||
}
|
||||
|
||||
CRGB&
|
||||
Display::pixelAt(const VirtualCoordinates coords)
|
||||
{
|
||||
return pixelAt(m_coordMap->virtualToPhysicalCoords(coords));
|
||||
}
|
||||
|
||||
CRGB&
|
||||
Display::pixelAt(int idx)
|
||||
{
|
||||
const int kx = idx % pixelCount();
|
||||
if (kx < 0) {
|
||||
return m_pixels[pixelCount() + 1 + kx];
|
||||
} else {
|
||||
return m_pixels[kx];
|
||||
}
|
||||
}
|
||||
|
||||
const CoordinateMapping*
|
||||
Display::coordinateMapping() const
|
||||
{
|
||||
return m_coordMap;
|
||||
}
|
56
lib/Figments/Display.h
Normal file
56
lib/Figments/Display.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include <FastLED.h>
|
||||
|
||||
#include "Geometry.h"
|
||||
|
||||
struct CoordinateMapping {
|
||||
virtual VirtualCoordinates physicalToVirtualCoords(const PhysicalCoordinates localCoords) const = 0;
|
||||
virtual PhysicalCoordinates virtualToPhysicalCoords(const VirtualCoordinates virtualCoords) const = 0;
|
||||
virtual int physicalCoordsToIndex(const PhysicalCoordinates localCoords) const = 0;
|
||||
virtual unsigned int physicalPixelCount() const = 0;
|
||||
};
|
||||
|
||||
struct LinearCoordinateMapping: CoordinateMapping {
|
||||
unsigned int pixelCount = 1;
|
||||
unsigned int startPixel = 0;
|
||||
LinearCoordinateMapping() {}
|
||||
LinearCoordinateMapping(unsigned int count, unsigned int start) : pixelCount(count), startPixel(start) {}
|
||||
VirtualCoordinates physicalToVirtualCoords(const PhysicalCoordinates localCoords) const {
|
||||
return VirtualCoordinates{(uint8_t)((localCoords.x) / pixelCount), 0};
|
||||
}
|
||||
|
||||
PhysicalCoordinates virtualToPhysicalCoords(const VirtualCoordinates virtualCoords) const {
|
||||
return PhysicalCoordinates{scale8(pixelCount, virtualCoords.x), 0};
|
||||
}
|
||||
|
||||
int physicalCoordsToIndex(const PhysicalCoordinates localCoords) const override {
|
||||
return localCoords.x + startPixel;
|
||||
}
|
||||
|
||||
unsigned int physicalPixelCount() const {
|
||||
return pixelCount;
|
||||
}
|
||||
};
|
||||
|
||||
class Display {
|
||||
public:
|
||||
|
||||
Display(CRGB* pixels, int pixelCount, const CoordinateMapping* map)
|
||||
: m_pixels(pixels), m_pixelCount(pixelCount), m_coordMap(map) {}
|
||||
|
||||
CRGB& pixelAt(const PhysicalCoordinates coords);
|
||||
CRGB& pixelAt(const VirtualCoordinates coords);
|
||||
CRGB& pixelAt(int idx);
|
||||
|
||||
int pixelCount() const;
|
||||
CRGB* pixelBacking() const;
|
||||
const CoordinateMapping* coordinateMapping() const;
|
||||
void clear();
|
||||
void clear(const CRGB& color);
|
||||
void clear(VirtualCoordinates& start, VirtualCoordinates& end, const CRGB& color);
|
||||
|
||||
private:
|
||||
CRGB* m_pixels;
|
||||
int m_pixelCount;
|
||||
const CoordinateMapping* m_coordMap;
|
||||
};
|
53
lib/Figments/Figment.h
Normal file
53
lib/Figments/Figment.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
#include <ArduinoLog.h>
|
||||
|
||||
class Display;
|
||||
class InputEvent;
|
||||
class InputSource;
|
||||
|
||||
struct Loopable {
|
||||
virtual void handleEvent(const InputEvent& event) {}
|
||||
virtual void loop() = 0;
|
||||
};
|
||||
|
||||
struct Task : public virtual Loopable {
|
||||
virtual void onStart() {};
|
||||
virtual void onStop() {};
|
||||
|
||||
enum State {
|
||||
Running,
|
||||
Stopped,
|
||||
};
|
||||
|
||||
Task() {}
|
||||
Task(State initialState) : Task(0, initialState) {}
|
||||
Task(const char* name) : Task(name, Running) {}
|
||||
Task(const char* name, State initialState) : name(name), state(initialState) {}
|
||||
|
||||
void start() { state = Running; onStart(); }
|
||||
void stop() { onStop(); state = Stopped; }
|
||||
virtual bool isFigment() const { return false; }
|
||||
|
||||
const char* name = 0;
|
||||
State state = Running;
|
||||
};
|
||||
|
||||
struct Figment: public Task {
|
||||
Figment() : Task() {}
|
||||
Figment(State initialState) : Task(initialState) {}
|
||||
Figment(const char* name) : Task(name) {}
|
||||
Figment(const char* name, State initialState) : Task(name, initialState) {}
|
||||
virtual void render(Display* dpy) const = 0;
|
||||
bool isFigment() const override { return true; }
|
||||
};
|
||||
|
||||
struct FigmentFunc: public Figment {
|
||||
FigmentFunc(std::function<void(Display*)> func) : Figment("lambda"), func(func) {}
|
||||
void loop() override {}
|
||||
void render(Display* dpy) const override {
|
||||
func(dpy);
|
||||
}
|
||||
std::function<void(Display*)> func;
|
||||
};
|
8
lib/Figments/Figments.h
Normal file
8
lib/Figments/Figments.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "./Display.h"
|
||||
#include "./Input.h"
|
||||
#include "./Figment.h"
|
||||
#include "./Animation.h"
|
||||
#include "./MainLoop.h"
|
||||
#include "./Renderer.h"
|
||||
#include "./Surface.h"
|
39
lib/Figments/Geometry.h
Normal file
39
lib/Figments/Geometry.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
template<typename T> struct Coordinates {
|
||||
Coordinates(T _x, T _y) : x(_x), y(_y) {}
|
||||
T x;
|
||||
T y;
|
||||
};
|
||||
|
||||
struct VirtualCoordinates: Coordinates<uint16_t> {
|
||||
VirtualCoordinates(uint16_t _x, uint16_t _y) : Coordinates(_x, _y) {}
|
||||
};
|
||||
|
||||
struct PhysicalCoordinates: Coordinates<uint16_t> {
|
||||
PhysicalCoordinates(uint16_t _x, uint16_t _y) : Coordinates(_x, _y) {}
|
||||
};
|
||||
|
||||
template<typename T> struct Vector3d {
|
||||
Vector3d(T _x, T _y, T _z) : x(_x), y(_y), z(_z) {}
|
||||
Vector3d() : Vector3d(0, 0, 0) {}
|
||||
T x;
|
||||
T y;
|
||||
T z;
|
||||
|
||||
T magnitude() const {
|
||||
return abs(max(x, max(y, z)));
|
||||
}
|
||||
|
||||
Vector3d<T> operator-(const Vector3d<T>& other) const {
|
||||
return Vector3d<T>(x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
|
||||
Vector3d<T> absolute() const {
|
||||
return Vector3d<T>(abs(x), abs(y), abs(z));
|
||||
}
|
||||
};
|
||||
|
||||
typedef Vector3d<uint8_t> Vec3;
|
47
lib/Figments/Input.cpp
Normal file
47
lib/Figments/Input.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include <Arduino.h>
|
||||
#include "./Input.h"
|
||||
#include "./MainLoop.h"
|
||||
|
||||
CRGB
|
||||
Variant::asRGB() const
|
||||
{
|
||||
return CRGB(m_value.asRGB[0], m_value.asRGB[1], m_value.asRGB[2]);
|
||||
}
|
||||
|
||||
const char*
|
||||
Variant::asString() const
|
||||
{
|
||||
return m_value.asString;
|
||||
}
|
||||
|
||||
int
|
||||
Variant::asInt() const
|
||||
{
|
||||
return m_value.asInt;
|
||||
}
|
||||
|
||||
void
|
||||
InputSource::loop()
|
||||
{
|
||||
MainLoop::instance()->dispatch(read());
|
||||
}
|
||||
|
||||
InputEvent
|
||||
BufferedInputSource::read()
|
||||
{
|
||||
InputEvent ret;
|
||||
m_eventQueue.take(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
BufferedInputSource::setEvent(InputEvent &&evt)
|
||||
{
|
||||
m_eventQueue.insert(std::move(evt));
|
||||
}
|
||||
|
||||
void
|
||||
BufferedInputSource::setEvent(InputEvent::Intent intent, Variant &&v)
|
||||
{
|
||||
m_eventQueue.insert(InputEvent{intent, std::move(v)});
|
||||
}
|
178
lib/Figments/Input.h
Normal file
178
lib/Figments/Input.h
Normal file
@ -0,0 +1,178 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include "./Geometry.h"
|
||||
#include "./Figment.h"
|
||||
#include "./Ringbuf.h"
|
||||
#include <FastLED.h>
|
||||
|
||||
typedef Vector3d<int> MotionVec;
|
||||
|
||||
struct Variant {
|
||||
enum Type {
|
||||
Null,
|
||||
Integer,
|
||||
String,
|
||||
Color,
|
||||
};
|
||||
|
||||
Variant(int v)
|
||||
: type(Integer), m_value{.asInt=v} {}
|
||||
|
||||
Variant(const char* v)
|
||||
: type(String), m_value{.asString=v} {}
|
||||
|
||||
Variant(const CRGB &v)
|
||||
: type(Color), m_value{.asRGB={v.r, v.g, v.b}} {}
|
||||
|
||||
Variant()
|
||||
: type(Null) {}
|
||||
|
||||
Type type;
|
||||
|
||||
const char* asString() const;
|
||||
CRGB asRGB() const;
|
||||
int asInt() const;
|
||||
|
||||
private:
|
||||
union {
|
||||
int asInt;
|
||||
const char* asString;
|
||||
uint8_t asRGB[3];
|
||||
} m_value;
|
||||
};
|
||||
|
||||
struct InputEvent: public Variant {
|
||||
enum Intent {
|
||||
// An empty non-event
|
||||
None,
|
||||
|
||||
// An input from the user, for other tasks to translate into canonical
|
||||
// types. Makes for easy button re-mapping on the fly.
|
||||
UserInput,
|
||||
|
||||
//
|
||||
// The canonical types
|
||||
//
|
||||
// Hardware inputs
|
||||
ButtonPress,
|
||||
Acceleration,
|
||||
NetworkStatus,
|
||||
NetworkActivity,
|
||||
|
||||
// Power management
|
||||
PowerToggle,
|
||||
SetPower,
|
||||
SetBrightness,
|
||||
|
||||
// Animation sequencing
|
||||
PreviousPattern,
|
||||
NextPattern,
|
||||
SetPattern,
|
||||
PreviousScene,
|
||||
NextScene,
|
||||
SetScene,
|
||||
|
||||
// Timekeeping
|
||||
ScheduleChange,
|
||||
|
||||
// Task management
|
||||
StartThing,
|
||||
StopThing,
|
||||
|
||||
// Configuration
|
||||
SetDisplayOffset,
|
||||
SetDisplayLength,
|
||||
SetColor,
|
||||
SaveConfigurationRequest,
|
||||
|
||||
// Firmware events
|
||||
FirmwareUpdate,
|
||||
};
|
||||
|
||||
template<typename Value>
|
||||
InputEvent(Intent s, Value v)
|
||||
: Variant(v), intent(s) {}
|
||||
|
||||
InputEvent(Intent s)
|
||||
: Variant(), intent(s) {}
|
||||
|
||||
InputEvent()
|
||||
: Variant(), intent(None) {}
|
||||
|
||||
Intent intent;
|
||||
};
|
||||
|
||||
class InputSource: public Task {
|
||||
public:
|
||||
InputSource() : Task() {}
|
||||
InputSource(const char* name) : Task(name) {}
|
||||
InputSource(Task::State initialState) : Task(initialState) {}
|
||||
InputSource(const char* name, Task::State initialState) : Task(name, initialState) {}
|
||||
void loop() override;
|
||||
virtual InputEvent read() = 0;
|
||||
};
|
||||
|
||||
class InputFunc : public InputSource {
|
||||
public:
|
||||
InputFunc(std::function<InputEvent(void)> f) : InputSource(), m_func(f) {}
|
||||
InputFunc(std::function<InputEvent(void)> f, const char* name) : InputSource(name), m_func(f) {}
|
||||
InputFunc(std::function<InputEvent(void)> f, const char* name, Task::State initialState) : InputSource(name, initialState), m_func(f) {}
|
||||
|
||||
InputEvent read() override {
|
||||
return m_func();
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<InputEvent(void)> m_func;
|
||||
};
|
||||
|
||||
class BufferedInputSource: public InputSource {
|
||||
public:
|
||||
BufferedInputSource() : InputSource() {}
|
||||
BufferedInputSource(const char* name) : InputSource(name) {}
|
||||
InputEvent read() override;
|
||||
|
||||
protected:
|
||||
void setEvent(InputEvent &&evt);
|
||||
void setEvent(InputEvent::Intent intent, Variant &&v);
|
||||
|
||||
private:
|
||||
Ringbuf<InputEvent, 5> m_eventQueue;
|
||||
};
|
||||
|
||||
class InputMapper: public BufferedInputSource {
|
||||
public:
|
||||
InputMapper(std::function<InputEvent(const InputEvent)> f, const char* name) : BufferedInputSource(name), m_func(f) {}
|
||||
|
||||
void handleEvent(const InputEvent& evt) override {
|
||||
setEvent(m_func(evt));
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<InputEvent(const InputEvent)> m_func;
|
||||
};
|
||||
|
||||
class OnlineTaskMixin : public virtual Loopable {
|
||||
public:
|
||||
void handleEvent(const InputEvent &evt) override {
|
||||
if (evt.intent == InputEvent::NetworkStatus) {
|
||||
m_online = evt.asInt();
|
||||
}
|
||||
if (m_online) {
|
||||
handleEventOnline(evt);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void handleEventOnline(const InputEvent &evt) = 0;
|
||||
|
||||
void loop() override {
|
||||
if (m_online) {
|
||||
loopOnline();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void loopOnline() = 0;
|
||||
|
||||
private:
|
||||
bool m_online = false;
|
||||
};
|
58
lib/Figments/MainLoop.cpp
Normal file
58
lib/Figments/MainLoop.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include "./MainLoop.h"
|
||||
#include "./Input.h"
|
||||
#include "./Figment.h"
|
||||
|
||||
#include <ArduinoLog.h>
|
||||
|
||||
void
|
||||
MainLoop::dispatch(const InputEvent& evt)
|
||||
{
|
||||
if (evt.intent == InputEvent::None) {
|
||||
return;
|
||||
}
|
||||
m_eventBuf.insert(evt);
|
||||
}
|
||||
|
||||
void
|
||||
MainLoop::loop()
|
||||
{
|
||||
InputEvent evt;
|
||||
while (m_eventBuf.take(evt)) {
|
||||
if (evt.intent == InputEvent::StartThing || evt.intent == InputEvent::StopThing) {
|
||||
const bool jobState = (evt.intent == InputEvent::StartThing);
|
||||
for(auto figmentJob: scheduler.tasks) {
|
||||
if (!strcmp(figmentJob->name, evt.asString())) {
|
||||
if (jobState) {
|
||||
//Log.notice("Starting %s", figmentJob->name);
|
||||
figmentJob->start();
|
||||
} else {
|
||||
//Log.notice("Stopping %s", figmentJob->name);
|
||||
figmentJob->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Task* task : scheduler) {
|
||||
task->handleEvent(evt);
|
||||
}
|
||||
}
|
||||
for(Task* task : scheduler) {
|
||||
//Log.notice("Running %s", task->name);
|
||||
task->loop();
|
||||
//Log.notice("next");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainLoop::start()
|
||||
{
|
||||
Log.notice("*** Starting %d tasks...", scheduler.tasks.size());
|
||||
Serial.flush();
|
||||
for(auto task: scheduler) {
|
||||
Log.notice("** Starting %s", task->name);
|
||||
task->start();
|
||||
}
|
||||
}
|
||||
|
||||
MainLoop* MainLoop::s_instance;
|
69
lib/Figments/MainLoop.h
Normal file
69
lib/Figments/MainLoop.h
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "./Input.h"
|
||||
#include "./Ringbuf.h"
|
||||
|
||||
class Task;
|
||||
class InputSource;
|
||||
|
||||
struct Scheduler {
|
||||
std::vector<Task*> tasks;
|
||||
|
||||
bool operator==(const Scheduler& other) const {
|
||||
return tasks == other.tasks;
|
||||
}
|
||||
|
||||
Scheduler(std::vector<Task*> &&tasks)
|
||||
: tasks(std::move(tasks))
|
||||
{}
|
||||
|
||||
struct iterator: public std::iterator<std::input_iterator_tag, Task*> {
|
||||
Scheduler& queue;
|
||||
int idx = 0;
|
||||
explicit iterator(Scheduler& queue) : queue(queue), idx(nextEnabled(0)) {}
|
||||
iterator(Scheduler& queue, int start) : queue(queue), idx(nextEnabled(start)) {}
|
||||
iterator& operator++() {
|
||||
while (idx < queue.tasks.size() && !queue.tasks[idx]->state == Task::Running) {
|
||||
idx++;
|
||||
}
|
||||
idx = nextEnabled(idx+1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int nextEnabled(int start) const {
|
||||
for(int pos = start; pos < queue.tasks.size();pos++) {
|
||||
if (queue.tasks[pos]->state == Task::Running) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return queue.tasks.size();
|
||||
}
|
||||
|
||||
iterator operator++(int) {iterator ret = *this; ++(*this); return ret;}
|
||||
bool operator==(iterator other) const { return idx == other.idx && queue == other.queue; }
|
||||
bool operator!=(iterator other) const { return !(*this == other); }
|
||||
Task* operator*() const { return queue.tasks[idx]; }
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(*this); }
|
||||
iterator end() { return iterator(*this, tasks.size()); }
|
||||
};
|
||||
|
||||
struct MainLoop {
|
||||
Scheduler scheduler;
|
||||
|
||||
MainLoop(std::vector<Task*> &&tasks)
|
||||
: scheduler(std::move(tasks)) {s_instance = this;}
|
||||
|
||||
void start();
|
||||
void loop();
|
||||
void dispatch(const InputEvent& event);
|
||||
static MainLoop* instance() { return s_instance; }
|
||||
|
||||
private:
|
||||
Ringbuf<InputEvent, 10> m_eventBuf;
|
||||
|
||||
static MainLoop* s_instance;
|
||||
};
|
31
lib/Figments/Renderer.cpp
Normal file
31
lib/Figments/Renderer.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "./Renderer.h"
|
||||
#include "./Display.h"
|
||||
|
||||
#include <ArduinoLog.h>
|
||||
|
||||
void
|
||||
Renderer::loop()
|
||||
{
|
||||
for(Display* dpy : m_displays) {
|
||||
for(Figment* figment : m_figments) {
|
||||
if (figment->state == Task::Running) {
|
||||
//Log.notice("Rendering %s", figment->name);
|
||||
figment->render(dpy);
|
||||
//Log.notice("next");
|
||||
} else {
|
||||
//Log.notice("Not rendering %s", figment->name);
|
||||
}
|
||||
};
|
||||
}
|
||||
FastLED.show();
|
||||
FastLED.countFPS();
|
||||
}
|
||||
|
||||
void
|
||||
Renderer::onStart()
|
||||
{
|
||||
for(Display* dpy : m_displays) {
|
||||
dpy->clear();
|
||||
}
|
||||
FastLED.show();
|
||||
}
|
16
lib/Figments/Renderer.h
Normal file
16
lib/Figments/Renderer.h
Normal file
@ -0,0 +1,16 @@
|
||||
#include "./Figment.h"
|
||||
#include <vector>
|
||||
|
||||
class Display;
|
||||
|
||||
struct Renderer: public Task {
|
||||
public:
|
||||
Renderer(std::vector<Display*> displays, const std::vector<Figment*> &figments) : Task("Renderer"), m_figments(figments), m_displays(displays) {}
|
||||
|
||||
void loop() override;
|
||||
void onStart() override;
|
||||
|
||||
private:
|
||||
const std::vector<Figment*> m_figments;
|
||||
const std::vector<Display*> m_displays;
|
||||
};
|
39
lib/Figments/Ringbuf.h
Normal file
39
lib/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;
|
||||
};
|
||||
|
0
lib/Figments/Service.h
Normal file
0
lib/Figments/Service.h
Normal file
40
lib/Figments/Surface.cpp
Normal file
40
lib/Figments/Surface.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "./Surface.h"
|
||||
#include "./Display.h"
|
||||
#include <ArduinoLog.h>
|
||||
|
||||
Surface::Surface(Display* dpy, const VirtualCoordinates& start, const VirtualCoordinates& end)
|
||||
: start(dpy->coordinateMapping()->virtualToPhysicalCoords(start)),
|
||||
end(dpy->coordinateMapping()->virtualToPhysicalCoords(end)),
|
||||
m_display(dpy)
|
||||
{
|
||||
}
|
||||
|
||||
Surface&
|
||||
Surface::operator=(const CRGB& color)
|
||||
{
|
||||
paintWith([&](CRGB& pixel) {
|
||||
pixel = color;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Surface&
|
||||
Surface::operator+=(const CRGB& color)
|
||||
{
|
||||
paintWith([&](CRGB& pixel) {
|
||||
pixel += color;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
Surface::paintWith(std::function<void(CRGB&)> func)
|
||||
{
|
||||
//Log.verbose("Painting startx=%d endx=%d starty=%d endy=%d", start.x, end.x, start.y, end.y);
|
||||
for(auto x = start.x; x <= end.x; x++) {
|
||||
for(auto y = start.y; y <= end.y; y++) {
|
||||
//Log.verbose("x=%d y=%d", x, y);
|
||||
func(m_display->pixelAt(PhysicalCoordinates{x, y}));
|
||||
}
|
||||
}
|
||||
}
|
21
lib/Figments/Surface.h
Normal file
21
lib/Figments/Surface.h
Normal file
@ -0,0 +1,21 @@
|
||||
#include <FastLED.h>
|
||||
#include "./Geometry.h"
|
||||
#include <functional>
|
||||
|
||||
class Display;
|
||||
|
||||
class Surface {
|
||||
public:
|
||||
Surface(Display* dpy, const VirtualCoordinates& start, const VirtualCoordinates& end);
|
||||
|
||||
Surface& operator=(const CRGB& color);
|
||||
Surface& operator+=(const CRGB& color);
|
||||
|
||||
void paintWith(std::function<void(CRGB&)> func);
|
||||
|
||||
const PhysicalCoordinates start;
|
||||
const PhysicalCoordinates end;
|
||||
|
||||
private:
|
||||
Display* m_display;
|
||||
};
|
46
lib/README
Normal file
46
lib/README
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
Reference in New Issue
Block a user