summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rwxr-xr-xmain.c200
1 files changed, 126 insertions, 74 deletions
diff --git a/main.c b/main.c
index 974f045fa..c3787122d 100755
--- a/main.c
+++ b/main.c
@@ -43,6 +43,7 @@
#include "lib/mp-readline/readline.h"
#include "lib/utils/pyexec.h"
+#include "background.h"
#include "mpconfigboard.h"
#include "supervisor/cpu.h"
#include "supervisor/memory.h"
@@ -51,14 +52,30 @@
#include "supervisor/shared/autoreload.h"
#include "supervisor/shared/translate.h"
#include "supervisor/shared/rgb_led_status.h"
+#include "supervisor/shared/safe_mode.h"
#include "supervisor/shared/status_leds.h"
#include "supervisor/shared/stack.h"
#include "supervisor/serial.h"
-#ifdef MICROPY_PY_NETWORK
+#include "boards/board.h"
+
+#if CIRCUITPY_DISPLAYIO
+#include "shared-module/displayio/__init__.h"
+#endif
+
+#if CIRCUITPY_NETWORK
#include "shared-module/network/__init__.h"
#endif
+#if CIRCUITPY_BOARD
+#include "shared-module/board/__init__.h"
+#endif
+
+#if CIRCUITPY_BLEIO
+#include "shared-bindings/_bleio/__init__.h"
+#include "supervisor/shared/bluetooth.h"
+#endif
+
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) {
@@ -83,15 +100,23 @@ void start_mp(supervisor_allocation* heap) {
reset_status_led();
autoreload_stop();
+ background_tasks_reset();
+
// Stack limit should be less than real stack size, so we have a chance
// to recover from limit hit. (Limit is measured in bytes.)
mp_stack_ctrl_init();
- mp_stack_set_limit(stack_alloc->length - 1024);
+
+ if (stack_alloc != NULL) {
+ mp_stack_set_limit(stack_alloc->length - 1024);
+ }
+
#if MICROPY_MAX_STACK_USAGE
// _ezero (same as _ebss) is an int, so start 4 bytes above it.
- mp_stack_set_bottom(stack_alloc->ptr);
- mp_stack_fill_with_sentinel();
+ if (stack_alloc != NULL) {
+ mp_stack_set_bottom(stack_alloc->ptr);
+ mp_stack_fill_with_sentinel();
+ }
#endif
// Sync the file systems in case any used RAM from the GC to cache. As soon
@@ -115,15 +140,28 @@ void start_mp(supervisor_allocation* heap) {
mp_obj_list_init(mp_sys_argv, 0);
- #if MICROPY_PY_NETWORK
+ #if CIRCUITPY_NETWORK
network_module_init();
#endif
}
void stop_mp(void) {
- #if MICROPY_PY_NETWORK
+ #if CIRCUITPY_NETWORK
network_module_deinit();
#endif
+
+ #if MICROPY_VFS
+ mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table);
+
+ // Unmount all heap allocated vfs mounts.
+ while (gc_nbytes(vfs) > 0) {
+ vfs = vfs->next;
+ }
+ MP_STATE_VM(vfs_mount_table) = vfs;
+ MP_STATE_VM(vfs_cur) = vfs;
+ #endif
+
+ gc_deinit();
}
#define STRING_LIST(...) {__VA_ARGS__, ""}
@@ -140,12 +178,6 @@ const char* first_existing_file_in_list(const char ** filenames) {
return NULL;
}
-void write_compressed(const compressed_string_t* compressed) {
- char decompressed[compressed->length];
- decompress(compressed, decompressed);
- serial_write(decompressed);
-}
-
bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) {
const char* filename = first_existing_file_in_list(filenames);
if (filename == NULL) {
@@ -153,24 +185,42 @@ bool maybe_run_list(const char ** filenames, pyexec_result_t* exec_result) {
}
mp_hal_stdout_tx_str(filename);
const compressed_string_t* compressed = translate(" output:\n");
- char decompressed[compressed->length];
+ char decompressed[decompress_length(compressed)];
decompress(compressed, decompressed);
mp_hal_stdout_tx_str(decompressed);
pyexec_file(filename, exec_result);
return true;
}
+void cleanup_after_vm(supervisor_allocation* heap) {
+ // Turn off the display and flush the fileystem before the heap disappears.
+ #if CIRCUITPY_DISPLAYIO
+ reset_displays();
+ #endif
+ filesystem_flush();
+ stop_mp();
+ free_memory(heap);
+ supervisor_move_memory();
+
+ reset_port();
+ #if CIRCUITPY_BOARD
+ reset_board_busses();
+ #endif
+ reset_board();
+ reset_status_led();
+}
+
bool run_code_py(safe_mode_t safe_mode) {
bool serial_connected_at_start = serial_connected();
- #ifdef CIRCUITPY_AUTORELOAD_DELAY_MS
+ #if CIRCUITPY_AUTORELOAD_DELAY_MS > 0
if (serial_connected_at_start) {
serial_write("\n");
if (autoreload_is_enabled()) {
- write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
+ serial_write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
} else if (safe_mode != NO_SAFE_MODE) {
- write_compressed(translate("Running in safe mode! Auto-reload is off.\n"));
+ serial_write_compressed(translate("Running in safe mode! Auto-reload is off.\n"));
} else if (!autoreload_is_enabled()) {
- write_compressed(translate("Auto-reload is off.\n"));
+ serial_write_compressed(translate("Auto-reload is off.\n"));
}
}
#endif
@@ -184,12 +234,12 @@ bool run_code_py(safe_mode_t safe_mode) {
bool found_main = false;
if (safe_mode != NO_SAFE_MODE) {
- write_compressed(translate("Running in safe mode! Not running saved code.\n"));
+ serial_write_compressed(translate("Running in safe mode! Not running saved code.\n"));
} else {
new_status_color(MAIN_RUNNING);
- const char *supported_filenames[] = STRING_LIST("code.txt", "code.py", "main.py", "main.txt");
- const char *double_extension_filenames[] = STRING_LIST("code.txt.py", "code.py.txt", "code.txt.txt","code.py.py",
+ static const char *supported_filenames[] = STRING_LIST("code.txt", "code.py", "main.py", "main.txt");
+ static const char *double_extension_filenames[] = STRING_LIST("code.txt.py", "code.py.txt", "code.txt.txt","code.py.py",
"main.txt.py", "main.py.txt", "main.txt.txt","main.py.py");
stack_resize();
@@ -200,15 +250,10 @@ bool run_code_py(safe_mode_t safe_mode) {
if (!found_main){
found_main = maybe_run_list(double_extension_filenames, &result);
if (found_main) {
- write_compressed(translate("WARNING: Your code filename has two extensions\n"));
+ serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
}
}
- stop_mp();
- free_memory(heap);
-
- reset_port();
- reset_board();
- reset_status_led();
+ cleanup_after_vm(heap);
if (result.return_code & PYEXEC_FORCED_EXIT) {
return reload_requested;
@@ -216,14 +261,20 @@ bool run_code_py(safe_mode_t safe_mode) {
}
// Wait for connection or character.
+ if (!serial_connected_at_start) {
+ serial_write_compressed(translate("\nCode done running. Waiting for reload.\n"));
+ }
+
bool serial_connected_before_animation = false;
+ #if CIRCUITPY_DISPLAYIO
+ bool refreshed_epaper_display = false;
+ #endif
rgb_status_animation_t animation;
prep_rgb_status_animation(&result, found_main, safe_mode, &animation);
while (true) {
- #ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP
- #endif
+ RUN_BACKGROUND_TASKS;
if (reload_requested) {
+ reload_requested = false;
return true;
}
@@ -239,43 +290,27 @@ bool run_code_py(safe_mode_t safe_mode) {
if (!serial_connected_at_start) {
if (autoreload_is_enabled()) {
- write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
+ serial_write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n"));
} else {
- write_compressed(translate("Auto-reload is off.\n"));
- }
- }
- // Output a user safe mode string if its set.
- #ifdef BOARD_USER_SAFE_MODE
- if (safe_mode == USER_SAFE_MODE) {
- serial_write("\n");
- write_compressed(translate("You requested starting safe mode by "));
- serial_write(BOARD_USER_SAFE_MODE_ACTION);
- serial_write("\n");
- write_compressed(translate("To exit, please reset the board without "));
- serial_write(BOARD_USER_SAFE_MODE_ACTION);
- serial_write("\n");
- } else
- #endif
- if (safe_mode != NO_SAFE_MODE) {
- serial_write("\n");
- write_compressed(translate("You are running in safe mode which means something really bad happened.\n"));
- if (safe_mode == HARD_CRASH) {
- write_compressed(translate("Looks like our core CircuitPython code crashed hard. Whoops!\n"));
- write_compressed(translate("Please file an issue here with the contents of your CIRCUITPY drive:\n"));
- serial_write("https://github.com/adafruit/circuitpython/issues\n");
- } else if (safe_mode == BROWNOUT) {
- write_compressed(translate("The microcontroller's power dipped. Please make sure your power supply provides\n"));
- write_compressed(translate("enough power for the whole circuit and press reset (after ejecting CIRCUITPY).\n"));
+ serial_write_compressed(translate("Auto-reload is off.\n"));
}
}
+ print_safe_mode_message(safe_mode);
serial_write("\n");
- write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload."));
+ serial_write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload."));
}
if (serial_connected_before_animation && !serial_connected()) {
serial_connected_at_start = false;
}
serial_connected_before_animation = serial_connected();
+ // Refresh the ePaper display if we have one. That way it'll show an error message.
+ #if CIRCUITPY_DISPLAYIO
+ if (!refreshed_epaper_display) {
+ refreshed_epaper_display = maybe_refresh_epaperdisplay();
+ }
+ #endif
+
tick_rgb_status_animation(&animation);
}
}
@@ -324,12 +359,12 @@ void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
mp_hal_delay_ms(1500);
// USB isn't up, so we can write the file.
- filesystem_writable_by_python(true);
+ filesystem_set_internal_writable_by_usb(false);
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
// Switch the filesystem back to non-writable by Python now instead of later,
// since boot.py might change it back to writable.
- filesystem_writable_by_python(false);
+ filesystem_set_internal_writable_by_usb(true);
// Write version info to boot_out.txt.
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
@@ -354,12 +389,7 @@ void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
boot_output_file = NULL;
#endif
- // Reset to remove any state that boot.py setup. It should only be used to
- // change internal state that's not in the heap.
- reset_port();
- reset_board();
- stop_mp();
- free_memory(heap);
+ cleanup_after_vm(heap);
}
}
@@ -376,10 +406,7 @@ int run_repl(void) {
} else {
exit_code = pyexec_friendly_repl();
}
- reset_port();
- reset_board();
- stop_mp();
- free_memory(heap);
+ cleanup_after_vm(heap);
autoreload_resume();
return exit_code;
}
@@ -394,6 +421,11 @@ int __attribute__((used)) main(void) {
init_status_leds();
rgb_led_status_init();
+ // Wait briefly to give a reset window where we'll enter safe mode after the reset.
+ if (safe_mode == NO_SAFE_MODE) {
+ safe_mode = wait_for_safe_mode_reset();
+ }
+
stack_init();
// Create a new filesystem only if we're not in a safe mode.
@@ -401,6 +433,12 @@ int __attribute__((used)) main(void) {
// no SPI flash filesystem, and we might erase the existing one.
filesystem_init(safe_mode == NO_SAFE_MODE, false);
+ // displays init after filesystem, since they could share the flash SPI
+ board_init();
+
+ // Start the debug serial
+ serial_early_init();
+
// Reset everything and prep MicroPython to run boot.py.
reset_port();
reset_board();
@@ -410,13 +448,18 @@ int __attribute__((used)) main(void) {
// By default our internal flash is readonly to local python code and
// writable over USB. Set it here so that boot.py can change it.
- filesystem_writable_by_python(false);
+ filesystem_set_internal_concurrent_write_protection(true);
+ filesystem_set_internal_writable_by_usb(true);
run_boot_py(safe_mode);
// Start serial and HID after giving boot.py a chance to tweak behavior.
serial_init();
+ #if CIRCUITPY_BLEIO
+ supervisor_start_bluetooth();
+ #endif
+
// Boot script is finished, so now go into REPL/main mode.
int exit_code = PYEXEC_FORCED_EXIT;
bool skip_repl = true;
@@ -427,7 +470,7 @@ int __attribute__((used)) main(void) {
}
if (exit_code == PYEXEC_FORCED_EXIT) {
if (!first_run) {
- write_compressed(translate("soft reboot\n"));
+ serial_write_compressed(translate("soft reboot\n"));
}
first_run = false;
skip_repl = run_code_py(safe_mode);
@@ -448,19 +491,28 @@ void gc_collect(void) {
// This collects root pointers from the VFS mount table. Some of them may
// have lost their references in the VM even though they are mounted.
gc_collect_root((void**)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t));
+
+ #if CIRCUITPY_DISPLAYIO
+ displayio_gc_collect();
+ #endif
+
+ #if CIRCUITPY_BLEIO
+ common_hal_bleio_gc_collect();
+ #endif
+
// This naively collects all object references from an approximate stack
// range.
- gc_collect_root((void**)sp, ((uint32_t)&_estack - sp) / sizeof(uint32_t));
+ gc_collect_root((void**)sp, ((uint32_t)port_stack_get_top() - sp) / sizeof(uint32_t));
gc_collect_end();
}
void NORETURN nlr_jump_fail(void *val) {
- HardFault_Handler();
+ reset_into_safe_mode(MICROPY_NLR_JUMP_FAIL);
while (true) {}
}
void NORETURN __fatal_error(const char *msg) {
- HardFault_Handler();
+ reset_into_safe_mode(MICROPY_FATAL_ERROR);
while (true) {}
}