#ifndef HECK_DIZZY_UTILS_HH #define HECK_DIZZY_UTILS_HH #include "dizzy_types.hh" // --------------------------------------------------------- // String representations // --------------------------------------------------------- namespace Heck::Dizzy { void GetMidiTypeAsString(const ld::MidiEvent& msg, char* str); void GetMidiRTTypeAsString(const ld::MidiEvent& msg, char* str); } // namespace Heck::Dizzy // --------------------------------------------------------- // Scaling // --------------------------------------------------------- namespace Heck::Dizzy { float scalen_min_max(float val, float min, float max); float scalen_center_range(float val, float center, float range); } // namespace Heck::Dizzy // --------------------------------------------------------- // SWTimer // --------------------------------------------------------- namespace Heck::Dizzy { class SWTimer { public: using Callback = std::function; void set_period(u32 time_units); void set_callback(const Callback& cb); bool is_it_already_time_again(u32 time_now); private: Callback callback_{}; u32 time_last_exec_{}; u32 time_period_{}; }; // !!! // constexpr function pointer // !!! // template // struct FunctionPtr { // constexpr FunctionPtr() = default; // static void call() // { // F(); // } // }; template class PeriodicTaskCT { public: PeriodicTaskCT() = default; PeriodicTaskCT(PeriodicTaskCT&) = delete; PeriodicTaskCT& operator=(PeriodicTaskCT&) = delete; PeriodicTaskCT(PeriodicTaskCT&&) = delete; PeriodicTaskCT& operator=(PeriodicTaskCT&&) = delete; ~PeriodicTaskCT() = default; bool run_pending(u32 time_now) { if (time_now - time_last_exec_ >= PERIOD) { time_last_exec_ = time_now; TASK(time_now); return true; } return false; } private: u32 time_last_exec_{}; }; class PeriodicTask { public: using Task = std::function; PeriodicTask() = delete; ~PeriodicTask() = default; PeriodicTask(u32 period, Task t) { init(period, t); } PeriodicTask(PeriodicTask&) = delete; PeriodicTask& operator=(PeriodicTask&) = delete; PeriodicTask(PeriodicTask&&) = delete; PeriodicTask& operator=(PeriodicTask&&) = delete; void set_period(u32 time_units) { time_period_ = time_units; } void set_task(Task t) { task_ = t; } bool run_pending(u32 time_now) { if (time_now - time_last_exec_ >= time_period_) { time_last_exec_ = time_now; if (task_) { //todo: constexpr if metrics task_(time_now); } return true; } return false; } private: void init(u32 period, Task t) { set_period(period); set_task(t); } Task task_{}; u32 time_last_exec_{}; u32 time_period_{}; }; } // namespace Heck::Dizzy // --------------------------------------------------------- // Observer // --------------------------------------------------------- namespace Heck::Dizzy { template class Observer { public: bool on_change(T val_new, std::function fn) { if (val_new != val_current_) { val_current_ = val_new; fn(val_current_); return true; } return false; } bool on_change_fuzzy(T val_new, T min_deviation, std::function fn) { if (std::abs(val_new - val_current_) >= min_deviation) { val_current_ = val_new; fn(val_current_); return true; } return false; } private: T val_current_{}; }; template class PollingObserver { public: using FetchCallback = std::function; using DeliverCallback = std::function; PollingObserver() = delete; ~PollingObserver() = default; explicit PollingObserver(FetchCallback fetch_cb, DeliverCallback deliver_cb) { init(fetch_cb, deliver_cb); } PollingObserver(PollingObserver&) = delete; PollingObserver& operator=(PollingObserver) = delete; PollingObserver(PollingObserver&&) = delete; PollingObserver& operator=(PollingObserver&&) = delete; void set_fetch_callback(FetchCallback cb) { fetch_cb_ = cb; } void set_deliver_callback(DeliverCallback cb) { deliver_cb_ = cb; } bool fetch_and_deliver() { T val_fetched{ fetch_cb_() }; if (val_fetched != val_current_) { val_current_ = val_fetched; deliver_cb_(val_current_); return true; } return false; } bool fetch_and_deliver_fuzzy(T min_deviation) { T val_fetched{ fetch_cb_() }; if (std::abs(val_fetched - val_current_) >= min_deviation) { val_current_ = val_fetched; deliver_cb_(val_current_); return true; } return false; } private: void init(FetchCallback fetch_cb, DeliverCallback deliver_cb) { set_fetch_callback(fetch_cb); set_deliver_callback(deliver_cb); } T val_current_{}; FetchCallback fetch_cb_{}; DeliverCallback deliver_cb_{}; }; } // namespace Heck::Dizzy // --------------------------------------------------------- // Cache // --------------------------------------------------------- namespace Heck::Dizzy { template class Cache { public: using UpdateCallback = std::function; using NotifyChangeCallback = std::function&)>; explicit Cache(UpdateCallback update_cb, NotifyChangeCallback notify_change_cb) { init(update_cb, notify_change_cb); } Cache() = delete; Cache(Cache&) = delete; Cache& operator=(Cache) = delete; Cache(Cache&&) = delete; Cache& operator=(Cache&&) = delete; ~Cache() = default; T read() { return val_current_; } void set_update_callback(UpdateCallback cb) { update_cb_ = cb; } void set_notify_change_callback(NotifyChangeCallback cb) { notify_change_cb_ = cb; } bool update_and_notify_change() { T val_fetched{ update_cb_() }; if (val_fetched != val_current_) { val_current_ = val_fetched; notify_change_cb_(*this); return true; } return false; } bool update_and_notify_change_fuzzy(T min_deviation) { T val_fetched{ update_cb_() }; if (std::abs(val_fetched - val_current_) >= min_deviation) { val_current_ = val_fetched; notify_change_cb_(*this); return true; } return false; } private: void init(UpdateCallback fetch_cb, NotifyChangeCallback deliver_cb) { set_update_callback(fetch_cb); set_notify_change_callback(deliver_cb); } T val_current_{}; UpdateCallback update_cb_{}; NotifyChangeCallback notify_change_cb_{}; }; } // namespace Heck::Dizzy // --------------------------------------------------------- // DigitalIn // --------------------------------------------------------- namespace Heck::Dizzy { struct DigitalIn { public: DigitalIn() = default; ~DigitalIn() = default; DigitalIn(u8 daisy_pin) { init(daisy_pin); } DigitalIn(DigitalIn&) = delete; DigitalIn& operator=(DigitalIn&) = delete; DigitalIn(DigitalIn&&) = delete; DigitalIn& operator=(DigitalIn&&) = delete; void init(u8 daisy_pin) { gpio_.Init(ld::DaisySeed::GetPin(daisy_pin), ld::GPIO::Mode::INPUT, ld::GPIO::Pull::PULLUP); } bool read() { return !gpio_.Read(); } Cache cache{ [&]() -> bool { return read(); }, [](Cache&) {} }; private: ld::GPIO gpio_{}; }; } // namespace Heck::Dizzy #endif // HECK_DAISY_UTILS_HH`