Born on Stahl's Birthday.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

353 lines
8.9 KiB

#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(u32 time)>;
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<auto F>
// struct FunctionPtr {
// constexpr FunctionPtr() = default;
// static void call()
// {
// F();
// }
// };
template<void (*TASK)(u32), int PERIOD>
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<void(u32 time)>;
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<typename T>
class Observer {
public:
bool on_change(T val_new, std::function<void(T val_current)> 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<void(T val_current)> 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<typename T>
class PollingObserver {
public:
using FetchCallback = std::function<T(void)>;
using DeliverCallback = std::function<void(T val_current)>;
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<typename T>
class Cache {
public:
using UpdateCallback = std::function<T(void)>;
using NotifyChangeCallback = std::function<void(Cache<T>&)>;
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<bool> cache{ [&]() -> bool { return read(); }, [](Cache<bool>&) {} };
private:
ld::GPIO gpio_{};
};
} // namespace Heck::Dizzy
#endif // HECK_DAISY_UTILS_HH`