-
Notifications
You must be signed in to change notification settings - Fork 1
/
muos.c
283 lines (230 loc) · 6.06 KB
/
muos.c
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/*
* mµOS - my micro OS
*
* Copyright (C)
* 2015 Christian Thäter <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <muos/muos.h>
#include <muos/error.h>
#include <muos/clock.h>
#include <muos/rtq.h>
#include <muos/hpq.h>
#include <muos/bgq.h>
#include <muos/clpq.h>
#include <muos/serial.h>
#include <muos/stepper.h>
#include <muos/cppm.h>
#include <muos/stck.h>
#include <stdlib.h>
//PLANNED: stash muos_now_ away on recursive mainloops
//PLANNED: make ERRORFN optional
//PLANNED: ignoremask for ERRORFN for errors handled elsewhere
//PLANNED: instead disabling interrupts have a mutex and temp buffer for work queues
//PLANNED: finer locking in mainloop instead interrupt disable, per queue
//PLANNED: error_set hook for debugging
//PLANNED: example sections in all API doc
//PLANNED: find some way to get rid of most of the *_isr variants at compiletime
volatile bool muos_ready;
//PLANNED: document and implement
void muos_die (void)
{
muos_interrupt_disable ();
muos_hw_shutdown (); //FIXME: let it fallthrough
abort ();
}
#if defined(MUOS_YIELD_DEPTH) || defined(MUOS_WAIT_DEPTH)
static uint8_t sched_depth_;
uint8_t
muos_sched_depth (void)
{
return sched_depth_;
}
#endif
static bool
sched_loop (muos_wait_fn fn, void* param, bool sleep)
{
MUOS_DEBUG_BUSY_ON;
muos_interrupt_disable ();
do
{
do
{
do
{
do
{
if (fn && fn (param))
{
muos_interrupt_enable ();
return true;
}
#if defined(MUOS_STCK) && defined(MUOS_STCK_AUTO)
if (!muos_stck_check (MUOS_STCK_AUTO))
muos_error_set_isr (muos_fatal_stack_overflow);
#endif
#ifdef MUOS_ERRORFN
if (muos_error_pending ())
{
MUOS_ERRORFN ();
}
#endif
muos_interrupt_disable ();
MUOS_DEBUG_SWITCH_TOGGLE;
//PLANNED: how to ensure that lower pri queues don't stall?
}
while (muos_rtq_schedule ()); //FIXME: rename schedule to scheduler_isr
}
while (muos_clpq_schedule_isr ());
}
while (muos_hpq_schedule ());
}
while (muos_bgq_schedule ());
#ifdef MUOS_SCHED_SLEEP
if (sleep && muos_hw_clpq_wake_isr ())
{
//TODO: select sleep mode depending on active hardware (adc, usart)
muos_hw_sleep_prepare (MUOS_SCHED_SLEEP);
do
{
// muos_hw_sleep () enables interrupts while sleeping
muos_hw_sleep ();
}
while (!muos_ready);
muos_ready = false;
muos_hw_sleep_done ();
}
#else
(void) sleep;
#endif // MUOS_SCHED_SLEEP
muos_interrupt_enable ();
return false;
}
#ifdef MUOS_YIELD_DEPTH
static bool
yield_countdown (void* count)
{
return *(uint8_t*)count--;
}
muos_error
muos_yield (uint8_t count)
{
//TODO: add 'sleep' parameter
if (sched_depth_ >= MUOS_YIELD_DEPTH)
{
return muos_warn_sched_depth;
}
++sched_depth_;
sched_loop (yield_countdown, &count, true);
--sched_depth_;
return muos_success;
}
#endif
#ifdef MUOS_WAIT_DEPTH
struct wait_data
{
muos_wait_fn fn;
void* param;
muos_clock wakeup;
muos_error ret;
};
static bool
wait_predicate (void* data)
{
if (((struct wait_data*)data)->fn && ((struct wait_data*)data)->fn (((struct wait_data*)data)->param))
{
muos_clpq_remove (&((struct wait_data*)data)->wakeup, NULL);
return true;
}
if (muos_clock_is_expired (&((struct wait_data*)data)->wakeup))
{
((struct wait_data*)data)->ret = muos_warn_wait_timeout;
return true;
}
return false;
}
muos_error
muos_wait (muos_wait_fn fn, void* param, muos_clock16 timeout)
{
if (sched_depth_ >= MUOS_WAIT_DEPTH)
{
return muos_warn_sched_depth;
}
++sched_depth_;
struct wait_data data;
data.fn = fn;
data.param = param;
muos_clock_now (&data.wakeup);
muos_clock_add16 (&data.wakeup, timeout);
while ((data.ret = muos_clpq_at (&data.wakeup, NULL, true)) == muos_error_clpq_nounique)
muos_clock_add8 (&data.wakeup, 1);
if (data.ret == muos_success)
{
while (!sched_loop (wait_predicate, &data, true));
}
--sched_depth_;
return data.ret;
}
muos_error
muos_wait_poll (muos_wait_fn fn, void* param, muos_clock16 timeout, uint32_t rep)
{
while (rep--)
{
muos_error err = muos_wait (fn, param, timeout);
if (err != muos_warn_wait_timeout)
return err;
}
return muos_warn_wait_timeout;
}
#endif
//TODO: since we autogenerate declarations here, remove them from header files
#define MUOS_INIT(fn) void fn(void)
#include <muos/init.inc>
#undef MUOS_INIT
void
muos_init (void)
{
#define MUOS_INIT(fn) fn()
#include <muos/init.inc>
#undef MUOS_INIT
}
int __attribute__((OS_main))
main()
{
MUOS_HW_INIT;
#ifdef MUOS_STCK
muos_stck_init ();
#endif // MUOS_STCK
//TODO: how to init all muos structures .. #define MUOS_EXPLICIT_INIT
#if defined(MUOS_CLPQ_LENGTH) && MUOS_CLPQ_LENGTH>0
//PLANNED: clpq calibration
#endif
#ifdef MUOS_DEBUG
muos_hw_debug_init ();
#endif
#if MUOS_HPQ_LENGTH >= 2
muos_hpq_push (MUOS_INITFN);
muos_hpq_push (muos_init);
#elif MUOS_BGQ_LENGTH >= 2
muos_bgq_push (MUOS_INITFN);
muos_bgq_push (muos_init);
#else
MUOS_INITFN ();
muos_init ();
#endif
muos_interrupt_enable ();
while (1)
sched_loop (NULL, NULL, true);
}