-
Notifications
You must be signed in to change notification settings - Fork 578
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
edd6435
commit 49b2cba
Showing
2 changed files
with
225 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <unistd.h> | ||
#include <limits.h> | ||
|
||
/* Free timers is a stack of available timer offsets */ | ||
unsigned int freeTimersHead = 0; | ||
unsigned int freeTimers[1000000]; | ||
|
||
/* Every timer is a bunch of components */ | ||
unsigned int componentMultiplierMs[5] = {10, 50, 100, 500, 1000}; | ||
|
||
struct Timer { | ||
/* Offsets in timers array */ | ||
unsigned int next, prev; | ||
|
||
/* The components remaining for this untriggered run */ | ||
unsigned int components[5]; | ||
|
||
/* We need to track the original Ms in case of repeat timers */ | ||
unsigned int nextOriginalMs; | ||
|
||
/* Overshoot Ms is used to track accumulated overshoot and to remove smallest 10ms when overshot more than 10ms */ | ||
unsigned int overshootMs; | ||
|
||
/* What list the timer is in */ | ||
unsigned int componentOffset; | ||
}; | ||
|
||
/* Timers are strides over an integer array */ | ||
struct Timer timers[1000000]; | ||
|
||
/* Timer to registered callback */ | ||
void (*timerCallbacks[1000000])(); | ||
|
||
/* Per component timer doubly linked list (head) */ | ||
unsigned int timerListHead[5] = {UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX}; | ||
|
||
void cb() { | ||
printf("A timer triggered!\n"); | ||
} | ||
|
||
void init() { | ||
freeTimersHead = 0; | ||
for (int i = 0; i < 1000000; i++) { | ||
freeTimers[i] = i; | ||
} | ||
for (int i = 0; i < 5; i++) { | ||
timerListHead[i] = UINT_MAX; | ||
} | ||
} | ||
|
||
unsigned int allocateTimer() { | ||
freeTimersHead++; | ||
//printf("Allocating timer: %d\n", freeTimers[freeTimersHead - 1]); | ||
return freeTimers[freeTimersHead - 1]; | ||
} | ||
|
||
void freeTimer(unsigned int timer) { | ||
//printf("Freeing timer: %d\n", timer); | ||
freeTimersHead--; | ||
freeTimers[freeTimersHead] = timer; | ||
} | ||
|
||
unsigned int divideComponents(unsigned int components[5], unsigned int *biggestSetComponent, unsigned int ms) { | ||
/* Start on fifth component */ | ||
int biggestComponent = 4; | ||
|
||
while (ms > 0 && biggestComponent >= 0) { | ||
/* Can we divide by this component? */ | ||
if (ms >= componentMultiplierMs[biggestComponent]) { | ||
components[biggestComponent] = ms / componentMultiplierMs[biggestComponent]; | ||
ms -= components[biggestComponent] * componentMultiplierMs[biggestComponent]; | ||
|
||
if (*biggestSetComponent < biggestComponent) { | ||
*biggestSetComponent = biggestComponent; | ||
} | ||
} | ||
biggestComponent--; | ||
} | ||
|
||
unsigned int overshoot = 0; | ||
if (ms) { | ||
components[0]++; | ||
overshoot = 10 - ms; | ||
} | ||
|
||
/* Return the overshoot */ | ||
return overshoot; | ||
} | ||
|
||
void addTimerToList(unsigned int timer, unsigned int componentOffset) { | ||
unsigned int head = timerListHead[componentOffset]; | ||
timers[timer].next = head; | ||
timers[timer].prev = UINT_MAX; | ||
if (head != UINT_MAX) { | ||
timers[head].prev = timer; | ||
} | ||
timerListHead[componentOffset] = timer; | ||
|
||
/* Track what list the timer is in */ | ||
timers[timer].componentOffset = componentOffset; | ||
} | ||
|
||
/* Returns the next timer in the list or UINT_MAX */ | ||
unsigned int removeTimerFromList(unsigned int timer, unsigned int componentOffset) { | ||
unsigned int prev = timers[timer].prev; | ||
unsigned int next = timers[timer].next; | ||
|
||
if (prev != UINT_MAX) { | ||
timers[prev].next = next; | ||
} else { | ||
timerListHead[componentOffset] = next; | ||
} | ||
|
||
if (next != UINT_MAX) { | ||
timers[next].prev = prev; | ||
} | ||
|
||
return next; | ||
} | ||
|
||
unsigned int moveTimerToList(unsigned int timer, unsigned int newComponentOffset) { | ||
unsigned int currentComponentOffset = timers[timer].componentOffset; | ||
unsigned int nextTimer = removeTimerFromList(timer, currentComponentOffset); | ||
addTimerToList(timer, newComponentOffset); | ||
return nextTimer; | ||
} | ||
|
||
/* Trigger a tick of the given component offset, to be called from system timers */ | ||
void tick(unsigned int componentOffset) { | ||
//printf("Tick for %d\n", componentOffset); | ||
|
||
/* Iterate this list, decrementing the timer components */ | ||
unsigned int timerIterator = timerListHead[componentOffset]; | ||
|
||
while (timerIterator != UINT_MAX) { | ||
//printf("Iterating timer %d\n", timerIterator); | ||
|
||
/* This timer needs to move to a higher precision list, or trigger */ | ||
if (!--timers[timerIterator].components[componentOffset]) { | ||
|
||
/* Seek to next non-null component or the 0th component */ | ||
unsigned int nextComponentOffsetForTimer = componentOffset; | ||
while (nextComponentOffsetForTimer && timers[timerIterator].components[nextComponentOffsetForTimer] == 0) { | ||
nextComponentOffsetForTimer--; | ||
} | ||
|
||
/* Here we either have a new list to join or we trigger the timer here and now */ | ||
if (timers[timerIterator].components[nextComponentOffsetForTimer]) { | ||
/* This should return the next timerIterator */ | ||
timerIterator = moveTimerToList(timerIterator, nextComponentOffsetForTimer); | ||
} else { | ||
/* This callback must not modify the list (but we can handle that later!) */ | ||
timerCallbacks[timerIterator](); | ||
|
||
/* If the timer itself is removed in the above callback, below removal will fail */ | ||
|
||
/* And remove the timer (this should return the next timerIterator) */ | ||
timerIterator = removeTimerFromList(timerIterator, componentOffset); | ||
} | ||
} else { | ||
timerIterator = timers[timerIterator].next; | ||
} | ||
} | ||
} | ||
|
||
unsigned int setTimeout_(void (*cb)(), unsigned int ms) { | ||
/* Allocate free timer */ | ||
unsigned int timer = allocateTimer(); | ||
|
||
/* Divide given ms in components */ | ||
unsigned int biggestSetComponent = 0; | ||
timers[timer].overshootMs = divideComponents(timers[timer].components, &biggestSetComponent, ms); | ||
|
||
//printf("Overshoot by %u ms\n", timers[timer].overshootMs); | ||
//printf("Biggest set component is %u\n", biggestSetComponent); | ||
|
||
/* Add the timer to the list of the highest component */ | ||
addTimerToList(timer, biggestSetComponent); | ||
|
||
/* Set the callback */ | ||
timerCallbacks[timer] = cb; | ||
|
||
return timer; | ||
} | ||
|
||
void clearTimeout_(unsigned int timer) { | ||
/* Unlink the timer from its list */ | ||
removeTimerFromList(timer, timers[timer].componentOffset); | ||
|
||
/* Put the timer into free timer circle buffer */ | ||
freeTimer(timer); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters