|
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