1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#include <hilbert/kernel/timer.hpp>
namespace hilbert::kernel::timer {
struct sleeping_thread {
uint64_t sleeping_until;
application::thread *thread;
};
//sorted ascending by sleeping_until
static utility::list<sleeping_thread> *sleeping_threads;
uint64_t current_time;
//output is
// seconds | (minutes << 8) | (hours << 16) |
// (days << 24) | ( months << 32) | (years << 40)
extern "C" uint64_t get_time_from_rtc();
//index is (year % 4) * 12 + month - 1;
//output is days from january 1st 2000 to [month] 1st [year]
static uint16_t month_table[] {
0, 31, 60, 91, 121, 152,
182, 213, 244, 274, 305, 335,
366, 397, 425, 456, 486, 517,
547, 578, 609, 639, 670, 700,
731, 762, 790, 821, 851, 882,
912, 943, 974, 1004, 1035, 1065,
1096, 1127, 1155, 1186, 1216, 1247,
1277, 1308, 1339, 1369, 1400, 1430
};
//index is (year % 4) * 12 + month - 1;
//output is days in that month
static uint8_t month_table_2[] = {
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
void clamp(uint8_t &value, uint8_t min, uint8_t max) {
if (value < min)
value = min;
else if (value > max)
value = max;
}
extern "C" void enable_rtc_interrupts();
void init_timer() {
sleeping_threads = new utility::list<sleeping_thread>();
uint64_t rtc_time = get_time_from_rtc();
uint8_t years = rtc_time >> 40;
uint8_t months = (rtc_time >> 32) & 0xff;
uint8_t days = (rtc_time >> 24) & 0xff;
uint8_t hours = (rtc_time >> 16) & 0xff;
uint8_t minutes = (rtc_time >> 8) & 0xff;
uint8_t seconds = rtc_time & 0xff;
uint8_t month_table_index =
(years % 4) * 12 + months - 1;
clamp( years, 0, 99);
clamp( months, 1, 12);
clamp( days, 1, month_table_2[month_table_index]);
clamp( hours, 0, 23);
clamp(minutes, 0, 59);
clamp(seconds, 0, 59);
current_time = 1461 * (years / 4);
current_time += month_table[month_table_index];
current_time += days - 1;
current_time *= 86400;
current_time += hours * 3600;
current_time += minutes * 60;
current_time += seconds;
current_time *= 1024;
enable_rtc_interrupts();
}
void register_sleeping_thread(
uint64_t sleeping_until, application::thread *thread) {
auto *after = sleeping_threads->first;
while (after && after->value.sleeping_until < sleeping_until)
after = after->next;
sleeping_threads->insert_before(
{ .sleeping_until = sleeping_until, .thread = thread }, after);
}
extern "C" void acknowledge_rtc_interrupt();
extern "C" void on_rtc_interrupt() {
++current_time;
while (sleeping_threads->first &&
sleeping_threads->first->value.sleeping_until <=
current_time) {
application::paused_threads->insert(
sleeping_threads->first->value.thread);
sleeping_threads->remove(sleeping_threads->first);
}
acknowledge_rtc_interrupt();
}
}
|