blob: f048aa85f5f7f13d0ba9bc998827d20d91b44798 [file] [log] [blame]
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_task.h"
#include "esp_event.h"
#include "esp_flash.h"
#include "esp_log.h"
#include "esp_memory_utils.h"
#include "esp_psram.h"
#include "py/cstack.h"
#include "py/nlr.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/persistentcode.h"
#include "py/repl.h"
#include "py/gc.h"
#include "py/mphal.h"
#include "shared/readline/readline.h"
#include "shared/runtime/pyexec.h"
#include "shared/timeutils/timeutils.h"
#include "shared/tinyusb/mp_usbd.h"
#include "mbedtls/platform_time.h"
#include "uart.h"
#include "usb.h"
#include "usb_serial_jtag.h"
#include "modmachine.h"
#include "modnetwork.h"
#if MICROPY_BLUETOOTH_NIMBLE
#include "extmod/modbluetooth.h"
#endif
#if MICROPY_PY_ESPNOW
#include "modespnow.h"
#endif
// MicroPython runs as a task under FreeRTOS
#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
typedef struct _native_code_node_t {
struct _native_code_node_t *next;
uint32_t data[];
} native_code_node_t;
static native_code_node_t *native_code_head = NULL;
static void esp_native_code_free_all(void);
int vprintf_null(const char *format, va_list ap) {
// do nothing: this is used as a log target during raw repl mode
return 0;
}
time_t platform_mbedtls_time(time_t *timer) {
// mbedtls_time requires time in seconds from EPOCH 1970
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + TIMEUTILS_SECONDS_1970_TO_2000;
}
void mp_task(void *pvParameter) {
volatile uint32_t sp = (uint32_t)esp_cpu_get_sp();
#if MICROPY_PY_THREAD
mp_thread_init(pxTaskGetStackStart(NULL), MICROPY_TASK_STACK_SIZE / sizeof(uintptr_t));
#endif
#if MICROPY_HW_ESP_USB_SERIAL_JTAG
usb_serial_jtag_init();
#elif MICROPY_HW_ENABLE_USBDEV
usb_init();
#endif
#if MICROPY_HW_ENABLE_UART_REPL
uart_stdout_init();
#endif
machine_init();
// Configure time function, for mbedtls certificate time validation.
mbedtls_platform_set_time(platform_mbedtls_time);
esp_err_t err = esp_event_loop_create_default();
if (err != ESP_OK) {
ESP_LOGE("esp_init", "can't create event loop: 0x%x\n", err);
}
void *mp_task_heap = MP_PLAT_ALLOC_HEAP(MICROPY_GC_INITIAL_HEAP_SIZE);
if (mp_task_heap == NULL) {
printf("mp_task_heap allocation failed!\n");
esp_restart();
}
soft_reset:
// initialise the stack pointer for the main thread
mp_cstack_init_with_top((void *)sp, MICROPY_TASK_STACK_SIZE);
gc_init(mp_task_heap, mp_task_heap + MICROPY_GC_INITIAL_HEAP_SIZE);
mp_init();
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
readline_init0();
// initialise peripherals
machine_pins_init();
#if MICROPY_PY_MACHINE_I2S
machine_i2s_init0();
#endif
// run boot-up scripts
pyexec_frozen_module("_boot.py", false);
int ret = pyexec_file_if_exists("boot.py");
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL && ret != 0) {
int ret = pyexec_file_if_exists("main.py");
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
}
for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null);
if (pyexec_raw_repl() != 0) {
break;
}
esp_log_set_vprintf(vprintf_log);
} else {
if (pyexec_friendly_repl() != 0) {
break;
}
}
}
soft_reset_exit:
#if MICROPY_BLUETOOTH_NIMBLE
mp_bluetooth_deinit();
#endif
#if MICROPY_PY_ESPNOW
espnow_deinit(mp_const_none);
MP_STATE_PORT(espnow_singleton) = NULL;
#endif
machine_timer_deinit_all();
#if MICROPY_PY_THREAD
mp_thread_deinit();
#endif
#if MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE
mp_usbd_deinit();
#endif
gc_sweep_all();
// Free any native code pointers that point to iRAM.
esp_native_code_free_all();
mp_hal_stdout_tx_str("MPY: soft reboot\r\n");
// deinitialise peripherals
machine_pwm_deinit_all();
// TODO: machine_rmt_deinit_all();
machine_pins_deinit();
machine_deinit();
#if MICROPY_PY_SOCKET_EVENTS
socket_events_deinit();
#endif
mp_deinit();
fflush(stdout);
goto soft_reset;
}
void boardctrl_startup(void) {
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
nvs_flash_erase();
nvs_flash_init();
}
// Query the physical size of the SPI flash and store it in the size
// variable of the global, default SPI flash handle.
esp_flash_get_physical_size(NULL, &esp_flash_default_chip->size);
// If there is no filesystem partition (no "vfs" or "ffat"), add a "vfs" partition
// that extends from the end of the application partition up to the end of flash.
if (esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "vfs") == NULL
&& esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "ffat") == NULL) {
// No "vfs" or "ffat" partition, so try to create one.
// Find the end of the last partition that exists in the partition table.
size_t offset = 0;
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
while (iter != NULL) {
const esp_partition_t *part = esp_partition_get(iter);
offset = MAX(offset, part->address + part->size);
iter = esp_partition_next(iter);
}
// If we found the application partition and there is some space between the end of
// that and the end of flash, create a "vfs" partition taking up all of that space.
if (offset > 0 && esp_flash_default_chip->size > offset) {
size_t size = esp_flash_default_chip->size - offset;
esp_partition_register_external(esp_flash_default_chip, offset, size, "vfs", ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, NULL);
}
}
}
void MICROPY_ESP_IDF_ENTRY(void) {
// Hook for a board to run code at start up.
// This defaults to initialising NVS and detecting the flash size.
MICROPY_BOARD_STARTUP();
// Create and transfer control to the MicroPython task.
xTaskCreatePinnedToCore(mp_task, "mp_task", MICROPY_TASK_STACK_SIZE / sizeof(StackType_t), NULL, MP_TASK_PRIORITY, &mp_main_task_handle, MP_TASK_COREID);
}
MP_WEAK void nlr_jump_fail(void *val) {
printf("NLR jump failed, val=%p\n", val);
esp_restart();
}
static void esp_native_code_free_all(void) {
while (native_code_head != NULL) {
native_code_node_t *next = native_code_head->next;
heap_caps_free(native_code_head);
native_code_head = next;
}
}
void *esp_native_code_commit(void *buf, size_t len, void *reloc) {
len = (len + 3) & ~3;
size_t len_node = sizeof(native_code_node_t) + len;
native_code_node_t *node = heap_caps_malloc(len_node, MALLOC_CAP_EXEC);
#if CONFIG_IDF_TARGET_ESP32S2
// Workaround for ESP-IDF bug https://github.com/espressif/esp-idf/issues/14835
if (node != NULL && !esp_ptr_executable(node)) {
free(node);
node = NULL;
}
#endif // CONFIG_IDF_TARGET_ESP32S2
if (node == NULL) {
m_malloc_fail(len_node);
}
node->next = native_code_head;
native_code_head = node;
void *p = node->data;
if (reloc) {
mp_native_relocate(reloc, buf, (uintptr_t)p);
}
memcpy(p, buf, len);
return p;
}