11 namespace poll = satcat5::poll;
20 #ifndef SATCAT5_PARANOIA
21 #define SATCAT5_PARANOIA 0
26 static unsigned panic(
const char* label) {
27 static constexpr
unsigned* NULLPTR = 0;
32 static unsigned panic(
const char* label) {
return 0;}
47 static TimeRef* g_main_timer = &null_timer;
53 static const char*
const LBL_POLL =
"POLL";
70 inline unsigned count()
const
71 {
return ListCore::len(m_item);}
77 bool pre_test_reset() {
79 if (ListCore::pre_test_reset<poll::Always>(g_list_always,
this)) {ok =
false;}
80 if (ListCore::pre_test_reset<poll::Timer>(g_list_timer, &clock)) {ok =
false;}
81 if (m_item) {m_item =
nullptr; ok =
false;}
82 if (m_next) {m_next =
nullptr; ok =
false;}
90 ListCore::remove(g_list_demand, ptr);
91 if (m_item) ListCore::remove(m_item, ptr);
102 inline void list_start() {
104 m_item = g_list_demand;
113 m_item = m_item->m_next;
122 if (!m_item) list_start();
123 if (SATCAT5_PARANOIA && ListCore::has_loop(m_item)) {
124 panic(
"poll_demand");
return;
136 if (!on_demand_helper.pre_test_reset()) ok =
false;
138 if (g_list_demand) {g_list_demand = 0; ok =
false;}
139 satcat5::datetime::clock.
reset(
true);
145 if (SATCAT5_PARANOIA && ListCore::has_loop(g_list_always)) {
146 panic(
"poll_always");
return;
162 while (g_list_demand && limit) {
172 #if SATCAT5_ALLOW_DELETION
173 poll::Always::~Always() {
180 return ListCore::len(g_list_always);
186 ListCore::add_safe(g_list_always,
this);
192 ListCore::remove(g_list_always,
this);
195 #if SATCAT5_ALLOW_DELETION
196 poll::OnDemand::~OnDemand() {
204 on_demand_helper.remove(
this);
214 if (SATCAT5_PARANOIA && ListCore::contains(g_list_demand,
this)) {
215 panic(
"poll_request");
217 ListCore::add(g_list_demand,
this);
227 on_demand_helper.remove(
this);
233 return ListCore::len(g_list_demand);
236 poll::Timekeeper::Timekeeper()
237 : m_tref(g_main_timer->now())
243 return g_main_timer != &null_timer;
253 g_main_timer = timer ? timer : &null_timer;
254 m_tref = g_main_timer->
now();
260 if (timer && timer->ticks_per_msec() > g_main_timer->
ticks_per_msec())
273 unsigned elapsed_msec = 1;
278 elapsed_msec = m_tref.increment_msec();
279 if (!elapsed_msec)
return;
282 if (SATCAT5_PARANOIA && ListCore::has_loop(g_list_timer)) {
283 panic(
"poll_timer");
return;
288 item->query(elapsed_msec);
300 ListCore::add(g_list_timer,
this);
303 #if SATCAT5_ALLOW_DELETION
304 poll::Timer::~Timer() {
307 ListCore::remove(g_list_timer,
this);
313 return ListCore::len(g_list_timer);
331 void poll::Timer::query(
unsigned elapsed_msec) {
332 if (m_trem > elapsed_msec) {
334 m_trem -= elapsed_msec;
338 unsigned ovr = elapsed_msec - m_trem;
343 m_trem = m_tnext - ovr;
344 }
else if (m_tnext) {
365 m_target->request_poll();
371 , m_tref(SATCAT5_CLOCK->now())
377 if (m_tref.interval_usec(m_interval))
378 m_target->request_poll();
void reset(bool full=false)
Reset internals after changes to SATCAT5_CLOCK.
VirtualTimer(satcat5::poll::OnDemand *obj, unsigned usec=1000)
Poll the designated object once every N microseconds.
void poll_always() override
Child class MUST override this method.
The Log class creates and formats one log message.
An "Always" object is polled whenever service() is called.
virtual void poll_always()=0
Child class MUST override this method.
static unsigned count_always()
Count active objects of this type.
void poll_register()
Register this pollable object, called by the constructor.
void poll_unregister()
Unregister this pollable object, called by the destructor.
Always(bool auto_register=true)
Registers this pollable object unless auto_register = false.
Global helper object that services all OnDemand objects.
void poll_always() override
Child class MUST override this method.
An "OnDemand" object is polled only on request.
virtual void poll_demand()=0
Deferred event handler, called after request().
void request_poll()
Call this method to request polling at a later time.
void request_cancel()
Call this method to cancel a previous request_poll().
static unsigned count_ondemand()
Count queued objects of this type (i.e., non-idle).
Global coordinator for multiple Timer objects.
void set_clock(satcat5::util::TimeRef *timer)
Immediately set the system time reference.
bool clock_ready() const
Has a system time reference been provided?
void suggest_clock(satcat5::util::TimeRef *timer)
Compare the provided reference to the current TimeRef, and keep whichever is "better" by an internal ...
bool pre_test_reset()
Reset timekeeper state at the start of each unit test.
satcat5::util::TimeRef * get_clock() const
Get the system time reference, if one is set.
void poll_demand() override
Deferred event handler, called after request().
void timer_event() override
Child class MUST override this method.
Timer objects are polled after a fixed delay or at a regular interval.
Timer()
Register object in the idle state.
void timer_stop()
Stop all future notifications.
void timer_once(unsigned msec)
Configure a one-time notification after X milliseconds.
static unsigned count_timer()
Count all objects of this type, including idle timers.
void timer_every(unsigned msec)
Configure a repeating notification every X milliseconds.
Helper functions for manipulating singly-linked lists.
Placeholder used if no timer is available.
The TimeRef API provides access to a monotonic time-counter.
u32 ticks_per_msec() const
Stable accessors for unit conversion.
TimeVal now()
Create a TimeVal object using the tick-count from raw().
Real-time clock conversion functions.
satcat5::datetime::Clock clock
Global instance of the datetime::Clock class.
Templated functions for manipulating singly-linked lists.
Diagnostic logging to UART and/or Ethernet ports.
Core event-processing loop for SatCat5 software.
Timekeeper timekeeper
There is a single global instance of the Timekeeper class.
bool pre_test_reset()
Hard-reset of global variables at the start of each unit test.
void service()
Single-pass service loop.
void service_all(unsigned limit=100)
Multi-pass service loop Calling this function regularly is required for SatCat5 operation.
Platform-agnostic API for interrupt management.