|
6 | 6 | * network topology allowing messages to be routed to nodes. |
7 | 7 | * |
8 | 8 | * Created by Henrik Ekblad <[email protected]> |
9 | | - * Copyright (C) 2013-2020 Sensnology AB |
| 9 | + * Copyright (C) 2013-2022 Sensnology AB |
10 | 10 | * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors |
11 | 11 | * |
12 | 12 | * Documentation: http://www.mysensors.org |
|
17 | 17 | * version 2 as published by the Free Software Foundation. |
18 | 18 | */ |
19 | 19 |
|
20 | | -//This may be used to change user task stack size: |
21 | | -//#define CONT_STACKSIZE 4096 |
22 | | -#include <Arduino.h> |
23 | | -#include "Schedule.h" |
24 | | -extern "C" { |
25 | | -#include "ets_sys.h" |
26 | | -#include "os_type.h" |
27 | | -#include "osapi.h" |
28 | | -#include "mem.h" |
29 | | -#include "user_interface.h" |
30 | | -#include "cont.h" |
31 | | -} |
32 | | -#include <core_version.h> |
33 | | -#include "gdb_hooks.h" |
34 | | - |
35 | | -#define LOOP_TASK_PRIORITY 1 |
36 | | -#define LOOP_QUEUE_SIZE 1 |
37 | | -#define OPTIMISTIC_YIELD_TIME_US 16000 |
38 | | - |
39 | | -extern "C" void call_user_start(); |
40 | | -extern void loop(); |
41 | | -extern void setup(); |
42 | | -extern void(*__init_array_start)(void); |
43 | | -extern void(*__init_array_end)(void); |
44 | | - |
45 | | -/* Not static, used in Esp.cpp */ |
46 | | -struct rst_info resetInfo; |
47 | | - |
48 | | -/* Not static, used in core_esp8266_postmortem.c and other places. |
49 | | - * Placed into noinit section because we assign value to this variable |
50 | | - * before .bss is zero-filled, and need to preserve the value. |
51 | | - */ |
52 | | -cont_t* g_pcont __attribute__((section(".noinit"))); |
53 | | - |
54 | | -/* Event queue used by the main (arduino) task */ |
55 | | -static os_event_t s_loop_queue[LOOP_QUEUE_SIZE]; |
56 | | - |
57 | | -/* Used to implement optimistic_yield */ |
58 | | -static uint32_t s_micros_at_task_start; |
59 | | - |
60 | | -/* For ets_intr_lock_nest / ets_intr_unlock_nest |
61 | | - * Max nesting seen by SDK so far is 2. |
62 | | - */ |
63 | | -#define ETS_INTR_LOCK_NEST_MAX 7 |
64 | | -static uint16_t ets_intr_lock_stack[ETS_INTR_LOCK_NEST_MAX]; |
65 | | -static byte ets_intr_lock_stack_ptr = 0; |
66 | | - |
67 | | - |
68 | | -extern "C" { |
69 | | - extern const uint32_t __attribute__((section(".ver_number"))) core_version = |
70 | | - ARDUINO_ESP8266_GIT_VER; |
71 | | - const char* core_release = |
72 | | -#ifdef ARDUINO_ESP8266_RELEASE |
73 | | - ARDUINO_ESP8266_RELEASE; |
74 | | -#else |
75 | | - NULL; |
76 | | -#endif |
77 | | -} // extern "C" |
78 | | - |
79 | | -void initVariant() __attribute__((weak)); |
80 | | -void initVariant() |
81 | | -{ |
82 | | -} |
83 | | - |
84 | | -void preloop_update_frequency() __attribute__((weak)); |
85 | | -void preloop_update_frequency() |
86 | | -{ |
87 | | -#if defined(F_CPU) && (F_CPU == 160000000L) |
88 | | - REG_SET_BIT(0x3ff00014, BIT(0)); |
89 | | - ets_update_cpu_frequency(160); |
90 | | -#endif |
91 | | -} |
92 | | - |
93 | | -extern "C" bool can_yield() |
94 | | -{ |
95 | | - return cont_can_yield(g_pcont); |
96 | | -} |
97 | | - |
98 | | -static inline void esp_yield_within_cont() __attribute__((always_inline)); |
99 | | -static void esp_yield_within_cont() |
100 | | -{ |
101 | | - cont_yield(g_pcont); |
102 | | - run_scheduled_recurrent_functions(); |
103 | | -} |
104 | | - |
105 | | -extern "C" void esp_yield() |
106 | | -{ |
107 | | - if (can_yield()) { |
108 | | - esp_yield_within_cont(); |
109 | | - } |
110 | | -} |
111 | | - |
112 | | -extern "C" void esp_schedule() |
113 | | -{ |
114 | | - // always on CONT stack here |
115 | | - ets_post(LOOP_TASK_PRIORITY, 0, 0); |
116 | | -} |
117 | | - |
118 | | -extern "C" void __yield() |
119 | | -{ |
120 | | - if (can_yield()) { |
121 | | - esp_schedule(); |
122 | | - esp_yield_within_cont(); |
123 | | - } else { |
124 | | - panic(); |
125 | | - } |
126 | | -} |
127 | | - |
128 | | -extern "C" void yield(void) __attribute__((weak, alias("__yield"))); |
129 | | - |
130 | | -extern "C" void optimistic_yield(uint32_t interval_us) |
131 | | -{ |
132 | | - if (can_yield() && |
133 | | - (system_get_time() - s_micros_at_task_start) > interval_us) { |
134 | | - yield(); |
135 | | - } |
136 | | -} |
137 | | - |
138 | | - |
139 | | -// Replace ets_intr_(un)lock with nestable versions |
140 | | -extern "C" void IRAM_ATTR ets_intr_lock() |
141 | | -{ |
142 | | - if (ets_intr_lock_stack_ptr < ETS_INTR_LOCK_NEST_MAX) { |
143 | | - ets_intr_lock_stack[ets_intr_lock_stack_ptr++] = xt_rsil(3); |
144 | | - } else { |
145 | | - xt_rsil(3); |
146 | | - } |
147 | | -} |
148 | | - |
149 | | -extern "C" void IRAM_ATTR ets_intr_unlock() |
150 | | -{ |
151 | | - if (ets_intr_lock_stack_ptr > 0) { |
152 | | - xt_wsr_ps(ets_intr_lock_stack[--ets_intr_lock_stack_ptr]); |
153 | | - } else { |
154 | | - xt_rsil(0); |
155 | | - } |
156 | | -} |
157 | | - |
158 | | - |
159 | | -// Save / Restore the PS state across the rom ets_post call as the rom code |
160 | | -// does not implement this correctly. |
161 | | -extern "C" bool ets_post_rom(uint8 prio, ETSSignal sig, ETSParam par); |
162 | | - |
163 | | -extern "C" bool IRAM_ATTR ets_post(uint8 prio, ETSSignal sig, ETSParam par) |
164 | | -{ |
165 | | - uint32_t saved; |
166 | | - asm volatile ("rsr %0,ps":"=a" (saved)); |
167 | | - bool rc = ets_post_rom(prio, sig, par); |
168 | | - xt_wsr_ps(saved); |
169 | | - return rc; |
170 | | -} |
171 | | - |
172 | | -extern "C" void __loop_end(void) |
| 20 | +inline void _my_sensors_loop() |
173 | 21 | { |
174 | | - run_scheduled_functions(); |
175 | | - run_scheduled_recurrent_functions(); |
176 | | -} |
177 | | - |
178 | | -extern "C" void loop_end(void) __attribute__((weak, alias("__loop_end"))); |
179 | | - |
180 | | -static void loop_wrapper() |
181 | | -{ |
182 | | - static bool setup_done = false; |
183 | | - preloop_update_frequency(); |
184 | | - if (!setup_done) { |
185 | | - _begin(); // Startup MySensors library |
186 | | - setup_done = true; |
187 | | - } |
188 | | - _process(); // Process incoming data |
| 22 | + // Process incoming data |
| 23 | + _process(); |
| 24 | + // Call of loop() in the Arduino sketch |
189 | 25 | loop(); |
190 | | - run_scheduled_functions(); |
191 | | - esp_schedule(); |
192 | 26 | } |
193 | 27 |
|
194 | | -static void loop_task(os_event_t *events) |
195 | | -{ |
196 | | - (void)events; |
197 | | - s_micros_at_task_start = system_get_time(); |
198 | | - cont_run(g_pcont, &loop_wrapper); |
199 | | - if (cont_check(g_pcont) != 0) { |
200 | | - panic(); |
201 | | - } |
202 | | -} |
203 | | -extern "C" { |
204 | | - |
205 | | - struct object { |
206 | | - long placeholder[10]; |
207 | | - }; |
208 | | - void __register_frame_info(const void *begin, struct object *ob); |
209 | | - extern char __eh_frame[]; |
210 | | -} |
211 | | - |
212 | | -static void do_global_ctors(void) |
213 | | -{ |
214 | | - static struct object ob; |
215 | | - __register_frame_info(__eh_frame, &ob); |
216 | | - |
217 | | - void(**p)(void) = &__init_array_end; |
218 | | - while (p != &__init_array_start) { |
219 | | - (*--p)(); |
220 | | - } |
221 | | -} |
222 | | - |
223 | | -extern "C" { |
224 | | - extern void __unhandled_exception(const char *str); |
225 | | - |
226 | | - static void __unhandled_exception_cpp() |
227 | | - { |
228 | | -#ifndef __EXCEPTIONS |
229 | | - abort(); |
230 | | -#else |
231 | | - static bool terminating; |
232 | | - if (terminating) { |
233 | | - abort(); |
234 | | - } |
235 | | - terminating = true; |
236 | | - /* Use a trick from vterminate.cc to get any std::exception what() */ |
237 | | - try { |
238 | | - __throw_exception_again; |
239 | | - } catch (const std::exception& e) { |
240 | | - __unhandled_exception(e.what()); |
241 | | - } catch (...) { |
242 | | - __unhandled_exception(""); |
243 | | - } |
244 | | -#endif |
245 | | - } |
246 | | - |
247 | | -} |
248 | | - |
249 | | -void init_done() |
250 | | -{ |
251 | | - system_set_os_print(1); |
252 | | - gdb_init(); |
253 | | - std::set_terminate(__unhandled_exception_cpp); |
254 | | - do_global_ctors(); |
255 | | - esp_schedule(); |
256 | | -} |
257 | | - |
258 | | -/* This is the entry point of the application. |
259 | | - * It gets called on the default stack, which grows down from the top |
260 | | - * of DRAM area. |
261 | | - * .bss has not been zeroed out yet, but .data and .rodata are in place. |
262 | | - * Cache is not enabled, so only ROM and IRAM functions can be called. |
263 | | - * Peripherals (except for SPI0 and UART0) are not initialized. |
264 | | - * This function does not return. |
265 | | - */ |
266 | 28 | /* |
267 | | - A bit of explanation for this entry point: |
268 | | -
|
269 | | - SYS is the SDK task/context used by the upperlying system to run its |
270 | | - administrative tasks (at least WLAN and lwip's receive callbacks and |
271 | | - Ticker). NONOS-SDK is designed to run user's non-threaded code in |
272 | | - another specific task/context with its own stack in BSS. |
273 | | -
|
274 | | - Some clever fellows found that the SYS stack was a large and quite unused |
275 | | - piece of ram that we could use for the user's stack instead of using user's |
276 | | - main memory, thus saving around 4KB on ram/heap. |
277 | | -
|
278 | | - A problem arose later, which is that this stack can heavily be used by |
279 | | - the SDK for some features. One of these features is WPS. We still don't |
280 | | - know if other features are using this, or if this memory is going to be |
281 | | - used in future SDK releases. |
282 | | -
|
283 | | - WPS beeing flawed by its poor security, or not beeing used by lots of |
284 | | - users, it has been decided that we are still going to use that memory for |
285 | | - user's stack and disable the use of WPS. |
286 | | -
|
287 | | - app_entry() jumps to app_entry_custom() defined as "weakref" calling |
288 | | - itself a weak customizable function, allowing to use another one when |
289 | | - this is required (see core_esp8266_app_entry_noextra4k.cpp, used by WPS). |
290 | | -
|
291 | | - (note: setting app_entry() itself as "weak" is not sufficient and always |
292 | | - ends up with the other "noextra4k" one linked, maybe because it has a |
293 | | - default ENTRY(app_entry) value in linker scripts). |
294 | | -
|
295 | | - References: |
296 | | - https://github.com/esp8266/Arduino/pull/4553 |
297 | | - https://github.com/esp8266/Arduino/pull/4622 |
298 | | - https://github.com/esp8266/Arduino/issues/4779 |
299 | | - https://github.com/esp8266/Arduino/pull/4889 |
300 | | -
|
301 | | -*/ |
302 | | - |
303 | | -extern "C" void app_entry_redefinable(void) __attribute__((weak)); |
304 | | -extern "C" void app_entry_redefinable(void) |
305 | | -{ |
306 | | - /* Allocate continuation context on this SYS stack, |
307 | | - and save pointer to it. */ |
308 | | - cont_t s_cont __attribute__((aligned(16))); |
309 | | - g_pcont = &s_cont; |
310 | | - |
311 | | - /* Call the entry point of the SDK code. */ |
312 | | - call_user_start(); |
313 | | -} |
314 | | - |
315 | | -static void app_entry_custom(void) __attribute__((weakref("app_entry_redefinable"))); |
316 | | - |
317 | | -extern "C" void app_entry(void) |
318 | | -{ |
319 | | - return app_entry_custom(); |
320 | | -} |
321 | | - |
322 | | -extern "C" void preinit(void) __attribute__((weak)); |
323 | | -extern "C" void preinit(void) |
324 | | -{ |
325 | | - /* do nothing by default */ |
326 | | -} |
327 | | - |
328 | | -extern "C" void user_init(void) |
329 | | -{ |
330 | | - struct rst_info *rtc_info_ptr = system_get_rst_info(); |
331 | | - memcpy((void *)&resetInfo, (void *)rtc_info_ptr, sizeof(resetInfo)); |
332 | | - |
333 | | - uart_div_modify(0, UART_CLK_FREQ / (115200)); |
334 | | - |
335 | | - init(); // in core_esp8266_wiring.c, inits hw regs and sdk timer |
336 | | - |
337 | | - initVariant(); |
338 | | - |
339 | | - cont_init(g_pcont); |
| 29 | + * Use preprocessor defines for injection of the MySensors calls |
| 30 | + * to _begin() and _process() in file core_esp8266_main.cpp. |
| 31 | + * These functions implement the "magic" how the MySensors stack |
| 32 | + * is setup and executed in background without need |
| 33 | + * for explicit calls from the Arduino sketch. |
| 34 | + */ |
340 | 35 |
|
341 | | - preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable. |
| 36 | +// Start up MySensors library including call of setup() in the Arduino sketch |
| 37 | +#define setup _begin |
| 38 | +// Helper function to _process() and call of loop() in the Arduino sketch |
| 39 | +#define loop _my_sensors_loop |
342 | 40 |
|
343 | | - ets_task(loop_task, |
344 | | - LOOP_TASK_PRIORITY, s_loop_queue, |
345 | | - LOOP_QUEUE_SIZE); |
| 41 | +#include <core_esp8266_main.cpp> |
346 | 42 |
|
347 | | - system_init_done_cb(&init_done); |
348 | | -} |
| 43 | +// Tidy up injection defines |
| 44 | +#undef loop |
| 45 | +#undef setup |
0 commit comments