| 
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