Skip to content

Instantly share code, notes, and snippets.

@hare1039
Last active August 5, 2020 01:08
Show Gist options
  • Save hare1039/2547f103d588c8aae1c08a42e87c5da4 to your computer and use it in GitHub Desktop.
Save hare1039/2547f103d588c8aae1c08a42e87c5da4 to your computer and use it in GitHub Desktop.
#include <ArduinoSTL.h>
#include <vector>
#include <functional>
using arduino_time_t = unsigned long;
using function_ptr = void (*)();
class dispatcher
{
static inline arduino_time_t now() { return millis(); }
public:
struct animation
{
arduino_time_t const duration;
function_ptr const callable;
arduino_time_t actual_time;
};
private:
std::vector<animation> animations_;
arduino_time_t start_ {now()};
public:
dispatcher(std::initializer_list<animation> animations):
animations_ {animations}
{
restart();
}
dispatcher& restart()
{
start_ = now();
arduino_time_t prev = 0;
for (animation& ani : animations_)
prev = ani.actual_time = prev + ani.duration;
return *this;
}
dispatcher& stop()
{
std::vector<animation>().swap(animations_);
return *this;
}
dispatcher& skip()
{
for (animation& ani : animations_)
{
if (now() < (ani.actual_time + start_))
{
start_ -= (ani.actual_time + start_ - now());
break;
}
}
return *this;
}
void operator() () { run(); }
void run ()
{
for (animation& ani : animations_)
{
if (now() < (ani.actual_time + start_))
{
ani.callable();
break;
}
}
}
};
template<typename T>
class once
{
T data_;
bool locked = false;
public:
once(T t): data_{t} {}
operator T* ()
{
if (locked)
return nullptr;
locked = true;
return &data_;
}
void unlock() { locked = false; }
};
class led_controller
{
int pin_ = 0;
dispatcher* control_ = nullptr;
public:
once<int> current_;
int amount = 1;
public:
led_controller(int pin, int start): pin_{pin}, current_{start} {}
void set(dispatcher * v) { control_ = v; control_->restart(); }
void run() { if (control_) { control_->run(); } }
void apply()
{
current_.unlock();
int* current = current_;
analogWrite(pin_, *current);
}
void off()
{
digitalWrite(pin_, LOW);
}
};
led_controller nine{9, 2};
dispatcher nine_dispatcher
{
dispatcher::animation{100, []() { nine.current_.unlock(); nine_dispatcher.skip(); }},
dispatcher::animation{20, []() {
int * current = nine.current_;
if (current)
{
if (*current >= 15 || *current <= 1)
nine.amount = -nine.amount;
(*current) += nine.amount;
}
}},
dispatcher::animation{30, []() { nine.apply(); nine_dispatcher.restart(); }}
};
dispatcher nine_fast_flash
{
dispatcher::animation{100, []() { nine.apply(); }},
dispatcher::animation{100, []() { nine.off(); }},
dispatcher::animation{30, []() { nine_fast_flash.restart(); }}
};
led_controller ten{10, 11};
dispatcher ten_dispatcher
{
dispatcher::animation{100, []() { ten.current_.unlock(); ten_dispatcher.skip(); }},
dispatcher::animation{45, []() {
int * current = ten.current_;
if (current)
{
if (*current >= 20 || *current <= 1)
ten.amount = -ten.amount;
(*current) += ten.amount;
}
}},
dispatcher::animation{30, []() { ten.apply(); ten_dispatcher.restart(); }}
};
dispatcher ten_fast_flash
{
dispatcher::animation{30, []() { ten.apply(); }},
dispatcher::animation{30, []() { ten.off(); }},
dispatcher::animation{30, []() { ten_fast_flash.restart(); }}
};
void setup()
{
Serial.begin(9600);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
delay(100);
nine.set(&nine_dispatcher);
ten.set(&ten_dispatcher);
}
bool have_lights = false;
void loop()
{
int v = analogRead(A1);
bool new_status = v < 500;
if (have_lights != new_status)
{
Serial.print (have_lights);
if (have_lights)
{
nine.set(&nine_dispatcher);
ten.set(&ten_dispatcher);
}
else
{
nine.set(&nine_fast_flash);
ten.set(&ten_fast_flash);
}
}
have_lights = new_status;
nine.run();
ten.run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment