summaryrefslogtreecommitdiff
path: root/arm9/lib/src/OS_alarm.c
diff options
context:
space:
mode:
authorCleverking2003 <30466983+Cleverking2003@users.noreply.github.com>2020-07-22 21:54:07 +0300
committerGitHub <noreply@github.com>2020-07-22 21:54:07 +0300
commit95d03abbfc10558d4a51f38d8131d47bbded6f8e (patch)
tree45f35a52ea8ff6021fc06ba1bf4690a83ce1de2c /arm9/lib/src/OS_alarm.c
parent7cd7b320d3336bdfe57b0a9d12174e32b242c088 (diff)
parent618a599c5bacc80d88c0d461ecb1efac7674dd7c (diff)
Merge pull request #242 from red031000/master
split mod05_021E1374 to mod05_02E1AD8 + arm9 OS_alarm
Diffstat (limited to 'arm9/lib/src/OS_alarm.c')
-rw-r--r--arm9/lib/src/OS_alarm.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/arm9/lib/src/OS_alarm.c b/arm9/lib/src/OS_alarm.c
new file mode 100644
index 00000000..1bd3ff2f
--- /dev/null
+++ b/arm9/lib/src/OS_alarm.c
@@ -0,0 +1,250 @@
+#include "function_target.h"
+#include "consts.h"
+#include "OS_alarm.h"
+#include "OS_interrupt.h"
+#include "OS_irqTable.h"
+#include "OS_terminate_proc.h"
+#include "OS_system.h"
+
+static struct OSiAlarmQueue OSi_AlarmQueue;
+
+static u16 OSi_UseAlarm = FALSE;
+
+ARM_FUNC static void OSi_SetTimer(OSAlarm *alarm)
+{
+ OSTick tick = OS_GetTick();
+
+ OS_SetTimerControl(OS_TIMER_1, 0);
+
+ s64 delta = (s64)(alarm->fire - tick);
+
+ OSi_EnterTimerCallback(OS_TIMER_1, OSi_AlarmHandler, NULL);
+
+ u16 timerCount;
+ if (delta < 0)
+ {
+ timerCount = (u16)~1;
+ }
+ else if (delta < 0x10000)
+ {
+ timerCount = (u16)(~delta);
+ }
+ else
+ {
+ timerCount = 0;
+ }
+
+ OS_SetTimerCount((OSTimer)OS_TIMER_1, timerCount);
+ OS_SetTimerControl(OS_TIMER_1, (u16)OSi_TICK_TIMERCONTROL);
+
+ (void)OS_EnableIrqMask(OS_IE_TIMER1);
+}
+
+ARM_FUNC void OS_InitAlarm(void)
+{
+ if (!OSi_UseAlarm)
+ {
+ OSi_UseAlarm = TRUE;
+
+ OSi_SetTimerReserved(OS_TIMER_1);
+
+ OSi_AlarmQueue.head = NULL;
+ OSi_AlarmQueue.tail = NULL;
+
+ (void)OS_DisableIrqMask(OS_IE_TIMER1);
+ }
+}
+
+ARM_FUNC BOOL OS_IsAlarmAvailable(void)
+{
+ return OSi_UseAlarm;
+}
+
+ARM_FUNC void OS_CreateAlarm(OSAlarm *alarm)
+{
+ alarm->handler = 0;
+ alarm->tag = 0;
+}
+
+ARM_FUNC static void OSi_InsertAlarm(OSAlarm *alarm, OSTick fire)
+{
+ if (alarm->period > 0)
+ {
+ OSTick tick = OS_GetTick();
+
+ fire = alarm->start;
+ if (alarm->start < tick)
+ {
+ fire += alarm->period * ((tick - alarm->start) / alarm->period + 1);
+ }
+ }
+
+ alarm->fire = fire;
+
+ OSAlarm *prev;
+ OSAlarm *next;
+
+ for (next = OSi_AlarmQueue.head; next; next = next->next)
+ {
+ if ((s64)(fire - next->fire) >= 0)
+ {
+ continue;
+ }
+
+ alarm->prev = next->prev;
+ next->prev = alarm;
+ alarm->next = next;
+ prev = alarm->prev;
+ if (prev)
+ {
+ prev->next = alarm;
+ }
+ else
+ {
+ OSi_AlarmQueue.head = alarm;
+ OSi_SetTimer(alarm);
+ }
+
+ return;
+ }
+
+ alarm->next = 0;
+ prev = OSi_AlarmQueue.tail;
+ OSi_AlarmQueue.tail = alarm;
+ alarm->prev = prev;
+ if (prev)
+ {
+ prev->next = alarm;
+ }
+ else
+ {
+ OSi_AlarmQueue.head = OSi_AlarmQueue.tail = alarm;
+ OSi_SetTimer(alarm);
+ }
+}
+
+ARM_FUNC void OS_SetAlarm(OSAlarm * alarm, OSTick tick, OSAlarmHandler handler, void *arg)
+{
+ if (!alarm || alarm->handler)
+ {
+ OS_Terminate();
+ }
+
+ OSIntrMode enabled = OS_DisableInterrupts();
+
+ alarm->period = 0;
+
+ alarm->handler = handler;
+ alarm->arg = arg;
+
+ OSi_InsertAlarm(alarm, OS_GetTick() + tick);
+
+ (void)OS_RestoreInterrupts(enabled);
+}
+
+ARM_FUNC void OS_CancelAlarm(OSAlarm *alarm)
+{
+ OSIntrMode enabled = OS_DisableInterrupts();
+
+ if (!alarm->handler)
+ {
+ (void)OS_RestoreInterrupts(enabled);
+ return;
+ }
+
+ OSAlarm *next = alarm->next;
+
+ if (!next)
+ {
+ OSi_AlarmQueue.tail = alarm->prev;
+ }
+ else
+ {
+ next->prev = alarm->prev;
+ }
+
+ if (alarm->prev)
+ {
+ alarm->prev->next = next;
+ }
+ else
+ {
+ OSi_AlarmQueue.head = next;
+ if (next)
+ {
+ OSi_SetTimer(next);
+ }
+ }
+
+ alarm->handler = NULL;
+ alarm->period = 0;
+
+ (void)OS_RestoreInterrupts(enabled);
+}
+
+ARM_FUNC asm void OSi_AlarmHandler(void *arg)
+{
+ stmfd sp!, {r0, lr}
+ bl OSi_ArrangeTimer
+ ldmfd sp!, {r0, lr}
+ bx lr
+}
+
+ARM_FUNC static void OSi_ArrangeTimer(void)
+{
+ OS_SetTimerControl(OS_TIMER_1, 0);
+
+ (void)OS_DisableIrqMask(OS_IE_TIMER1);
+
+ OS_SetIrqCheckFlag(OS_IE_TIMER1);
+
+ OSTick tick = OS_GetTick();
+
+ OSAlarm *alarm = OSi_AlarmQueue.head;
+
+ if (!alarm)
+ {
+ return;
+ }
+
+ if (tick < alarm->fire)
+ {
+ OSi_SetTimer(alarm);
+ return;
+ }
+
+ OSAlarm *next = alarm->next;
+ OSi_AlarmQueue.head = next;
+
+ if (!next)
+ {
+ OSi_AlarmQueue.tail = NULL;
+ }
+ else
+ {
+ next->prev = NULL;
+ }
+
+ OSAlarmHandler handler = alarm->handler;
+
+ if (!alarm->period)
+ {
+ alarm->handler = NULL;
+ }
+
+ if (handler)
+ {
+ (handler)(alarm->arg);
+ }
+
+ if (alarm->period > 0)
+ {
+ alarm->handler = handler;
+ OSi_InsertAlarm(alarm, 0);
+ }
+
+ if (OSi_AlarmQueue.head)
+ {
+ OSi_SetTimer(OSi_AlarmQueue.head);
+ }
+}