-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathequeue_mbed.cpp
214 lines (169 loc) · 5.19 KB
/
equeue_mbed.cpp
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
/*
* Implementation for the mbed library
* https://github.com/mbedmicro/mbed
*
* Copyright (c) 2016 Christopher Haster
* Distributed under the MIT license
*/
#include "equeue_platform.h"
#if defined(EQUEUE_PLATFORM_MBED)
#include <stdbool.h>
#include <string.h>
#include "platform/mbed_critical.h"
#include "drivers/Timer.h"
#include "drivers/Ticker.h"
#include "drivers/Timeout.h"
#include "drivers/LowPowerTimeout.h"
#include "drivers/LowPowerTicker.h"
#include "drivers/LowPowerTimer.h"
using namespace mbed;
// Ticker operations
#if MBED_CONF_RTOS_API_PRESENT
#include "rtos/Kernel.h"
#include "platform/mbed_os_timer.h"
static bool equeue_tick_inited = false;
static void equeue_tick_init() {
#if defined MBED_TICKLESS || !MBED_CONF_RTOS_PRESENT
mbed::internal::init_os_timer();
#endif
equeue_tick_inited = true;
}
unsigned equeue_tick() {
if (!equeue_tick_inited) {
equeue_tick_init();
}
#if defined MBED_TICKLESS || !MBED_CONF_RTOS_PRESENT
// It is not safe to call get_ms_count from ISRs, both
// because documentation says so, and because it will give
// a stale value from the RTOS if the interrupt has woken
// us out of sleep - the RTOS will not have updated its
// ticks yet.
if (core_util_is_isr_active()) {
// And the documentation further says that this
// should not be called from critical sections, for
// performance reasons, but I don't have a good
// current alternative!
return mbed::internal::os_timer->get_time() / 1000;
} else {
return rtos::Kernel::get_ms_count();
}
#else
// And this is the legacy behaviour - if running in
// non-tickless mode, this works fine, despite Mbed OS
// documentation saying no. (Most recent CMSIS-RTOS
// permits `ososKernelGetTickCount` from IRQ, and our
// `rtos::Kernel` wrapper copes too).
return rtos::Kernel::get_ms_count();
#endif
}
#else
#if MBED_CONF_EVENTS_USE_LOWPOWER_TIMER_TICKER
#define ALIAS_TIMER LowPowerTimer
#define ALIAS_TICKER LowPowerTicker
#define ALIAS_TIMEOUT LowPowerTimeout
#else
#define ALIAS_TIMER Timer
#define ALIAS_TICKER Ticker
#define ALIAS_TIMEOUT Timeout
#endif
static bool equeue_tick_inited = false;
static volatile unsigned equeue_minutes = 0;
static unsigned equeue_timer[
(sizeof(ALIAS_TIMER)+sizeof(unsigned)-1)/sizeof(unsigned)];
static unsigned equeue_ticker[
(sizeof(ALIAS_TICKER)+sizeof(unsigned)-1)/sizeof(unsigned)];
static void equeue_tick_update() {
equeue_minutes += reinterpret_cast<ALIAS_TIMER*>(equeue_timer)->read_ms();
reinterpret_cast<ALIAS_TIMER*>(equeue_timer)->reset();
}
static void equeue_tick_init() {
MBED_STATIC_ASSERT(sizeof(equeue_timer) >= sizeof(ALIAS_TIMER),
"The equeue_timer buffer must fit the class Timer");
MBED_STATIC_ASSERT(sizeof(equeue_ticker) >= sizeof(ALIAS_TICKER),
"The equeue_ticker buffer must fit the class Ticker");
ALIAS_TIMER *timer = new (equeue_timer) ALIAS_TIMER;
ALIAS_TICKER *ticker = new (equeue_ticker) ALIAS_TICKER;
equeue_minutes = 0;
timer->start();
ticker->attach_us(equeue_tick_update, 1000 << 16);
equeue_tick_inited = true;
}
unsigned equeue_tick() {
if (!equeue_tick_inited) {
equeue_tick_init();
}
unsigned minutes;
unsigned ms;
do {
minutes = equeue_minutes;
ms = reinterpret_cast<ALIAS_TIMER*>(equeue_timer)->read_ms();
} while (minutes != equeue_minutes);
return minutes + ms;
}
#endif
// Mutex operations
int equeue_mutex_create(equeue_mutex_t *m) { return 0; }
void equeue_mutex_destroy(equeue_mutex_t *m) { }
void equeue_mutex_lock(equeue_mutex_t *m) {
core_util_critical_section_enter();
}
void equeue_mutex_unlock(equeue_mutex_t *m) {
core_util_critical_section_exit();
}
// Semaphore operations
#ifdef MBED_CONF_RTOS_PRESENT
int equeue_sema_create(equeue_sema_t *s) {
osEventFlagsAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.cb_mem = &s->mem;
attr.cb_size = sizeof(s->mem);
s->id = osEventFlagsNew(&attr);
return !s->id ? -1 : 0;
}
void equeue_sema_destroy(equeue_sema_t *s) {
osEventFlagsDelete(s->id);
}
void equeue_sema_signal(equeue_sema_t *s) {
osEventFlagsSet(s->id, 1);
}
bool equeue_sema_wait(equeue_sema_t *s, int ms) {
if (ms < 0) {
ms = osWaitForever;
}
return (osEventFlagsWait(s->id, 1, osFlagsWaitAny, ms) == 1);
}
#else
// Semaphore operations
int equeue_sema_create(equeue_sema_t *s) {
*s = false;
return 0;
}
void equeue_sema_destroy(equeue_sema_t *s) {
}
void equeue_sema_signal(equeue_sema_t *s) {
*s = 1;
}
static void equeue_sema_timeout(equeue_sema_t *s) {
*s = -1;
}
bool equeue_sema_wait(equeue_sema_t *s, int ms) {
int signal = 0;
ALIAS_TIMEOUT timeout;
if (ms == 0) {
return false;
} else if (ms > 0) {
timeout.attach_us(callback(equeue_sema_timeout, s), (us_timestamp_t)ms*1000);
}
core_util_critical_section_enter();
while (!*s) {
sleep();
core_util_critical_section_exit();
core_util_critical_section_enter();
}
signal = *s;
*s = false;
core_util_critical_section_exit();
return (signal > 0);
}
#endif
#endif