#include "Jtk.h" #include #include #include typedef struct { uint64_t next; /**< Time the timer next expires (us). */ uint64_t interval; /**< Timer interval (us). */ size_t id; /**< Timer ID. */ void * user[2]; /**< User data pointers. */ } Timer; /** Vector used to allocate timer IDs. */ static std::vector> g_timers; /** Linked list used to traverse all active timers. */ static std::list> g_active_timers; static size_t AllocateTimerID() { for (size_t i = 0; i < g_timers.size(); i++) { if (!g_timers[i]) { return i; } } g_timers.push_back(nullptr); return g_timers.size() - 1u; } /** * Add a timer. * * @param delay * Delay time in milliseconds. * @param interval * Interval time in milliseconds. A value of 0 indicates that the timer * is not periodic. * @param user1 * User data pointer 1. This value is not used by Jtk but can be retrieved by * the user when a timer expires. * @param user2 * User data pointer 2. This value is not used by Jtk but can be retrieved by * the user when a timer expires. * * @return * Timer ID. */ size_t Jtk_AddTimer(uint32_t delay, uint32_t interval, void * user1, void * user2) { uint64_t current_system_time = Jtk_UsTime(); size_t timer_id = AllocateTimerID(); auto timer = std::make_shared(); timer->next = current_system_time + (delay * 1000u); timer->interval = interval * 1000u; timer->id = timer_id; timer->user[0] = user1; timer->user[1] = user2; g_timers[timer_id] = timer; g_active_timers.push_back(timer); return timer_id; } /** * Remove a timer. * * @param timer_id * The ID of the timer to remove. */ void Jtk_RemoveTimer(size_t timer_id) { if (timer_id < g_timers.size()) { auto timer = g_timers[timer_id]; g_active_timers.remove(timer); g_timers[timer_id] = nullptr; } } /** * Determine the amount of time until the next timer expires (in us). * * @return * Time (in us) until the next timer expires. This will be 0 if an active * timer has already expired, and will be (uint64_t)-1 if there are no * active timers. */ uint64_t Jtk_TimeToNextTimerExpiration() { uint64_t time = (uint64_t)-1; uint64_t current_system_time = Jtk_UsTime(); for (auto & timer : g_active_timers) { if (timer->next <= current_system_time) { return 0; } uint64_t time_until_this_timer = timer->next - current_system_time; if (time_until_this_timer < time) { time = time_until_this_timer; } } return time; } /** * Service a timer. * * This will increment the timer's next activation time by its interval, or * for a timer with an interval of 0, will remove the timer. * * @param timer_id * The ID of the timer to service. */ void Jtk_ServiceTimer(size_t timer_id) { auto timer = g_timers[timer_id]; if (timer->interval == 0u) { Jtk_RemoveTimer(timer_id); } else { timer->next += timer->interval; } } /** * Return the ID of an expired timer. * * @return * The ID of an expired timer, or (size_t)-1 if no timer is expired. */ size_t Jtk_GetExpiredTimer() { uint64_t current_system_time = Jtk_UsTime(); for (auto & timer : g_active_timers) { if (timer->next <= current_system_time) { return timer->id; } } return (size_t)-1; } void * Jtk_GetTimerUserData(size_t timer_id, uint8_t index) { if (timer_id < g_timers.size()) { return g_timers[timer_id]->user[index]; } return nullptr; }