2424#include <hardware/sync.h>
2525#include <hardware/flash.h>
2626#include <pico/time.h>
27+ #include <pico/runtime_init.h>
2728#include <hardware/gpio.h>
2829#include <hardware/uart.h>
2930#include <hardware/watchdog.h>
@@ -54,26 +55,33 @@ void dumphex(uint32_t x) {
5455}
5556
5657extern OTACmdPage _ota_cmd ;
57- void do_ota () {
58+ static uint32_t blockToErase ;
59+
60+
61+ bool has_ota () {
5862 if (* __FS_START__ == * __FS_END__ ) {
59- return ;
63+ return false ;
6064 }
6165 if (!lfsMount (* __FS_START__ , 4096 , * __FS_END__ - * __FS_START__ )) {
62- uart_puts (uart0 , "mount failed\n" );
63- return ;
66+ return false;
6467 }
6568
6669 // We are very naughty and record the last block read, since it should be the actual data block of the
6770 // OTA structure. We'll erase it behind the scenes to avoid bringing in all of LittleFS write infra.
68- uint32_t blockToErase ;
6971 if (!lfsReadOTA (& _ota_cmd , & blockToErase )) {
70- return ;
72+ return false ;
7173 }
7274
7375 if (memcmp (_ota_cmd .sign , "Pico OTA" , 8 )) {
74- return ; // No signature
76+ return false ; // No signature
7577 }
7678
79+ return true;
80+ }
81+
82+
83+
84+ void do_ota () {
7785 uint32_t crc = 0xffffffff ;
7886 const uint8_t * data = (const uint8_t * )& _ota_cmd ;
7987 for (uint32_t i = 0 ; i < offsetof(OTACmdPage , crc32 ); i ++ ) {
@@ -159,31 +167,18 @@ void do_ota() {
159167
160168 // Do a hard reset just in case the start up sequence is not the same
161169 watchdog_reboot (0 , 0 , 100 );
170+ while (true) {
171+ tight_loop_contents ();
172+ }
162173}
163174
164-
165175#pragma GCC push_options
166176#pragma GCC optimize("O0")
167- int main (int a , char * * b ) {
168- (void ) a ;
169- (void ) b ;
170-
171- #ifdef DEBUG
172- uart_init (uart0 , 115200 );
173- gpio_set_function (0 , GPIO_FUNC_UART );
174- gpio_set_function (1 , GPIO_FUNC_UART );
175- uart_set_hw_flow (uart0 , false, false);
176- uart_set_format (uart0 , 8 , 1 , UART_PARITY_NONE );
177- #endif
178-
179- do_ota ();
180-
177+ __attribute__((noreturn ))
178+ void boot_normal () {
181179#ifdef __riscv
182180 extern void __mainapp ();
183181 __mainapp ();
184-
185- // Should never get here!
186- return 0 ;
187182#else
188183 // Reset the interrupt/etc. vectors to the real app. Will be copied to RAM in app's runtime_init
189184 scb_hw -> vtor = (uint32_t )0x10003000 ;
@@ -194,10 +189,43 @@ int main(int a, char **b) {
194189 register void (* fcn )(void ) = (void (* )(void )) * (uint32_t * )0x10003004 ;
195190 sp = (uint32_t * )_sp ;
196191 fcn ();
192+ (void )sp ;
193+ #endif
194+
195+ __builtin_unreachable ();
196+ }
197+
198+ void check_ota () {
199+ // this runs before the full runtime and hardware is initialized to prevent
200+ // initialization happening again in the application. Care must be taken that
201+ // no uninitialized peripheral or part of the runtime is used.
202+ // If necessary, init routines can be moved before check_ota() by adjusting
203+ // their PICO_RUNTIME_INIT_* in CMakeLists.txt.
204+ // refer to this source for existing init routines:
205+ // https://github.com/raspberrypi/pico-sdk/blob/2.1.0/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h
206+ if (!has_ota ()) {
207+ boot_normal ();
208+ }
209+ }
210+ PICO_RUNTIME_INIT_FUNC_RUNTIME (check_ota , "00099" );
211+
212+ int main (int a , char * * b ) {
213+ (void ) a ;
214+ (void ) b ;
197215
198- // Should never get here!
199- return * sp ;
216+ #ifdef DEBUG
217+ uart_init (uart0 , 115200 );
218+ gpio_set_function (0 , GPIO_FUNC_UART );
219+ gpio_set_function (1 , GPIO_FUNC_UART );
220+ uart_set_hw_flow (uart0 , false, false);
221+ uart_set_format (uart0 , 8 , 1 , UART_PARITY_NONE );
200222#endif
223+
224+ // if we arrive here, it looks like we have an OTA command in the LittleFS
225+ do_ota ();
226+
227+ // fallback to normal boot if do_ota() failed, e.g. due to CRC failure or corruption
228+ boot_normal ();
201229}
202230#pragma GCC pop_options
203231
0 commit comments