From 5fbad195df25bb1bebb079a1bcde0b09d080ff1b Mon Sep 17 00:00:00 2001 From: Henri Manson Date: Sun, 12 Apr 2026 01:39:39 +0200 Subject: [PATCH 1/8] IDF v5.5.1 and Tanmatsu support (#55) --- components/buses/CMakeLists.txt | 12 +- components/buses/buses.c | 43 +-- components/buses/include/buses.h | 1 + components/consts/CMakeLists.txt | 15 + components/consts/Kconfig | 76 +++++ components/consts/modconsts.c | 70 +++++ components/driver_badge_bsp/CMakeLists.txt | 19 ++ components/driver_badge_bsp/Kconfig | 6 + .../driver_badge_bsp/driver_badge_bsp.c | 53 ++++ .../include/driver_badge_bsp.h | 21 ++ .../include/framebuffer_display.h | 17 ++ .../driver_display_ili9341/CMakeLists.txt | 2 +- components/driver_framebuffer/CMakeLists.txt | 31 ++- .../driver_framebuffer/driver_framebuffer.cpp | 1 + components/driver_framebuffer/moddisplay.c | 16 +- .../driver_framebuffer/png/flash_reader.h | 2 + components/driver_mch22/CMakeLists.txt | 28 +- .../esp32-component-mch2022-rp2040 | 2 +- components/driver_mch22/modmch22.c | 40 +-- components/driver_rtcmem/CMakeLists.txt | 26 +- components/driver_rtcmem/driver_rtcmem.c | 115 +++++--- .../driver_rtcmem/include/driver_rtcmem.h | 24 +- components/driver_rtcmem/modrtcmem.c | 142 ++++++---- components/driver_sndmixer/CMakeLists.txt | 25 +- components/driver_sndmixer/driver_i2s.c | 213 +++++++------- components/driver_sndmixer/driver_i2s.h | 12 +- components/driver_sndmixer/ibxm/ibxm.h | 2 +- components/driver_sndmixer/modsndmixer.c | 7 +- components/driver_sndmixer/snd_source_mod.c | 6 +- components/driver_sndmixer/snd_source_mp3.c | 44 +-- components/driver_sndmixer/snd_source_opus.c | 8 +- components/driver_sndmixer/snd_source_synth.c | 6 +- components/driver_sndmixer/snd_source_wav.c | 62 +++-- components/driver_sndmixer/sndmixer.c | 115 +++++--- components/driver_sndmixer/sndmixer.h | 16 +- .../libopus/silk/fixed/encode_frame_FIX.c | 2 + components/micropython/CMakeLists.txt | 263 +----------------- components/pynvs/CMakeLists.txt | 26 +- components/pynvs/modnvs.c | 5 +- python_modules/common/audio.py | 22 +- python_modules/common/system.py | 174 ++++++------ python_modules/mch2022/hardware/__init__.py | 6 +- 42 files changed, 1043 insertions(+), 733 deletions(-) create mode 100644 components/consts/CMakeLists.txt create mode 100644 components/consts/Kconfig create mode 100644 components/consts/modconsts.c create mode 100644 components/driver_badge_bsp/CMakeLists.txt create mode 100644 components/driver_badge_bsp/Kconfig create mode 100644 components/driver_badge_bsp/driver_badge_bsp.c create mode 100644 components/driver_badge_bsp/include/driver_badge_bsp.h create mode 100644 components/driver_badge_bsp/include/framebuffer_display.h diff --git a/components/buses/CMakeLists.txt b/components/buses/CMakeLists.txt index 24e81f6..a202ac2 100644 --- a/components/buses/CMakeLists.txt +++ b/components/buses/CMakeLists.txt @@ -1,4 +1,12 @@ +#get_cmake_property(_vars VARIABLES) +#foreach(v ${_vars}) +# message(STATUS "${v} = [${${v}}]") +#endforeach() + idf_component_register( SRCS "buses.c" - INCLUDE_DIRS include -) + INCLUDE_DIRS include ${PROJECT_DIR} + REQUIRES + micropython + driver + freertos) diff --git a/components/buses/buses.c b/components/buses/buses.c index ff5f765..46b9287 100644 --- a/components/buses/buses.c +++ b/components/buses/buses.c @@ -22,8 +22,11 @@ #define ACK_VAL 0x0 // I2C ack value #define NACK_VAL 0x1 // I2C nack value -static xSemaphoreHandle i2c0_mux = NULL; -static xSemaphoreHandle i2c1_mux = NULL; + +static SemaphoreHandle_t i2c0_mux = NULL; +static SemaphoreHandle_t i2c1_mux = NULL; + +static const char* TAG = "buses"; esp_err_t start_buses() { // This function initializes the VSPI, HSPI and I2C buses of the ESP32 @@ -129,9 +132,9 @@ esp_err_t driver_i2c_read_bytes(int bus, uint8_t addr, uint8_t *value, size_t va res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -158,9 +161,9 @@ esp_err_t driver_i2c_read_reg(int bus, uint8_t addr, uint8_t reg, uint8_t *value res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -179,9 +182,9 @@ esp_err_t driver_i2c_read_event(int bus, uint8_t addr, uint8_t *buf) { res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -198,9 +201,9 @@ esp_err_t driver_i2c_write_byte(int bus, uint8_t addr, uint8_t value) { res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -219,9 +222,9 @@ esp_err_t driver_i2c_write_reg(int bus, uint8_t addr, uint8_t reg, uint8_t value res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -242,9 +245,9 @@ esp_err_t driver_i2c_write_reg_n(int bus, uint8_t addr, uint8_t reg, uint8_t *va res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -263,9 +266,9 @@ esp_err_t driver_i2c_write_buffer(int bus, uint8_t addr, const uint8_t* buffer, res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -286,9 +289,9 @@ esp_err_t driver_i2c_write_buffer_reg(int bus, uint8_t addr, uint8_t reg, const res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; @@ -313,9 +316,9 @@ esp_err_t driver_i2c_write_reg32(int bus, uint8_t addr, uint8_t reg, uint32_t va res = i2c_master_stop(cmd); if (res != ESP_OK) { i2c_cmd_link_delete(cmd); return res; } - xSemaphoreHandle mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; + SemaphoreHandle_t mux = (bus == I2C_NUM_1) ? i2c1_mux : i2c0_mux; if (xSemaphoreTake(mux, portMAX_DELAY) != pdTRUE) return ESP_ERR_TIMEOUT; // Wait for I2C bus to become available - res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS); + res = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); xSemaphoreGive(mux); return res; diff --git a/components/buses/include/buses.h b/components/buses/include/buses.h index d018c31..ed3180b 100644 --- a/components/buses/include/buses.h +++ b/components/buses/include/buses.h @@ -4,6 +4,7 @@ #include extern esp_err_t start_buses(); + extern esp_err_t driver_i2c_read_bytes(int bus, uint8_t addr, uint8_t *value, size_t value_len); extern esp_err_t driver_i2c_read_reg(int bus, uint8_t addr, uint8_t reg, uint8_t *value, size_t value_len); extern esp_err_t driver_i2c_read_event(int bus, uint8_t addr, uint8_t *buf); diff --git a/components/consts/CMakeLists.txt b/components/consts/CMakeLists.txt new file mode 100644 index 0000000..b5e237e --- /dev/null +++ b/components/consts/CMakeLists.txt @@ -0,0 +1,15 @@ +# Compute the MicroPython root relative to this component +set(MP_ROOT ${PROJECT_DIR}/../..) + +idf_component_register( + SRCS "modconsts.c" + PRIV_INCLUDE_DIRS + ${MP_ROOT} # micropython/ + ${PROJECT_DIR} # micropython/ports/esp32 + ${MICROPY_BOARD_DIR} # board headers (mpconfigboard.h) + ${CMAKE_CURRENT_LIST_DIR}/.. + ${BUILD_DIR} + REQUIRES + micropython + driver + freertos) diff --git a/components/consts/Kconfig b/components/consts/Kconfig new file mode 100644 index 0000000..0803c28 --- /dev/null +++ b/components/consts/Kconfig @@ -0,0 +1,76 @@ +menu "Firmware & device configuration" + config INFO_FIRMWARE_NAME + string "Code-name of the firmware" + default "Unknown" + + config INFO_FIRMWARE_BUILD + int "Build number of the firmware" + default 0 + + config INFO_HARDWARE_NAME + string "Name of the device" + default "Generic device" + help + A semantic name for your badge + + config MICROPY_FROZEN_MANIFEST + string "Manifest to load modules from stored in the manifests folder" + default "manifest.py" + + config INFO_HARDWARE_WOEZEL_NAME + string "Name of the badge on the app hatchery" + default "generic" + + config OTA_WEB_SERVER + string "Hostname of server for OTA updates" + default "badge.team" + + config OTA_WEB_USE_HTTPS + bool "Use HTTPS for OTA updates" + default y + + config OTA_WEB_PORT + int "Port of server for OTA updates" + default 443 + + config OTA_WEB_PATH + string "Path on the server for OTA updates" + default "/firmware/unknown.bin" + + config OTA_WEB_VERSION_PATH + string "Path on the server for OTA update version" + default "/firmware/version/unknown.txt" + + config WOEZEL_WEB_SERVER + string "Hostname of server for app hatchery that contains user apps" + default "badge.team" + + config WIFI_SSID + string "Default WiFi ssid" + default "badge" + + config WIFI_PASSWORD + string "Default WiFi password, leave empty for unsecure network" + default "" + + choice + prompt "Default display orientation" + default DEFAULT_DISPLAY_ORIENTATION_LANDSCAPE + config DEFAULT_DISPLAY_ORIENTATION_LANDSCAPE + bool "Landscape (0 degrees)" + config DEFAULT_DISPLAY_ORIENTATION_PORTRAIT + bool "Portrait (90 degrees)" + config DEFAULT_DISPLAY_ORIENTATION_REVERSE_LANDSCAPE + bool "Reverse landscape (180 degrees)" + config DEFAULT_DISPLAY_ORIENTATION_REVERSE_PORTRAIT + bool "Reverse portrait (270 degrees)" + endchoice + + config FW_ENABLE_SHA2017_DISOBEY2019_PARTITION_TABLE_UPGRADE + bool "Enable partition table upgrade function for SHA2017 and Disobey 2019 badges" + default n + + config FW_DISABLE_OTA_AND_FIRSTBOOT + bool "Disable OTA update function and first boot ZIP unpacking" + default n +endmenu diff --git a/components/consts/modconsts.c b/components/consts/modconsts.c new file mode 100644 index 0000000..3a1ad7b --- /dev/null +++ b/components/consts/modconsts.c @@ -0,0 +1,70 @@ +#include "sdkconfig.h" +#include +#include +#include "py/builtin.h" +#include "py/objlist.h" +#include "py/objtuple.h" +#include "py/objstr.h" +#include "py/objint.h" +#include "py/objtype.h" +#include "py/stream.h" +#include "py/smallint.h" +#include "py/runtime.h" +#include "shared/runtime/pyexec.h" + +#define INT_TO_STR_EX(number) #number +#define INT_TO_STR(number) INT_TO_STR_EX(number) + +#ifdef CONFIG_OTA_WEB_USE_HTTPS +#define OTA_PROTOCOL "https" +#else +#define OTA_PROTOCOL "http" +#endif + +#if defined(CONFIG_DEFAULT_DISPLAY_ORIENTATION_PORTRAIT) + #define DEFAULT_ORIENTATION 90 +#elif defined(CONFIG_DEFAULT_DISPLAY_ORIENTATION_REVERSE_LANDSCAPE) + #define DEFAULT_ORIENTATION 180 +#elif defined(CONFIG_DEFAULT_DISPLAY_ORIENTATION_REVERSE_PORTRAIT) + #define DEFAULT_ORIENTATION 270 +#else + #define DEFAULT_ORIENTATION 0 +#endif + +static const MP_DEFINE_STR_OBJ( info_firmware_name_obj, CONFIG_INFO_FIRMWARE_NAME ); +static const MP_DEFINE_STR_OBJ( info_hardware_name_obj, CONFIG_INFO_HARDWARE_NAME ); +static const MP_DEFINE_STR_OBJ( info_hardware_folder_obj, CONFIG_MICROPY_FROZEN_MANIFEST ); +static const MP_DEFINE_STR_OBJ( ota_web_server_obj, CONFIG_OTA_WEB_SERVER ); +static const MP_DEFINE_STR_OBJ( ota_web_port_obj, INT_TO_STR(CONFIG_OTA_WEB_PORT) ); +static const MP_DEFINE_STR_OBJ( ota_web_protocol_obj, OTA_PROTOCOL ); +static const MP_DEFINE_STR_OBJ( ota_web_path_obj, CONFIG_OTA_WEB_PATH ); +static const MP_DEFINE_STR_OBJ( ota_web_version_path_obj, CONFIG_OTA_WEB_VERSION_PATH ); +static const MP_DEFINE_STR_OBJ( info_woezel_web_server_obj, CONFIG_WOEZEL_WEB_SERVER ); +static const MP_DEFINE_STR_OBJ( info_hardware_woezel_name_obj, CONFIG_INFO_HARDWARE_WOEZEL_NAME ); +static const MP_DEFINE_STR_OBJ( wifi_ssid_obj, CONFIG_WIFI_SSID ); +static const MP_DEFINE_STR_OBJ( wifi_pass_obj, CONFIG_WIFI_PASSWORD ); + +static const mp_rom_map_elem_t consts_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_INFO_FIRMWARE_NAME ), MP_ROM_PTR( &info_firmware_name_obj ) }, + { MP_ROM_QSTR(MP_QSTR_INFO_FIRMWARE_BUILD ), MP_ROM_INT( CONFIG_INFO_FIRMWARE_BUILD ) }, + { MP_ROM_QSTR(MP_QSTR_INFO_HARDWARE_NAME ), MP_ROM_PTR( &info_hardware_name_obj ) }, + { MP_ROM_QSTR(MP_QSTR_INFO_HARDWARE_FOLDER ), MP_ROM_PTR( &info_hardware_folder_obj ) }, + { MP_ROM_QSTR(MP_QSTR_WOEZEL_WEB_SERVER ), MP_ROM_PTR( &info_woezel_web_server_obj ) }, + { MP_ROM_QSTR(MP_QSTR_INFO_HARDWARE_WOEZEL_NAME ), MP_ROM_PTR( &info_hardware_woezel_name_obj ) }, + { MP_ROM_QSTR(MP_QSTR_OTA_WEB_SERVER ), MP_ROM_PTR( &ota_web_server_obj ) }, + { MP_ROM_QSTR(MP_QSTR_OTA_WEB_PORT ), MP_ROM_PTR( &ota_web_port_obj ) }, + { MP_ROM_QSTR(MP_QSTR_OTA_WEB_PROTOCOL ), MP_ROM_PTR( &ota_web_protocol_obj ) }, + { MP_ROM_QSTR(MP_QSTR_OTA_WEB_PATH ), MP_ROM_PTR( &ota_web_path_obj ) }, + { MP_ROM_QSTR(MP_QSTR_OTA_WEB_VERSION_PATH ), MP_ROM_PTR( &ota_web_version_path_obj ) }, + { MP_ROM_QSTR(MP_QSTR_WIFI_SSID ), MP_ROM_PTR( &wifi_ssid_obj ) }, + { MP_ROM_QSTR(MP_QSTR_WIFI_PASSWORD ), MP_ROM_PTR( &wifi_pass_obj ) }, + { MP_ROM_QSTR(MP_QSTR_DEFAULT_ORIENTATION ), MP_ROM_INT( DEFAULT_ORIENTATION ) }, +}; + +static MP_DEFINE_CONST_DICT(consts_module_globals, consts_module_globals_table); + +const mp_obj_module_t consts_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&consts_module_globals, +}; +MP_REGISTER_MODULE(MP_QSTR_consts, consts_module); diff --git a/components/driver_badge_bsp/CMakeLists.txt b/components/driver_badge_bsp/CMakeLists.txt new file mode 100644 index 0000000..ff62d53 --- /dev/null +++ b/components/driver_badge_bsp/CMakeLists.txt @@ -0,0 +1,19 @@ +if(CONFIG_DRIVER_BADGE_BSP_ENABLE) + set(srcs + "driver_badge_bsp.c" + ) + set(includes + "include" + ) +else() + set(srcs "") + set(includes + "" + ) +endif() + +idf_component_register( + SRCS "${srcs}" + INCLUDE_DIRS ${includes} + REQUIRES micropython badge-bsp +) diff --git a/components/driver_badge_bsp/Kconfig b/components/driver_badge_bsp/Kconfig new file mode 100644 index 0000000..d736284 --- /dev/null +++ b/components/driver_badge_bsp/Kconfig @@ -0,0 +1,6 @@ +menu "Driver: Badge BSP display" + config DRIVER_BADGE_BSP_ENABLE + bool "Enable the Badge BSP display driver" + default n + +endmenu diff --git a/components/driver_badge_bsp/driver_badge_bsp.c b/components/driver_badge_bsp/driver_badge_bsp.c new file mode 100644 index 0000000..febee19 --- /dev/null +++ b/components/driver_badge_bsp/driver_badge_bsp.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "include/driver_badge_bsp.h" + +#define TAG "badge_bsp" + +static size_t h_res; +static size_t v_res; +static lcd_color_rgb_pixel_format_t color_fmt; +static lcd_rgb_data_endian_t data_endian; + +esp_err_t driver_badge_bsp_init(void) +{ + esp_err_t err = bsp_display_get_parameters(&h_res, &v_res, &color_fmt, &data_endian); + if (err == ESP_OK) { + ESP_LOGI(TAG, "h_res: %d, v_res: %d, color_fmt: %d, data_endian: %d", h_res, v_res, color_fmt, data_endian); + } else { + ESP_LOGI(TAG, "error: %d", err); + } + return err; +} + +size_t driver_badge_bsp_get_width(void) +{ + return h_res; +} + +size_t driver_badge_bsp_get_height(void) +{ + return v_res; +} + +size_t driver_badge_bsp_get_size(void) +{ + size_t size = h_res * v_res * 2; + return size; +} + +esp_err_t driver_badge_bsp_set_backlight_brightness(uint8_t percentage) +{ + return bsp_display_set_backlight_brightness(percentage); +} + +esp_err_t driver_badge_bsp_flush(const uint8_t *buffer, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + return bsp_display_blit(x0, y0, x1 - x0 + 1, y1 - y0 + 1, buffer); +} diff --git a/components/driver_badge_bsp/include/driver_badge_bsp.h b/components/driver_badge_bsp/include/driver_badge_bsp.h new file mode 100644 index 0000000..a3da2cd --- /dev/null +++ b/components/driver_badge_bsp/include/driver_badge_bsp.h @@ -0,0 +1,21 @@ +#ifndef DRIVER_BADGE_BSP_H +#define DRIVER_BADGE_BSP_H + +#include +#include +#include +#include "bsp/display.h" + +__BEGIN_DECLS + +extern esp_err_t driver_badge_bsp_init(void); +extern size_t driver_badge_bsp_get_width(void); +extern size_t driver_badge_bsp_get_height(void); +extern size_t driver_badge_bsp_get_size(void); +extern esp_err_t driver_badge_bsp_set_backlight_brightness(uint8_t percentage); + +extern esp_err_t driver_badge_bsp_flush(const uint8_t *buffer, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + +__END_DECLS + +#endif // DRIVER_BADGE_BSP_H diff --git a/components/driver_badge_bsp/include/framebuffer_display.h b/components/driver_badge_bsp/include/framebuffer_display.h new file mode 100644 index 0000000..a34f5d4 --- /dev/null +++ b/components/driver_badge_bsp/include/framebuffer_display.h @@ -0,0 +1,17 @@ +#ifndef __FRAMEBUFFER_DISPLAY_H__ +#define __FRAMEBUFFER_DISPLAU_H__ + +#include "driver_badge_bsp.h" + +//This header file containes the defines used by the framebuffer driver. + +#define FB_SIZE driver_badge_bsp_get_size() +#define FB_WIDTH driver_badge_bsp_get_width() +#define FB_HEIGHT driver_badge_bsp_get_height() +#define FB_TYPE_16BPP +#define FB_ALPHA_ENABLED +#define FB_FLUSH(buffer,eink_flags,x0,y0,x1,y1) driver_badge_bsp_flush(buffer, x0, y0, x1 - x0 + 1, y1 - y0 + 1); +#define FB_SET_BACKLIGHT(brightness) driver_badge_bsp_set_backlight_brightness(brightness) +#define COLOR_FILL_DEFAULT 0x000000 +#define COLOR_TEXT_DEFAULT 0xFFFFFF +#endif diff --git a/components/driver_display_ili9341/CMakeLists.txt b/components/driver_display_ili9341/CMakeLists.txt index 1e040eb..dac493b 100644 --- a/components/driver_display_ili9341/CMakeLists.txt +++ b/components/driver_display_ili9341/CMakeLists.txt @@ -16,4 +16,4 @@ endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS ${includes} - REQUIRES driver_framebuffer) + REQUIRES micropython driver_framebuffer) diff --git a/components/driver_framebuffer/CMakeLists.txt b/components/driver_framebuffer/CMakeLists.txt index d39f7ea..ad82f97 100644 --- a/components/driver_framebuffer/CMakeLists.txt +++ b/components/driver_framebuffer/CMakeLists.txt @@ -64,16 +64,33 @@ set(IDF_COMPONENTS micropython buses driver_display_ili9341 - driver_display_depg0290b1 - driver_display_ssd1306 - driver_io_disobey_samd +# driver_display_depg0290b1 +# driver_display_ssd1306 +# driver_io_disobey_samd spi_flash + esp_partition + esp_timer + esp_mm ) set(includes "include" - "png") + "png" +) + +# Compute the MicroPython root relative to this component +set(MP_ROOT ${PROJECT_DIR}/../..) -idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS ${includes} - REQUIRES ${IDF_COMPONENTS}) +idf_component_register( + SRCS "${srcs}" + PRIV_INCLUDE_DIRS + ${MP_ROOT} # micropython/ + ${MP_ROOT}/py # micropython/py + ${PROJECT_DIR} # micropython/ports/esp32 + ${MICROPY_BOARD_DIR} # board headers (mpconfigboard.h) + ${CMAKE_CURRENT_LIST_DIR}/.. + ${BUILD_DIR} + + INCLUDE_DIRS ${includes} + REQUIRES ${IDF_COMPONENTS} +) diff --git a/components/driver_framebuffer/driver_framebuffer.cpp b/components/driver_framebuffer/driver_framebuffer.cpp index 465344d..aa614da 100644 --- a/components/driver_framebuffer/driver_framebuffer.cpp +++ b/components/driver_framebuffer/driver_framebuffer.cpp @@ -10,6 +10,7 @@ #include "esp_system.h" + #include "include/driver_framebuffer_internal.h" #define TAG "fb" diff --git a/components/driver_framebuffer/moddisplay.c b/components/driver_framebuffer/moddisplay.c index 6f3e39a..8902bc8 100644 --- a/components/driver_framebuffer/moddisplay.c +++ b/components/driver_framebuffer/moddisplay.c @@ -7,8 +7,8 @@ #include "py/runtime.h" #include "py/objarray.h" -#include "vfs.h" -#include "vfs_native.h" +//#include "vfs.h" +//#include "vfs_native.h" #ifndef NO_QSTR #include "include/driver_framebuffer.h" @@ -851,6 +851,12 @@ static mp_obj_t framebuffer_get_text_height(mp_uint_t n_args, const mp_obj_t *ar return mp_obj_new_int(value); } +static int physicalPathN(char *filename, char *fullname, size_t size) +{ + snprintf(fullname, size, "/sd/%s", filename); + return 0; +} + static mp_obj_t framebuffer_png_info(mp_uint_t n_args, const mp_obj_t *args) { lib_reader_read_t reader; @@ -870,6 +876,7 @@ static mp_obj_t framebuffer_png_info(mp_uint_t n_args, const mp_obj_t *args) const char* filename = mp_obj_str_get_str(args[0]); char fullname[128] = {'\0'}; int res = physicalPathN(filename, fullname, sizeof(fullname)); + if ((res != 0) || (strlen(fullname) == 0)) { mp_raise_ValueError("Error resolving file name"); return mp_const_none; @@ -1446,7 +1453,7 @@ static mp_obj_t framebuffer_transformPoint(mp_uint_t n_args, const mp_obj_t *arg matrix_3d_transform_point(stack_3d->current, &x, &y, &z); - mp_obj_t out[2] = { + mp_obj_t out[3] = { mp_obj_new_float(x), mp_obj_new_float(y), mp_obj_new_float(z) @@ -1808,7 +1815,7 @@ static mp_obj_t framebuffer_get3D(mp_uint_t n_args, const mp_obj_t *args) { } } -static mp_obj_t framebuffer_clearDepth(mp_uint_t n_args, const mp_obj_t *args) +static mp_obj_t framebuffer_clearDepth(void) { depth_buffer_3d *buffer = &depth_buffer_global; @@ -2078,5 +2085,6 @@ const mp_obj_module_t udisplay_module = { .base = {&mp_type_module}, .globals = (mp_obj_dict_t *)&framebuffer_module_globals, }; +MP_REGISTER_MODULE(MP_QSTR_display, udisplay_module); #endif //CONFIG_DRIVER_FRAMEBUFFER_ENABLE diff --git a/components/driver_framebuffer/png/flash_reader.h b/components/driver_framebuffer/png/flash_reader.h index dac0f6d..085a7a1 100644 --- a/components/driver_framebuffer/png/flash_reader.h +++ b/components/driver_framebuffer/png/flash_reader.h @@ -4,6 +4,8 @@ #include #include +#define SPI_FLASH_SEC_SIZE 4096 + struct lib_flash_reader { const esp_partition_t *part; size_t offset; diff --git a/components/driver_mch22/CMakeLists.txt b/components/driver_mch22/CMakeLists.txt index bdb9876..4cb0de1 100644 --- a/components/driver_mch22/CMakeLists.txt +++ b/components/driver_mch22/CMakeLists.txt @@ -1,3 +1,4 @@ +#message(STATUS "CONFIG_DRIVER_MCH22_RP2040_ENABLE: ${CONFIG_DRIVER_MCH22_RP2040_ENABLE}") if(CONFIG_DRIVER_MCH22_RP2040_ENABLE) set(srcs "esp32-component-mch2022-rp2040/rp2040.c" @@ -14,8 +15,29 @@ set(include "esp32-component-spi-ice40/include" ) +# REQUIRES micropython buses driver_display_ili9341 + +# Compute the MicroPython root relative to this component +set(MP_ROOT ${PROJECT_DIR}/../..) + +#message(STATUS ${MP_GENHDR}) idf_component_register( - SRCS "${srcs}" - INCLUDE_DIRS "${include}" - REQUIRES micropython buses driver_display_ili9341 + SRCS "${srcs}" + INCLUDE_DIRS "${include}" + PRIV_INCLUDE_DIRS + ${MP_ROOT} # micropython/ + ${MP_ROOT}/py # micropython/py + ${PROJECT_DIR} # micropython/ports/esp32 + ${MICROPY_BOARD_DIR} # board headers (mpconfigboard.h) + ${CMAKE_CURRENT_LIST_DIR}/.. + ${BUILD_DIR} + REQUIRES + micropython + buses + driver_display_ili9341 + driver + freertos + esp_timer + esp_hw_support + esp_mm ) diff --git a/components/driver_mch22/esp32-component-mch2022-rp2040 b/components/driver_mch22/esp32-component-mch2022-rp2040 index b04727d..ae563b2 160000 --- a/components/driver_mch22/esp32-component-mch2022-rp2040 +++ b/components/driver_mch22/esp32-component-mch2022-rp2040 @@ -1 +1 @@ -Subproject commit b04727dffbc79c90ac705ab620e60f8daf2c13a0 +Subproject commit ae563b23221acfbafe3fce7d9752790aa981aa00 diff --git a/components/driver_mch22/modmch22.c b/components/driver_mch22/modmch22.c index 1ddebe6..04c7166 100644 --- a/components/driver_mch22/modmch22.c +++ b/components/driver_mch22/modmch22.c @@ -1,4 +1,5 @@ #ifndef NO_QSTR +#include #include "rp2040.h" #include "ice40.h" @@ -14,7 +15,7 @@ #include #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" -#endif +#endif /* NO_QSTR */ #define TAG "RP2040_UPY" @@ -28,6 +29,8 @@ #define MAXIMUM_CALLBACK_RETRY (10) +#define STATIC static + static ICE40 ice40; static RP2040 rp2040; static mp_obj_t touch_callback = mp_const_none; @@ -50,7 +53,9 @@ static esp_err_t ice40_set_reset_wrapper(bool reset) { } void driver_mch22_init() { - rp2040.i2c_bus = 0; + ESP_LOGI(TAG, "driver_mch22_init()"); + + rp2040.i2c_bus = 1; rp2040.i2c_address = RP2040_ADDR; rp2040.pin_interrupt = GPIO_INT_RP2040; rp2040.queue = xQueueCreate(15, sizeof(rp2040_input_message_t)); @@ -82,7 +87,7 @@ void driver_mch22_init() { } } - xTaskCreatePinnedToCore(button_handler, "button_handler_task", 2048, NULL, 100, NULL, MP_TASK_COREID); + xTaskCreatePinnedToCore(button_handler, "button_handler_task", 2048, NULL, 5, NULL, MP_TASK_COREID); //xTaskCreatePinnedToCore(webusb_handler, "webusb_handler_task", 2048, NULL, 100, NULL, MP_TASK_COREID); } @@ -95,7 +100,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(buttons_obj, buttons); static mp_obj_t get_gpio_dir(mp_obj_t gpio) { uint8_t value_gpio = mp_obj_get_int(gpio); - uint8_t value_direction; + bool value_direction; rp2040_get_gpio_dir(&rp2040, value_gpio, &value_direction); return mp_obj_new_int(value_direction); } @@ -111,7 +116,7 @@ static MP_DEFINE_CONST_FUN_OBJ_2(set_gpio_dir_obj, set_gpio_dir); static mp_obj_t get_gpio_value(mp_obj_t gpio) { uint8_t value_gpio = mp_obj_get_int(gpio); - uint8_t value_value; + bool value_value; rp2040_get_gpio_value(&rp2040, value_gpio, &value_value); return mp_obj_new_int(value_value); } @@ -161,13 +166,13 @@ static MP_DEFINE_CONST_FUN_OBJ_0(disable_webusb_obj, enable_webusb);*/ static mp_obj_t driver_ice40_load_bitstream(mp_obj_t bitstream) { if (!MP_OBJ_IS_TYPE(bitstream, &mp_type_bytes)) { - mp_raise_ValueError("Expected a bytestring like object"); + mp_raise_ValueError(MP_ERROR_TEXT("Expected a bytestring like object")); return mp_const_none; } mp_uint_t length; uint8_t* data = (uint8_t*) mp_obj_str_get_data(bitstream, &length); esp_err_t res = ice40_load_bitstream(&ice40, data, length); - if (res != ESP_OK) mp_raise_ValueError("Failed to load bitstream"); + if (res != ESP_OK) mp_raise_ValueError(MP_ERROR_TEXT("Failed to load bitstream")); return mp_const_none; } @@ -193,7 +198,7 @@ static uint8_t* get_buffer_data(mp_obj_t transmit_data, mp_uint_t* length) *length = (mp_uint_t) bufinfo.len; } } else { - mp_raise_ValueError("Expected a bytestring like object"); + mp_raise_ValueError(MP_ERROR_TEXT("Expected a bytestring like object")); } return data_out; } @@ -205,7 +210,7 @@ static mp_obj_t driver_ice40_transaction(mp_obj_t transmit_data) { if (data_out != NULL) { uint8_t* data_in = heap_caps_malloc(length + 4, MALLOC_CAP_DMA); if (data_in == NULL) { - mp_raise_ValueError("Out of memory"); + mp_raise_ValueError(MP_ERROR_TEXT("Out of memory")); return mp_const_none; } @@ -213,7 +218,7 @@ static mp_obj_t driver_ice40_transaction(mp_obj_t transmit_data) { if (res != ESP_OK) { heap_caps_free(data_in); - mp_raise_ValueError("Failed to execute transaction"); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to execute transaction")); return mp_const_none; } @@ -230,7 +235,7 @@ static mp_obj_t driver_ice40_receive(mp_obj_t length_obj) { size_t length = mp_obj_get_int(length_obj); uint8_t* data_in = heap_caps_malloc(length, MALLOC_CAP_DMA); if (data_in == NULL) { - mp_raise_ValueError("Out of memory"); + mp_raise_ValueError(MP_ERROR_TEXT("Out of memory")); return mp_const_none; } @@ -238,7 +243,7 @@ static mp_obj_t driver_ice40_receive(mp_obj_t length_obj) { if (res != ESP_OK) { heap_caps_free(data_in); - mp_raise_ValueError("Failed to execute transaction"); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to execute transaction")); return mp_const_none; } @@ -257,7 +262,7 @@ static mp_obj_t driver_ice40_send(mp_obj_t transmit_data) { esp_err_t res = ice40_send(&ice40, data_out, length); if (res != ESP_OK) { - mp_raise_ValueError("Failed to execute transaction"); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to execute transaction")); } } return mp_const_none; @@ -273,7 +278,7 @@ static mp_obj_t driver_ice40_send_turbo(mp_obj_t transmit_data) { esp_err_t res = ice40_send_turbo(&ice40, data_out, length); if (res != ESP_OK) { - mp_raise_ValueError("Failed to execute transaction"); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to execute transaction")); } } return mp_const_none; @@ -301,7 +306,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(mch22_return_to_launcher_obj, driver_mch22_retu static mp_obj_t read_vbat() { float vbat = 0; if (rp2040_read_vbat(&rp2040, &vbat) != ESP_OK) { - mp_raise_ValueError("Failed to get battery voltage"); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to get battery voltage")); return mp_const_none; } return mp_obj_new_float(vbat); @@ -311,7 +316,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(read_vbat_obj, read_vbat); static mp_obj_t read_vusb() { float vusb = 0; if (rp2040_read_vusb(&rp2040, &vusb) != ESP_OK) { - mp_raise_ValueError("Failed to get USB voltage"); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to get USB voltage")); return mp_const_none; } return mp_obj_new_float(vusb); @@ -351,10 +356,11 @@ STATIC const mp_rom_map_elem_t mch22_module_globals_table[] = { STATIC MP_DEFINE_CONST_DICT(mch22_module_globals, mch22_module_globals_table); //=================================== -const mp_obj_module_t mch22_module = { +const mp_obj_module_t mp_module_mch22 = { .base = {&mp_type_module}, .globals = (mp_obj_dict_t *)&mch22_module_globals, }; +MP_REGISTER_MODULE(MP_QSTR_mch22, mp_module_mch22); static void button_handler(void *parameter) { diff --git a/components/driver_rtcmem/CMakeLists.txt b/components/driver_rtcmem/CMakeLists.txt index 9666a34..e9d18a3 100644 --- a/components/driver_rtcmem/CMakeLists.txt +++ b/components/driver_rtcmem/CMakeLists.txt @@ -7,6 +7,26 @@ set(includes "include" ) -idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS ${includes} - REQUIRES lwip micropython) +# Compute the MicroPython root relative to this component +set(MP_ROOT ${PROJECT_DIR}/../..) + +set(IDF_COMPONENTS + nvs_flash + esp_driver_gpio + esp_driver_spi + esp_mm + micropython +) + +idf_component_register( + SRCS "${srcs}" + INCLUDE_DIRS ${includes} + PRIV_INCLUDE_DIRS + ${MP_ROOT} # micropython/ + ${MP_ROOT}/py # micropython/py + ${PROJECT_DIR} # micropython/ports/esp32 + ${MICROPY_BOARD_DIR} # board headers (mpconfigboard.h) + ${CMAKE_CURRENT_LIST_DIR}/.. + ${BUILD_DIR} + REQUIRES ${IDF_COMPONENTS} +) diff --git a/components/driver_rtcmem/driver_rtcmem.c b/components/driver_rtcmem/driver_rtcmem.c index 31dde10..c5127ca 100644 --- a/components/driver_rtcmem/driver_rtcmem.c +++ b/components/driver_rtcmem/driver_rtcmem.c @@ -1,66 +1,105 @@ -#include -#include -#include #include -#include -#include -#include -#include -#include -#include - -#include "driver/rtc_io.h" -#include "include/driver_rtcmem.h" +#include "driver_rtcmem.h" +#include "esp_log.h" +#include "esp_attr.h" #define TAG "rtcmem" +#define STATIC static + #define RTC_MEM_INT_SIZE 64 -#define RTC_MEM_STR_SIZE 512 +#define RTC_MEM_STR_SIZE 64 + +// --------------------------------------------------------------------------- +// RTC memory storage (modern ESP-IDF 5.x method) +// --------------------------------------------------------------------------- + +RTC_SLOW_ATTR static int rtc_mem_int[RTC_MEM_INT_SIZE]; +RTC_SLOW_ATTR static char rtc_mem_str[RTC_MEM_STR_SIZE]; + +// --------------------------------------------------------------------------- +// Initialization (kept for API compatibility) +// --------------------------------------------------------------------------- + +esp_err_t driver_rtcmem_init(void) { + // Nothing to initialize in IDF 5.x, but keep API stable + return ESP_OK; +} -static int *const rtc_mem_int = (int *const) (RTC_SLOW_MEM + CONFIG_ESP32_ULP_COPROC_RESERVE_MEM); -static uint16_t *const rtc_mem_int_crc = (uint16_t *const) (rtc_mem_int + (sizeof(int) * RTC_MEM_INT_SIZE)); -static char *const rtc_mem_str = (char *const) (rtc_mem_int_crc + sizeof(uint16_t)); -static uint16_t *const rtc_mem_str_crc = (uint16_t *const) (rtc_mem_str + (RTC_MEM_STR_SIZE * sizeof(char))); +// --------------------------------------------------------------------------- +// Integer API +// --------------------------------------------------------------------------- esp_err_t driver_rtcmem_int_write(int pos, int val) { - if (pos >= RTC_MEM_INT_SIZE) return ESP_FAIL; + if (pos < 0 || pos >= RTC_MEM_INT_SIZE) { + return ESP_ERR_INVALID_ARG; + } rtc_mem_int[pos] = val; - *rtc_mem_int_crc = crc16_le(0, (uint8_t const *)rtc_mem_int, RTC_MEM_INT_SIZE*sizeof(int)); return ESP_OK; } -esp_err_t driver_rtcmem_int_read(int pos, int* val) { - if (pos >= RTC_MEM_INT_SIZE) return ESP_FAIL; - if (*rtc_mem_int_crc != crc16_le(0, (uint8_t const *)rtc_mem_int, RTC_MEM_INT_SIZE*sizeof(int))) return ESP_FAIL; +esp_err_t driver_rtcmem_int_read(int pos, int *val) { + if (!val) { + return ESP_ERR_INVALID_ARG; + } + if (pos < 0 || pos >= RTC_MEM_INT_SIZE) { + *val = 0; + return ESP_ERR_INVALID_ARG; + } *val = rtc_mem_int[pos]; return ESP_OK; } -esp_err_t driver_rtcmem_string_write(const char* str) { - if (strlen(str) >= RTC_MEM_STR_SIZE) return ESP_FAIL; - memset(rtc_mem_str, 0, RTC_MEM_STR_SIZE*sizeof(char)); - strcpy(rtc_mem_str, str); - *rtc_mem_str_crc = crc16_le(0, (uint8_t const *)rtc_mem_str, RTC_MEM_STR_SIZE); +// --------------------------------------------------------------------------- +// String API +// --------------------------------------------------------------------------- + +esp_err_t driver_rtcmem_string_write(const char *str) { + if (!str) { + return ESP_ERR_INVALID_ARG; + } + + size_t len = strlen(str); + if (len > RTC_MEM_STR_SIZE) { + len = RTC_MEM_STR_SIZE; + } + + memset(rtc_mem_str, 0, RTC_MEM_STR_SIZE); + memcpy(rtc_mem_str, str, len); + return ESP_OK; } -esp_err_t driver_rtcmem_string_read(const char** str) { - if (*rtc_mem_str_crc != crc16_le(0, (uint8_t const *)rtc_mem_str, RTC_MEM_STR_SIZE)) return ESP_FAIL; +esp_err_t driver_rtcmem_string_read(const char **str) { + if (!str) { + return ESP_ERR_INVALID_ARG; + } + + // Return pointer directly into RTC memory *str = rtc_mem_str; return ESP_OK; } -esp_err_t driver_rtcmem_clear() { - memset(rtc_mem_int, 0, RTC_MEM_INT_SIZE*sizeof(int)); - memset(rtc_mem_str, 0, RTC_MEM_STR_SIZE*sizeof(char)); - *rtc_mem_int_crc = 0; - *rtc_mem_str_crc = 0; +// --------------------------------------------------------------------------- +// Clear API +// --------------------------------------------------------------------------- + +esp_err_t driver_rtcmem_clear(void) { + memset(rtc_mem_int, 0, sizeof(rtc_mem_int)); + memset(rtc_mem_str, 0, sizeof(rtc_mem_str)); return ESP_OK; } +// --------------------------------------------------------------------------- +// Optional debug dump +// --------------------------------------------------------------------------- + +void driver_rtcmem_dump(void) { + ESP_LOGI(TAG, "RTC int values:"); + for (int i = 0; i < RTC_MEM_INT_SIZE; i++) { + ESP_LOGI(TAG, " [%02d] = %d", i, rtc_mem_int[i]); + } -esp_err_t driver_rtcmem_init(void) -{ - //Empty - return ESP_OK; + ESP_LOGI(TAG, "RTC string:"); + ESP_LOG_BUFFER_HEX(TAG, rtc_mem_str, RTC_MEM_STR_SIZE); } diff --git a/components/driver_rtcmem/include/driver_rtcmem.h b/components/driver_rtcmem/include/driver_rtcmem.h index b949529..fe0cccd 100644 --- a/components/driver_rtcmem/include/driver_rtcmem.h +++ b/components/driver_rtcmem/include/driver_rtcmem.h @@ -5,18 +5,26 @@ #include #include -__BEGIN_DECLS +#ifdef __cplusplus +extern "C" { +#endif -extern esp_err_t driver_rtcmem_int_write(int pos, int val); -extern esp_err_t driver_rtcmem_int_read(int pos, int* val); +// Initialize RTC memory subsystem (optional for IDF 5.x) +esp_err_t driver_rtcmem_init(void); -extern esp_err_t driver_rtcmem_string_write(const char* str); -extern esp_err_t driver_rtcmem_string_read(const char** str); +// Integer API +esp_err_t driver_rtcmem_int_write(int pos, int val); +esp_err_t driver_rtcmem_int_read(int pos, int *val); -extern esp_err_t driver_rtcmem_clear(); +// String API +esp_err_t driver_rtcmem_string_write(const char *str); +esp_err_t driver_rtcmem_string_read(const char **str); -extern esp_err_t driver_rtcmem_init(void); +// Clear all RTC memory regions used by this driver +esp_err_t driver_rtcmem_clear(void); -__END_DECLS +#ifdef __cplusplus +} +#endif #endif // DRIVER_RTCMEM_H diff --git a/components/driver_rtcmem/modrtcmem.c b/components/driver_rtcmem/modrtcmem.c index 9fb1e21..1d54f00 100644 --- a/components/driver_rtcmem/modrtcmem.c +++ b/components/driver_rtcmem/modrtcmem.c @@ -1,73 +1,111 @@ -#include "include/driver_rtcmem.h" +#include "py/obj.h" +#include "py/runtime.h" +#ifndef NO_QSTR +#include "driver_rtcmem.h" +#endif -#include -#include +#define STATIC static -#include "sdkconfig.h" +// --------------------------------------------------------------------------- +// Integer API +// --------------------------------------------------------------------------- -#include "py/obj.h" -#include "py/objstr.h" -#include "py/runtime.h" +STATIC mp_obj_t mod_rtcmem_int_read(mp_obj_t index_in) { + int index = mp_obj_get_int(index_in); + int value = 0; -#include "mphalport.h" -#include "modmachine.h" + if (driver_rtcmem_int_read(index, &value) != ESP_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("rtcmem int_read failed")); + } -// ====== RTC memory functions ============================ + return mp_obj_new_int(value); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_rtcmem_int_read_obj, mod_rtcmem_int_read); -//-------------------------------------------------------------------------------- -STATIC mp_obj_t esp_rtcmem_write(mp_obj_t _pos, mp_obj_t _val) { - int pos = mp_obj_get_int(_pos); - int val = mp_obj_get_int(_val); - if (driver_rtcmem_int_write(pos, val) != ESP_OK) return mp_const_false; - return mp_const_true; +STATIC mp_obj_t mod_rtcmem_int_write(mp_obj_t index_in, mp_obj_t value_in) { + int index = mp_obj_get_int(index_in); + int value = mp_obj_get_int(value_in); + + if (driver_rtcmem_int_write(index, value) != ESP_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("rtcmem int_write failed")); + } + + return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_rtcmem_write_obj, esp_rtcmem_write); - -//---------------------------------------------------------------- -STATIC mp_obj_t esp_rtcmem_read(mp_obj_t _pos) { - int pos = mp_obj_get_int(_pos); - int value; - if (driver_rtcmem_int_read(pos, &value) != ESP_OK) return mp_const_none; - return mp_obj_new_int(value); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_rtcmem_int_write_obj, mod_rtcmem_int_write); + +// We now clear both int + string via driver_rtcmem_clear() +STATIC mp_obj_t mod_rtcmem_int_clear(void) { + if (driver_rtcmem_clear() != ESP_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("rtcmem clear failed")); + } + return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_rtcmem_read_obj, esp_rtcmem_read); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_rtcmem_int_clear_obj, mod_rtcmem_int_clear); + +// --------------------------------------------------------------------------- +// String API +// --------------------------------------------------------------------------- -//-------------------------------------------------------------------------- -STATIC mp_obj_t esp_rtcmem_write_string(mp_obj_t str_in) { - const char *str = mp_obj_str_get_str(str_in); - if (driver_rtcmem_string_write(str) != ESP_OK) return mp_const_false; - return mp_const_true; +STATIC mp_obj_t mod_rtcmem_str_read(void) { + const char *ptr = NULL; + + if (driver_rtcmem_string_read(&ptr) != ESP_OK || ptr == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("rtcmem read_string failed")); + } + + // Stored as a fixed-size buffer; treat as C string + return mp_obj_new_str(ptr, strlen(ptr)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_rtcmem_write_string_obj, esp_rtcmem_write_string); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_rtcmem_str_read_obj, mod_rtcmem_str_read); + +STATIC mp_obj_t mod_rtcmem_str_write(mp_obj_t str_in) { + size_t len; + const char *str = mp_obj_str_get_data(str_in, &len); -//-------------------------------------------------------- -STATIC mp_obj_t esp_rtcmem_read_string() { - const char* str; - if (driver_rtcmem_string_read(&str) != ESP_OK) return mp_const_none; - return mp_obj_new_str(str, strlen(str)); + // Truncation is handled inside driver_rtcmem_string_write + if (driver_rtcmem_string_write(str) != ESP_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("rtcmem write_string failed")); + } + + return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_rtcmem_read_string_obj, esp_rtcmem_read_string); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_rtcmem_str_write_obj, mod_rtcmem_str_write); -//-------------------------------------------------- -STATIC mp_obj_t esp_rtcmem_clear() { - driver_rtcmem_clear(); - return mp_const_none; +// For symmetry with the old API: clear string only +STATIC mp_obj_t mod_rtcmem_str_clear(void) { + // We don't have a dedicated string-clear in the driver anymore, + // so reuse driver_rtcmem_clear() and accept that it clears ints too. + if (driver_rtcmem_clear() != ESP_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("rtcmem clear_string failed")); + } + return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_rtcmem_clear_obj, esp_rtcmem_clear); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_rtcmem_str_clear_obj, mod_rtcmem_str_clear); +// --------------------------------------------------------------------------- +// Module globals +// --------------------------------------------------------------------------- -//========================================================= STATIC const mp_rom_map_elem_t rtcmem_module_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&esp_rtcmem_write_obj}, - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&esp_rtcmem_read_obj}, - { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&esp_rtcmem_clear_obj}, - { MP_OBJ_NEW_QSTR(MP_QSTR_write_string), (mp_obj_t)&esp_rtcmem_write_string_obj}, - { MP_OBJ_NEW_QSTR(MP_QSTR_read_string), (mp_obj_t)&esp_rtcmem_read_string_obj}, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rtcmem) }, + + // Integer API + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mod_rtcmem_int_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mod_rtcmem_int_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&mod_rtcmem_int_clear_obj) }, + + // String API + { MP_ROM_QSTR(MP_QSTR_read_string), MP_ROM_PTR(&mod_rtcmem_str_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_string), MP_ROM_PTR(&mod_rtcmem_str_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_string), MP_ROM_PTR(&mod_rtcmem_str_clear_obj) }, }; + STATIC MP_DEFINE_CONST_DICT(rtcmem_module_globals, rtcmem_module_globals_table); -//=================================== -const mp_obj_module_t rtcmem_module = { - .base = {&mp_type_module}, +const mp_obj_module_t mp_module_rtcmem = { + .base = { &mp_type_module }, .globals = (mp_obj_dict_t *)&rtcmem_module_globals, -}; \ No newline at end of file +}; + +MP_REGISTER_MODULE(MP_QSTR_rtcmem, mp_module_rtcmem); diff --git a/components/driver_sndmixer/CMakeLists.txt b/components/driver_sndmixer/CMakeLists.txt index 33af2d1..68932b4 100644 --- a/components/driver_sndmixer/CMakeLists.txt +++ b/components/driver_sndmixer/CMakeLists.txt @@ -38,9 +38,26 @@ set(includes set(IDF_COMPONENTS nvs_flash + esp_driver_i2s + esp_driver_gpio + esp_driver_spi + esp_mm libopus - micropython) + micropython +) -idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS ${includes} - REQUIRES ${IDF_COMPONENTS}) +# Compute the MicroPython root relative to this component +set(MP_ROOT ${PROJECT_DIR}/../..) + +idf_component_register( + SRCS "${srcs}" + INCLUDE_DIRS ${includes} + PRIV_INCLUDE_DIRS + ${MP_ROOT} # micropython/ + ${MP_ROOT}/py # micropython/py + ${PROJECT_DIR} # micropython/ports/esp32 + ${MICROPY_BOARD_DIR} # board headers (mpconfigboard.h) + ${CMAKE_CURRENT_LIST_DIR}/.. + ${BUILD_DIR} + REQUIRES ${IDF_COMPONENTS} +) diff --git a/components/driver_sndmixer/driver_i2s.c b/components/driver_sndmixer/driver_i2s.c index 30c2017..44a80bd 100644 --- a/components/driver_sndmixer/driver_i2s.c +++ b/components/driver_sndmixer/driver_i2s.c @@ -1,154 +1,161 @@ #include #include +#include #include "driver_i2s.h" #ifdef CONFIG_DRIVER_SNDMIXER_ENABLE #ifdef CONFIG_DRIVER_SNDMIXER_DEBUG -int min_val=0, max_val=0; +int min_val = 0, max_val = 0; #endif struct Config { - uint8_t volume; + uint8_t volume; } config; -static QueueHandle_t soundQueue; static int soundRunning = 0; #ifdef CONFIG_DRIVER_SNDMIXER_I2S_PORT1 -static const i2s_port_t g_i2s_port = 1; +static const i2s_port_t g_i2s_port = I2S_NUM_1; #else -static const i2s_port_t g_i2s_port = 0; +static const i2s_port_t g_i2s_port = I2S_NUM_0; #endif -void driver_i2s_sound_start() { - config.volume = 255; +static i2s_chan_handle_t tx_chan = NULL; - int rate = CONFIG_DRIVER_SNDMIXER_SAMPLE_RATE; - int buffsize = CONFIG_DRIVER_SNDMIXER_BUFFZIE; +void driver_i2s_sound_start(void) { + if (soundRunning) return; + + config.volume = 255; - i2s_config_t cfg = { -#ifdef CONFIG_DRIVER_SNDMIXER_I2S_DAC_INTERNAL - .mode = I2S_MODE_TX | I2S_MODE_MASTER | I2S_MODE_DAC_BUILT_IN, -#else - .mode = I2S_MODE_TX | I2S_MODE_MASTER, -#endif - .sample_rate = rate, - .bits_per_sample = CONFIG_DRIVER_SNDMIXER_BITS_PER_SAMPLE, + int rate = CONFIG_DRIVER_SNDMIXER_SAMPLE_RATE; + + // 1) Create TX channel + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(g_i2s_port, I2S_ROLE_MASTER); + + ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_chan, NULL)); + + // 2) Configure standard I2S mode (Philips) + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(rate), + .slot_cfg = { + .data_bit_width = CONFIG_DRIVER_SNDMIXER_BITS_PER_SAMPLE, + .slot_bit_width = CONFIG_DRIVER_SNDMIXER_BITS_PER_SAMPLE, #if defined(CONFIG_DRIVER_SNDMIXER_I2S_CHANNEL_FORMAT_OR) - .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, + .slot_mode = I2S_SLOT_MODE_MONO, #elif defined(CONFIG_DRIVER_SNDMIXER_I2S_CHANNEL_FORMAT_OL) - .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .slot_mode = I2S_SLOT_MODE_MONO, #elif defined(CONFIG_DRIVER_SNDMIXER_I2S_CHANNEL_FORMAT_AL) - .channel_format = I2S_CHANNEL_FMT_ALL_LEFT, + .slot_mode = I2S_SLOT_MODE_STEREO, #elif defined(CONFIG_DRIVER_SNDMIXER_I2S_CHANNEL_FORMAT_AR) - .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT, -#else - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, -#endif -#ifdef CONFIG_DRIVER_SNDMIXER_I2S_DAC_INTERNAL - .communication_format = I2S_COMM_FORMAT_I2S_MSB, -#elif defined(CONFIG_DRIVER_SNDMIXER_I2S_DAC_EXTERNAL_MSB) - .communication_format = I2S_COMM_FORMAT_I2S_MSB | I2S_COMM_FORMAT_I2S, -#elif defined(CONFIG_DRIVER_SNDMIXER_I2S_DAC_EXTERNAL_LSB) - .communication_format = I2S_COMM_FORMAT_I2S_LSB | I2S_COMM_FORMAT_I2S, -#else - .communication_format = I2S_COMM_FORMAT_I2S, -#endif - .intr_alloc_flags = 0, - .dma_buf_count = 4, - .dma_buf_len = buffsize / 4 - }; - - i2s_driver_install(g_i2s_port, &cfg, 4, &soundQueue); - i2s_set_sample_rates(g_i2s_port, cfg.sample_rate); -#ifdef CONFIG_DRIVER_SNDMIXER_I2S_DAC_INTERNAL - i2s_set_pin(g_i2s_port, NULL); -#ifdef CONFIG_DRIVER_SNDMIXER_I2S_INTERNAL_DAC_BOTH - i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); -#elif defined(CONFIG_DRIVER_SNDMIXER_I2S_INTERNAL_DAC_RIGHT) - i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN); -#elif defined(CONFIG_DRIVER_SNDMIXER_I2S_INTERNAL_DAC_LEFT) - i2s_set_dac_mode(I2S_DAC_CHANNEL_LEFT_EN); -#else - i2s_set_dac_mode(I2S_DAC_CHANNEL_DISABLE); -#endif + .slot_mode = I2S_SLOT_MODE_STEREO, #else - static const i2s_pin_config_t pin_config = {.bck_io_num = CONFIG_DRIVER_SNDMIXER_PIN_BCK, - .mck_io_num = CONFIG_DRIVER_SNDMIXER_PIN_MCK, - .ws_io_num = CONFIG_DRIVER_SNDMIXER_PIN_WS, - .data_out_num = CONFIG_DRIVER_SNDMIXER_PIN_DATA_OUT, - .data_in_num = I2S_PIN_NO_CHANGE}; - i2s_set_pin(g_i2s_port, &pin_config); + .slot_mode = I2S_SLOT_MODE_STEREO, #endif - soundRunning = 1; + .slot_mask = I2S_STD_SLOT_BOTH, + .ws_width = CONFIG_DRIVER_SNDMIXER_BITS_PER_SAMPLE, + .ws_pol = false, + .bit_shift = true, + .msb_right = true, + }, + .gpio_cfg = { + .mclk = CONFIG_DRIVER_SNDMIXER_PIN_MCK, + .bclk = CONFIG_DRIVER_SNDMIXER_PIN_BCK, + .ws = CONFIG_DRIVER_SNDMIXER_PIN_WS, + .dout = CONFIG_DRIVER_SNDMIXER_PIN_DATA_OUT, + .din = I2S_GPIO_UNUSED, + .invert_flags = { + .mclk_inv = false, + .bclk_inv = false, + .ws_inv = false, + }, + }, + }; + + ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &std_cfg)); + ESP_ERROR_CHECK(i2s_channel_enable(tx_chan)); + + soundRunning = 1; } -void driver_i2s_sound_stop() { - i2s_driver_uninstall(g_i2s_port); +void driver_i2s_sound_stop(void) { + if (!soundRunning) return; + if (tx_chan) { + i2s_channel_disable(tx_chan); + i2s_del_channel(tx_chan); + tx_chan = NULL; + } + soundRunning = 0; } #define SND_CHUNKSZ 32 void driver_i2s_sound_push(int16_t *buf, int len, int stereo_input) { - int16_t tmpb[SND_CHUNKSZ * 2]; - int i = 0; - while (i < len) { - int plen = len - i; - if (plen > SND_CHUNKSZ) { - plen = SND_CHUNKSZ; + if (!tx_chan || !soundRunning) { + return; } - for (int sample = 0; sample < plen; sample++) { - int32_t s[2] = {0, 0}; - if (stereo_input) { - s[0] = buf[(i + sample) * 2 + 0]; - s[1] = buf[(i + sample) * 2 + 1]; - } else { - s[0] = s[1] = buf[i + sample]; - } - - // Multiply with volume/volume_max, resulting in signed integers with range [INT16_MIN:INT16_MAX] - s[0] = (s[0] * config.volume / 255); - s[1] = (s[1] * config.volume / 255); + + int16_t tmpb[SND_CHUNKSZ * 2]; + int i = 0; + while (i < len) { + int plen = len - i; + if (plen > SND_CHUNKSZ) { + plen = SND_CHUNKSZ; + } + for (int sample = 0; sample < plen; sample++) { + int32_t s[2] = {0, 0}; + if (stereo_input) { + s[0] = buf[(i + sample) * 2 + 0]; + s[1] = buf[(i + sample) * 2 + 1]; + } else { + s[0] = s[1] = buf[i + sample]; + } + + s[0] = (s[0] * config.volume) / 255; + s[1] = (s[1] * config.volume) / 255; #ifdef CONFIG_DRIVER_SNDMIXER_I2S_DATA_FORMAT_UNSIGNED - // Offset to [0:UINT16_MAX] store as unsigned integers - s[0] -= INT16_MIN; - s[1] -= INT16_MIN; + s[0] -= INT16_MIN; + s[1] -= INT16_MIN; #endif - tmpb[(i + sample) * 2 + 0] = s[0]; - tmpb[(i + sample) * 2 + 1] = s[1]; + tmpb[(sample * 2) + 0] = (int16_t)s[0]; + tmpb[(sample * 2) + 1] = (int16_t)s[1]; #ifdef CONFIG_DRIVER_SNDMIXER_DEBUG - min_val = s[0] < min_val ? s[0] : min_val; - max_val = s[0] > max_val ? s[0] : max_val; - - if (i == 0 && sample == 0 && rand() < (RAND_MAX/100)) { - ESP_LOGW("Sndmixer","[global vol %d]: min %d max %d", config.volume, min_val, max_val); - } + min_val = s[0] < min_val ? s[0] : min_val; + max_val = s[0] > max_val ? s[0] : max_val; + if (i == 0 && sample == 0 && rand() < (RAND_MAX / 100)) { + ESP_LOGW("Sndmixer", "[global vol %d]: min %d max %d", config.volume, min_val, max_val); + } #endif + } + + size_t bytes_written = 0; + ESP_ERROR_CHECK(i2s_channel_write(tx_chan, + tmpb, + plen * 2 * sizeof(tmpb[0]), + &bytes_written, + portMAX_DELAY)); + i += plen; } - size_t bytes_written; - i2s_write(g_i2s_port, (char *)tmpb, plen * 2 * sizeof(tmpb[0]), &bytes_written, portMAX_DELAY); - i += plen; - } } void driver_i2s_set_volume(uint8_t new_volume) { - // xSemaphoreTake(configMux, portMAX_DELAY); - config.volume = new_volume; - // xSemaphoreGive(configMux); + config.volume = new_volume; } -uint8_t driver_i2s_get_volume() { - return config.volume; +uint8_t driver_i2s_get_volume(void) { + return config.volume; } void driver_i2s_sound_mute(int doMute) { - if (doMute) { - dac_i2s_disable(); - } else { - dac_i2s_enable(); - } + if (!tx_chan) { + return; + } + if (doMute) { + i2s_channel_disable(tx_chan); + } else { + i2s_channel_enable(tx_chan); + } } #endif diff --git a/components/driver_sndmixer/driver_i2s.h b/components/driver_sndmixer/driver_i2s.h index 938d4e9..1de15cd 100644 --- a/components/driver_sndmixer/driver_i2s.h +++ b/components/driver_sndmixer/driver_i2s.h @@ -4,14 +4,20 @@ #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" -#include "driver/i2s.h" +//#include "driver/i2s.h" +#include "driver/i2s_common.h" +#include "driver/i2s_etm.h" +#include "driver/i2s_pdm.h" +#include "driver/i2s_std.h" +#include "driver/i2s_tdm.h" +#include "driver/i2s_types.h" #include "esp_sleep.h" #include "nvs.h" #include "nvs_flash.h" #include "driver/gpio.h" -#include "driver/adc.h" -#include "driver/dac.h" +//#include "driver/adc.h" +//#include "driver/dac.h" #include "soc/rtc_cntl_reg.h" // Start audio output driver diff --git a/components/driver_sndmixer/ibxm/ibxm.h b/components/driver_sndmixer/ibxm/ibxm.h index 7e96f5a..59cda2d 100644 --- a/components/driver_sndmixer/ibxm/ibxm.h +++ b/components/driver_sndmixer/ibxm/ibxm.h @@ -6,7 +6,7 @@ //Set to 1 to output mono samples #define IBXM_MONO 1 -const char *IBXM_VERSION; +extern const char *IBXM_VERSION; struct data { char *buffer; diff --git a/components/driver_sndmixer/modsndmixer.c b/components/driver_sndmixer/modsndmixer.c index 4b9e3c1..edac4a4 100644 --- a/components/driver_sndmixer/modsndmixer.c +++ b/components/driver_sndmixer/modsndmixer.c @@ -145,7 +145,7 @@ static mp_obj_t modsndmixer_wav_stream(mp_obj_t _stream) { mp_raise_ValueError(msg_error_not_started); return mp_const_none; } - int id = sndmixer_queue_wav_stream(mp_stream_posix_read, mp_stream_posix_lseek, (void *)_stream); + int id = sndmixer_queue_wav_stream(mp_stream_posix_read, mp_stream_posix_lseek, _stream); // sndmixer_play(id); return mp_obj_new_int(id); } @@ -184,7 +184,7 @@ static mp_obj_t modsndmixer_mp3_stream(mp_obj_t _stream) { mp_raise_ValueError(msg_error_not_started); return mp_const_none; } - int id = sndmixer_queue_mp3_stream(mp_stream_posix_read, mp_stream_posix_lseek, (void *)_stream); + int id = sndmixer_queue_mp3_stream(mp_stream_posix_read, mp_stream_posix_lseek, _stream); // sndmixer_play(id); return mp_obj_new_int(id); } @@ -206,7 +206,7 @@ static mp_obj_t modsndmixer_opus_stream(mp_obj_t _stream) { mp_raise_ValueError(msg_error_not_started); return mp_const_none; } - int id = sndmixer_queue_opus_stream(mp_stream_posix_read, (void *)_stream); + int id = sndmixer_queue_opus_stream(mp_stream_posix_read, _stream); // sndmixer_play(id); return mp_obj_new_int(id); } @@ -335,3 +335,4 @@ const mp_obj_module_t sndmixer_module = { .base = {&mp_type_module}, .globals = (mp_obj_dict_t *)&sndmixer_module_globals, }; +MP_REGISTER_MODULE(MP_QSTR_sndmixer, sndmixer_module); diff --git a/components/driver_sndmixer/snd_source_mod.c b/components/driver_sndmixer/snd_source_mod.c index b3c04ac..40ac9cc 100644 --- a/components/driver_sndmixer/snd_source_mod.c +++ b/components/driver_sndmixer/snd_source_mod.c @@ -5,6 +5,8 @@ #include #include "snd_source_mod.h" +#include "board_kconfig.h" + #ifdef CONFIG_DRIVER_SNDMIXER_ENABLE typedef struct { @@ -14,8 +16,8 @@ typedef struct { } mod_ctx_t; int mod_init_source(const void *data_start, const void *data_end, int req_sample_rate, void **ctx, - int *stereo) { - mod_ctx_t *mod = calloc(sizeof(mod_ctx_t), 1); + int *stereo, stream_seek_type seek_func) { + mod_ctx_t *mod = calloc(1, sizeof(mod_ctx_t)); if (!mod) return -1; char error[64]; diff --git a/components/driver_sndmixer/snd_source_mp3.c b/components/driver_sndmixer/snd_source_mp3.c index 4b16440..e719bcd 100644 --- a/components/driver_sndmixer/snd_source_mp3.c +++ b/components/driver_sndmixer/snd_source_mp3.c @@ -67,7 +67,7 @@ void _readData(mp3_ctx_t *mp3) { // printf("_readData: %d, %d, %d\n", dataAvailable, bufferAvailable, amountFetched); } -int IRAM_ATTR mp3_decode(void *ctx) { +int mp3_decode(void *ctx) { mp3_ctx_t *mp3 = (mp3_ctx_t *)ctx; if (mp3->stream) @@ -107,7 +107,7 @@ int IRAM_ATTR mp3_decode(void *ctx) { } } -int IRAM_ATTR mp3_init_source(const void *data_start, const void *data_end, int req_sample_rate, void **ctx, +int mp3_init_source(const void *data_start, const void *data_end, int req_sample_rate, void **ctx, int *stereo) { // Allocate space for the information struct mp3_ctx_t *mp3 = calloc(sizeof(mp3_ctx_t), 1); @@ -156,8 +156,14 @@ int IRAM_ATTR mp3_init_source(const void *data_start, const void *data_end, int return -1; } -int IRAM_ATTR mp3_init_source_stream(const void *stream_read_fn, const void *stream, int req_sample_rate, - void **ctx, int *stereo, const void *seek_func) { +int mp3_init_source_stream( + stream_read_type stream_read_fn, + void *stream, + int req_sample_rate, + void **ctx, + int *stereo, + stream_seek_type seek_func +) { // Allocate space for the information struct mp3_ctx_t *mp3 = calloc(sizeof(mp3_ctx_t), 1); if (!mp3) { @@ -218,12 +224,12 @@ int IRAM_ATTR mp3_init_source_stream(const void *stream_read_fn, const void *str return -1; } -int IRAM_ATTR mp3_get_sample_rate(void *ctx) { +int mp3_get_sample_rate(void *ctx) { mp3_ctx_t *mp3 = (mp3_ctx_t *)ctx; return mp3->lastRate; } -int IRAM_ATTR mp3_fill_buffer(void *ctx, int16_t *buffer, int stereo) { +int mp3_fill_buffer(void *ctx, int16_t *buffer, int stereo) { mp3_ctx_t *mp3 = (mp3_ctx_t *)ctx; if (mp3->bufferValid <= 0) mp3_decode(ctx); @@ -274,16 +280,20 @@ int mp3_stream_reset_buffer(void *ctx) { } -const sndmixer_source_t sndmixer_source_mp3 = {.init_source = mp3_init_source, - .get_sample_rate = mp3_get_sample_rate, - .fill_buffer = mp3_fill_buffer, - .reset_buffer = mp3_reset_buffer, - .deinit_source = mp3_deinit_source}; - -const sndmixer_source_t sndmixer_source_mp3_stream = {.init_source = mp3_init_source_stream, - .get_sample_rate = mp3_get_sample_rate, - .fill_buffer = mp3_fill_buffer, - .reset_buffer = mp3_stream_reset_buffer, - .deinit_source = mp3_deinit_source}; +const sndmixer_source_t sndmixer_source_mp3 = { + .init_source = mp3_init_source, + .get_sample_rate = mp3_get_sample_rate, + .fill_buffer = mp3_fill_buffer, + .reset_buffer = mp3_reset_buffer, + .deinit_source = mp3_deinit_source +}; + +const sndmixer_source_t sndmixer_source_mp3_stream = { + .init_source_stream = mp3_init_source_stream, + .get_sample_rate = mp3_get_sample_rate, + .fill_buffer = mp3_fill_buffer, + .reset_buffer = mp3_stream_reset_buffer, + .deinit_source = mp3_deinit_source +}; #endif diff --git a/components/driver_sndmixer/snd_source_opus.c b/components/driver_sndmixer/snd_source_opus.c index 4ec712d..d590db3 100644 --- a/components/driver_sndmixer/snd_source_opus.c +++ b/components/driver_sndmixer/snd_source_opus.c @@ -12,6 +12,8 @@ #include "sndmixer.h" #include "opus.h" +#include "board_kconfig.h" + #ifdef CONFIG_DRIVER_SNDMIXER_ENABLE #define INPUT_BUFFER_SIZE (2 * 1024) @@ -102,9 +104,9 @@ static int IRAM_ATTR ctx_decode(void *_ctx) { } int IRAM_ATTR opus_init_source(const void *data_start, const void *data_end, int req_sample_rate, void **_ctx, - int *stereo) { + int *stereo, stream_seek_type seek_func) { // Allocate space for the information struct - opus_ctx_t *ctx = calloc(sizeof(opus_ctx_t), 1); + opus_ctx_t *ctx = calloc(1, sizeof(opus_ctx_t)); if (!ctx) goto err; @@ -144,7 +146,7 @@ int IRAM_ATTR opus_init_source(const void *data_start, const void *data_end, int } int IRAM_ATTR opus_init_source_stream(const void *stream_read_fn, const void *stream, int req_sample_rate, - void **_ctx, int *stereo) { + void **_ctx, int *stereo, stream_seek_type seek_func) { // Allocate space for the information struct opus_ctx_t *ctx = heap_caps_calloc(sizeof(opus_ctx_t), 1, MALLOC_CAP_DMA); if (!ctx) diff --git a/components/driver_sndmixer/snd_source_synth.c b/components/driver_sndmixer/snd_source_synth.c index c8e0266..3ec28cf 100644 --- a/components/driver_sndmixer/snd_source_synth.c +++ b/components/driver_sndmixer/snd_source_synth.c @@ -11,6 +11,8 @@ #include "sndmixer.h" +#include "board_kconfig.h" + #ifdef CONFIG_DRIVER_SNDMIXER_ENABLE #define CHUNK_SIZE 32 @@ -108,8 +110,8 @@ const uint8_t noise[] = { 0x72, 0xe5, 0x6f, 0x3e, 0x79, 0xa6, 0xbc, 0x6f, 0x67, 0x8f, 0xe5, 0xc8, 0x7a, 0x6c, 0xde, 0x8e}; int IRAM_ATTR synth_init_source(const void *data_start, const void *data_end, int req_sample_rate, void **ctx, - int *stereo) { - synth_ctx_t *synth = calloc(sizeof(synth_ctx_t), 1); + int *stereo, stream_seek_type seek_func) { + synth_ctx_t *synth = calloc(1, sizeof(synth_ctx_t)); if (!synth) return -1; diff --git a/components/driver_sndmixer/snd_source_wav.c b/components/driver_sndmixer/snd_source_wav.c index 8ebd61c..f6a5668 100644 --- a/components/driver_sndmixer/snd_source_wav.c +++ b/components/driver_sndmixer/snd_source_wav.c @@ -17,7 +17,7 @@ typedef struct { const uint8_t *data; // Pointer to internal buffer (if applicable) - uint32_t pos; + ssize_t pos; uint32_t data_len; uint32_t rate; uint16_t channels, bits; @@ -25,7 +25,7 @@ typedef struct { stream_read_type stream_read; stream_seek_type seek_func; void *stream; // Pointer to stream - uint32_t data_start_offset; + off_t data_start_offset; } wav_ctx_t; typedef struct __attribute__((packed)) { @@ -56,11 +56,11 @@ typedef struct __attribute__((packed)) { }; } chunk_hdr_t; -int IRAM_ATTR wav_init_source(const void *data_start, const void *data_end, int req_sample_rate, void **ctx, +int wav_init_source(const void *data_start, const void *data_end, int req_sample_rate, void **ctx, int *stereo) { // Check sanity first char *p = (char *)data_start; - wav_ctx_t *wav = heap_caps_calloc(sizeof(wav_ctx_t), 1, MALLOC_CAP_DMA); + wav_ctx_t *wav = calloc(1, sizeof(wav_ctx_t)); if (!wav) goto err; riff_hdr_t *riff = (riff_hdr_t *)p; @@ -104,10 +104,16 @@ int IRAM_ATTR wav_init_source(const void *data_start, const void *data_end, int return -1; } -int IRAM_ATTR wav_init_source_stream(void *stream_read_fn, void *stream, int req_sample_rate, - void **ctx, int *stereo, void *seek_func) { +int wav_init_source_stream( + stream_read_type stream_read_fn, + void *stream, + int req_sample_rate, + void **ctx, + int *stereo, + stream_seek_type seek_func +) { ESP_LOGI(TAG, "init wav"); - wav_ctx_t *wav = heap_caps_calloc(sizeof(wav_ctx_t), 1, MALLOC_CAP_DMA); + wav_ctx_t *wav = calloc(1, sizeof(wav_ctx_t)); if (!wav) { ESP_LOGE(TAG, "Failed to allocate wave file context"); return -1; @@ -117,7 +123,7 @@ int IRAM_ATTR wav_init_source_stream(void *stream_read_fn, void *stream, int req wav->seek_func = seek_func; wav->stream = stream; - ESP_LOGI(TAG, "header @ %d", wav->seek_func(wav->stream, 0, SEEK_CUR)); + ESP_LOGI(TAG, "header @ %ld", wav->seek_func(wav->stream, 0, SEEK_CUR)); riff_hdr_t *riffHdr = calloc(1, sizeof(riff_hdr_t)); int read = wav->stream_read(wav->stream, riffHdr, sizeof(riff_hdr_t)); if (read < 7) { @@ -134,7 +140,7 @@ int IRAM_ATTR wav_init_source_stream(void *stream_read_fn, void *stream, int req return -1; } - ESP_LOGI(TAG, "fmt @ %d", wav->seek_func(wav->stream, 0, SEEK_CUR)); + ESP_LOGI(TAG, "fmt @ %ld", wav->seek_func(wav->stream, 0, SEEK_CUR)); chunk_hdr_t chunk; wav->stream_read(wav->stream, &chunk, 4 + 4); @@ -144,7 +150,7 @@ int IRAM_ATTR wav_init_source_stream(void *stream_read_fn, void *stream, int req } ESP_LOGI(TAG, "fmt size %d", chunk.size); - ESP_LOGI(TAG, "fmt body @ %d", wav->seek_func(wav->stream, 0, SEEK_CUR)); + ESP_LOGI(TAG, "fmt body @ %ld", wav->seek_func(wav->stream, 0, SEEK_CUR)); fmt_data_t format; wav->stream_read(wav->stream, &format, chunk.size); if (format.fmtcode != WAVE_FORMAT_PCM) { @@ -160,7 +166,7 @@ int IRAM_ATTR wav_init_source_stream(void *stream_read_fn, void *stream, int req ESP_LOGI(TAG, "channels: %d, bits: %d, rate: %d", wav->channels, wav->bits, wav->rate); - ESP_LOGI(TAG, "data @ %d", wav->seek_func(wav->stream, 0, SEEK_CUR)); + ESP_LOGI(TAG, "data @ %ld", wav->seek_func(wav->stream, 0, SEEK_CUR)); wav->stream_read(wav->stream, &chunk, 4 + 4); if (memcmp(chunk.magic, "data", 4) != 0){ ESP_LOGW(TAG, "WAV file does not contain data chunk after format chunk"); @@ -170,7 +176,7 @@ int IRAM_ATTR wav_init_source_stream(void *stream_read_fn, void *stream, int req ESP_LOGI(TAG, "seek"); wav->data_start_offset = wav->seek_func(wav->stream, 0, SEEK_CUR); wav->data_len = chunk.size; - ESP_LOGI(TAG, "WAV data offset: %d", wav->data_start_offset); + ESP_LOGI(TAG, "WAV data offset: %ld", wav->data_start_offset); wav->pos = 0; *ctx = (void *)wav; @@ -178,7 +184,7 @@ int IRAM_ATTR wav_init_source_stream(void *stream_read_fn, void *stream, int req return CHUNK_SIZE; } -int IRAM_ATTR wav_get_sample_rate(void *ctx) { +int wav_get_sample_rate(void *ctx) { wav_ctx_t *wav = (wav_ctx_t *)ctx; return wav->rate; } @@ -195,7 +201,7 @@ uint8_t get_sample_byte(wav_ctx_t *wav) { return rv; } -int16_t IRAM_ATTR get_sample(wav_ctx_t *wav) { +int16_t get_sample(wav_ctx_t *wav) { int16_t rv = 0; if (wav->bits == 8) { rv = (get_sample_byte(wav) - 128) << 8; @@ -205,7 +211,7 @@ int16_t IRAM_ATTR get_sample(wav_ctx_t *wav) { return rv; } -int IRAM_ATTR wav_fill_buffer(void *ctx, int16_t *buffer, int stereo) { +int wav_fill_buffer(void *ctx, int16_t *buffer, int stereo) { wav_ctx_t *wav = (wav_ctx_t *)ctx; int channels = 1; if (wav->channels == 2 && stereo) { @@ -213,9 +219,9 @@ int IRAM_ATTR wav_fill_buffer(void *ctx, int16_t *buffer, int stereo) { } if(wav->stream && stereo && wav->bits == 16 && wav->channels <= 2) { // Optimisation: if we're streaming a 1 or 2-channel 16 bit file, we can directly copy its contents - int read = wav->stream_read(wav->stream, buffer, CHUNK_SIZE * sizeof(uint16_t) * wav->channels); + ssize_t read = wav->stream_read(wav->stream, buffer, CHUNK_SIZE * sizeof(uint16_t) * wav->channels); wav->pos += read; - return read / (2 * 2); + return read / (sizeof(uint16_t) * wav->channels); } for (int i = 0; i < CHUNK_SIZE; i++) { if (wav->pos >= wav->data_len) @@ -253,16 +259,20 @@ void wav_deinit_source(void *ctx) { free(wav); } -const sndmixer_source_t sndmixer_source_wav = {.init_source = wav_init_source, - .get_sample_rate = wav_get_sample_rate, - .fill_buffer = wav_fill_buffer, - .reset_buffer = wav_reset_buffer, - .deinit_source = wav_deinit_source}; - -const sndmixer_source_t sndmixer_source_wav_stream = {.init_source = wav_init_source_stream, +const sndmixer_source_t sndmixer_source_wav = { + .init_source = wav_init_source, .get_sample_rate = wav_get_sample_rate, .fill_buffer = wav_fill_buffer, - .reset_buffer = wav_stream_reset_buffer, - .deinit_source = wav_deinit_source}; + .reset_buffer = wav_reset_buffer, + .deinit_source = wav_deinit_source +}; + +const sndmixer_source_t sndmixer_source_wav_stream = { + .init_source_stream = wav_init_source_stream, + .get_sample_rate = wav_get_sample_rate, + .fill_buffer = wav_fill_buffer, + .reset_buffer = wav_stream_reset_buffer, + .deinit_source = wav_deinit_source +}; #endif diff --git a/components/driver_sndmixer/sndmixer.c b/components/driver_sndmixer/sndmixer.c index 09dc9a8..f6b1efb 100644 --- a/components/driver_sndmixer/sndmixer.c +++ b/components/driver_sndmixer/sndmixer.c @@ -62,7 +62,7 @@ typedef struct { const void *queue_file_start; const void *queue_file_end; const void *read_func; - const void *stream; + void *stream; const void *seek_func; const void *callback_func; const void *callback_handle; @@ -105,33 +105,37 @@ static uint8_t beat_sync_bpm = 120; // Preconfigured BPM. Can be configured with // Grabs a new ID by atomically increasing curr_id and returning its value. This is called outside // of the audio playing thread, hence the atomicity. -static uint32_t new_id() { - uint32_t old_id, new_id; - do { - old_id = curr_id; - new_id = old_id + 1; - // compares curr_id with old_id, sets to new_id if same, returns old val in new_id - uxPortCompareSet(&curr_id, old_id, &new_id); - } while (new_id != old_id); - return old_id + 1; +static uint32_t new_id(void) { + uint32_t old_id = __atomic_load_n(&curr_id, __ATOMIC_SEQ_CST); + uint32_t new_id; + while (1) { + new_id = old_id + 1; + if (__atomic_compare_exchange_n(&curr_id, &old_id, new_id, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST)) { + return new_id; + } + // on failure, old_id is updated; loop and try again + } } -static void clean_up_channel(int ch) { - if(channel[ch].callback_handle) { +static void clean_up_channel(sndmixer_channel_t *chan) { + if(chan->callback_handle) { // exec callback - callback_type do_callback = channel[ch].callback_func; - do_callback(channel[ch].callback_handle,0,0); + callback_type do_callback = chan->callback_func; + do_callback(chan->callback_handle,0); } - if (channel[ch].source) { - channel[ch].source->deinit_source(channel[ch].src_ctx); - channel[ch].source = NULL; + if (chan->source) { + chan->source->deinit_source(chan->src_ctx); + chan->source = NULL; } - free(channel[ch].buffer); - channel[ch].buffer = NULL; - channel[ch].flags = 0; - ESP_LOGI(TAG, "Sndmixer: %d: cleaning up done", channel[ch].id); - channel[ch].id = 0; + free(chan->buffer); + chan->buffer = NULL; + chan->flags = 0; + ESP_LOGI(TAG, "Sndmixer: %d: cleaning up done", chan->id); + chan->id = 0; } static int find_free_channel() { @@ -142,7 +146,7 @@ static int find_free_channel() { // No free channels. Maybe one is evictable? for (int x = 0; x < no_channels; x++) { if (channel[x].flags & CHFL_EVICTABLE) { - clean_up_channel(x); + clean_up_channel(channel + x); return x; } } @@ -150,7 +154,7 @@ static int find_free_channel() { } static int init_source(int* chan_id, const sndmixer_source_t *srcfns, const void *data_start, - const void *data_end, const void *seek_func) { + const void *data_end) { int ch = find_free_channel(); *chan_id = ch; if (ch < 0) { @@ -159,14 +163,47 @@ static int init_source(int* chan_id, const sndmixer_source_t *srcfns, const void ESP_LOGI(TAG, "Sndmixer: %d: initialising source\n", ch); int stereo = 0; int chunksz = - srcfns->init_source(data_start, data_end, samplerate, &channel[ch].src_ctx, &stereo, seek_func); + srcfns->init_source(data_start, data_end, samplerate, &channel[ch].src_ctx, &stereo); if (chunksz <= 0) return 0; // failed channel[ch].source = srcfns; channel[ch].volume = 255; channel[ch].buffer = malloc(chunksz * sizeof(channel[ch].buffer[0]) * ((stereo && use_stereo) ? 2 : 1)); if (!channel[ch].buffer) { - clean_up_channel(ch); + clean_up_channel(channel + ch); + return 0; + } + channel[ch].chunksz = chunksz; + int64_t real_rate = srcfns->get_sample_rate(channel[ch].src_ctx); + channel[ch].dds_rate = (real_rate << 16) / samplerate; + channel[ch].dds_acc = chunksz << 16; // to force the main thread to get new data + channel[ch].flags = 0; + if (stereo && use_stereo) { + ESP_LOGI(TAG, "Starting stereo channel"); + channel[ch].flags |= CHFL_STEREO; + } + return 1; +} + +static int init_source_stream(int* chan_id, const sndmixer_source_t *srcfns, const stream_read_type read_fn, void *stream, stream_seek_type seek_func) { + int ch = find_free_channel(); + *chan_id = ch; + if (ch < 0) { + return 0; // no free channels + } + ESP_LOGI(TAG, "Sndmixer: %d: initialising source\n", ch); + int stereo = 0; + int chunksz = + srcfns->init_source_stream(read_fn, stream, samplerate, &channel[ch].src_ctx, &stereo, seek_func); + if (chunksz <= 0) + return 0; // failed + channel[ch].source = srcfns; + channel[ch].volume = 255; + int msize = chunksz * sizeof(channel[ch].buffer[0]) * ((stereo && use_stereo) ? 2 : 1); + channel[ch].buffer = malloc(msize); + ESP_LOGI(TAG, "init_source_stream: chunksz %d, msize %d, stereo: %d, use_stereo: %d, buffer = %p", chunksz, msize, stereo, use_stereo, channel[ch].buffer); + if (!channel[ch].buffer) { + clean_up_channel(channel + ch); return 0; } channel[ch].chunksz = chunksz; @@ -189,28 +226,28 @@ static void handle_cmd(sndmixer_cmd_t *cmd) { // Global initialisation commands that are not bound to a single channel switch(cmd->cmd) { case CMD_QUEUE_WAV: - cmd_success = init_source(&chan_id, &sndmixer_source_wav, cmd->queue_file_start, cmd->queue_file_end, 0); + cmd_success = init_source(&chan_id, &sndmixer_source_wav, cmd->queue_file_start, cmd->queue_file_end); break; case CMD_QUEUE_WAV_STREAM: - cmd_success = init_source(&chan_id, &sndmixer_source_wav_stream, cmd->read_func, cmd->stream, cmd->seek_func); + cmd_success = init_source_stream(&chan_id, &sndmixer_source_wav_stream, cmd->read_func, cmd->stream, cmd->seek_func); break; case CMD_QUEUE_MOD: - cmd_success = init_source(&chan_id, &sndmixer_source_mod, cmd->queue_file_start, cmd->queue_file_end, 0); + cmd_success = init_source(&chan_id, &sndmixer_source_mod, cmd->queue_file_start, cmd->queue_file_end); break; case CMD_QUEUE_MP3: - cmd_success = init_source(&chan_id, &sndmixer_source_mp3, cmd->queue_file_start, cmd->queue_file_end, 0); + cmd_success = init_source(&chan_id, &sndmixer_source_mp3, cmd->queue_file_start, cmd->queue_file_end); break; case CMD_QUEUE_MP3_STREAM: - cmd_success = init_source(&chan_id, &sndmixer_source_mp3_stream, cmd->read_func, cmd->stream, cmd->seek_func); + cmd_success = init_source_stream(&chan_id, &sndmixer_source_mp3_stream, cmd->read_func, cmd->stream, cmd->seek_func); break; case CMD_QUEUE_OPUS: - cmd_success = init_source(&chan_id, &sndmixer_source_opus, cmd->queue_file_start, cmd->queue_file_end, 0); + cmd_success = init_source(&chan_id, &sndmixer_source_opus, cmd->queue_file_start, cmd->queue_file_end); break; case CMD_QUEUE_OPUS_STREAM: - cmd_success = init_source(&chan_id, &sndmixer_source_opus_stream, cmd->read_func, cmd->stream, 0); + cmd_success = init_source_stream(&chan_id, &sndmixer_source_opus_stream, cmd->read_func, cmd->stream, cmd->seek_func); break; case CMD_QUEUE_SYNTH: - cmd_success = init_source(&chan_id, &sndmixer_source_synth, 0, 0, 0); + cmd_success = init_source(&chan_id, &sndmixer_source_synth, 0, 0); break; default: cmd_found = false; @@ -291,7 +328,7 @@ static void handle_cmd(sndmixer_cmd_t *cmd) { break; case CMD_STOP: ESP_LOGI(TAG, "%d: cleaning up source due to external stop request", cmd->id); - clean_up_channel(chan_id); + clean_up_channel(channel + chan_id); break; case CMD_FREQ: if (channel[chan_id].source->set_frequency) { @@ -322,7 +359,7 @@ static void handle_cmd(sndmixer_cmd_t *cmd) { #define CHUNK_SIZE 32 // Sound mixer main loop. -IRAM_ATTR static void sndmixer_task(void *arg) { +static void sndmixer_task(void *arg) { int16_t mixbuf[CHUNK_SIZE * (use_stereo ? 2 : 1)]; ESP_LOGI(TAG, "Sndmixer task up.\n"); @@ -377,7 +414,7 @@ IRAM_ATTR static void sndmixer_task(void *arg) { ESP_LOGI(TAG, "Looping sample"); if (chan->source->reset_buffer(chan->src_ctx) < 0) { ESP_LOGE(TAG, "%d: cleaning up source, loop failed", chan->id); - clean_up_channel(ch); + clean_up_channel(chan); break; } else { r = chan->source->fill_buffer(chan->src_ctx, chan->buffer, use_stereo); @@ -385,16 +422,18 @@ IRAM_ATTR static void sndmixer_task(void *arg) { } else { // Source is done and no loops are requested ESP_LOGI(TAG, "%d: cleaning up source because of EOF", chan->id); - clean_up_channel(ch); + clean_up_channel(chan); break; } continue; } + if (chan->source) { int64_t real_rate = chan->source->get_sample_rate(chan->src_ctx); chan->dds_rate = (real_rate << 16) / samplerate; chan->dds_acc -= (chan->chunksz << 16); // reset dds acc; we have parsed chunksize samples. chan->chunksz = r; // save new chunksize + } else { ESP_LOGE(TAG, "chan->source is NULL"); } } if (!chan->source) { continue; diff --git a/components/driver_sndmixer/sndmixer.h b/components/driver_sndmixer/sndmixer.h index 8770807..0cfc694 100644 --- a/components/driver_sndmixer/sndmixer.h +++ b/components/driver_sndmixer/sndmixer.h @@ -1,5 +1,6 @@ #pragma once #include +#include "py/obj.h" #ifdef __cplusplus extern "C" { @@ -9,15 +10,19 @@ extern "C" { #define SEEK_CUR 1 #define SEEK_END 2 +typedef ssize_t (*stream_read_type)(void *, void *, size_t); +typedef off_t (*stream_seek_type)(void *, off_t, int); + /** * @brief Structure describing a sound source */ typedef struct { /*! Initialize the sound source. Returns size of data returned per call of fill_buffer. */ int (*init_source)(const void *data_start, const void *data_end, int req_sample_rate, void **ctx, - int *stereo, const void *seek_func); - - /*! Get the actual sample rate at which the source returns data */ + int *stereo); + int (*init_source_stream)(stream_read_type stream_read_fn, mp_obj_t stream, int req_sample_rate, + void **ctx, int *stereo, stream_seek_type seek_func); + /*! Get the actual sample rate at which the source returns data */ int (*get_sample_rate)(void *ctx); /*! Decode a bufferful of data. Returns 0 when file ended or something went wrong. Returns amount * of bytes in buffer (normally what init_source returned) otherwise. */ @@ -32,9 +37,6 @@ typedef struct { void (*set_waveform)(void *ctx, uint8_t waveform); } sndmixer_source_t; -typedef ssize_t (*stream_read_type)(void *, void *, size_t); -typedef ssize_t (*stream_seek_type)(void *, size_t, size_t); - /** * @brief Initialize the sound mixer * @@ -153,7 +155,7 @@ int sndmixer_queue_synth(); void sndmixer_freq(int id, uint16_t frequency); void sndmixer_waveform(int id, uint8_t waveform); -typedef ssize_t (*callback_type)(void *, size_t, size_t); +typedef _Bool (*callback_type)(void *, void *); /** * @brief Set a callback function to execute after the sample has finished diff --git a/components/libopus/silk/fixed/encode_frame_FIX.c b/components/libopus/silk/fixed/encode_frame_FIX.c index a02bf87..060e9bf 100644 --- a/components/libopus/silk/fixed/encode_frame_FIX.c +++ b/components/libopus/silk/fixed/encode_frame_FIX.c @@ -34,6 +34,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "stack_alloc.h" #include "tuning_parameters.h" +#pragma GCC diagnostic ignored "-Wstringop-overread" + /* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ static OPUS_INLINE void silk_LBRR_encode_FIX( silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ diff --git a/components/micropython/CMakeLists.txt b/components/micropython/CMakeLists.txt index f162cc1..d426a85 100644 --- a/components/micropython/CMakeLists.txt +++ b/components/micropython/CMakeLists.txt @@ -1,259 +1,8 @@ -get_filename_component(MICROPY_DIR ${PROJECT_DIR}/components/micropython/micropython ABSOLUTE) -get_filename_component(MICROPY_PORT_DIR ${PROJECT_DIR}/components/micropython/micropython/ports/esp32 ABSOLUTE) -set(MICROPY_FROZEN_MANIFEST ${PROJECT_DIR}/manifests/${CONFIG_MICROPY_FROZEN_MANIFEST}) - -# Include core source components. -include(${MICROPY_DIR}/py/py.cmake) - -if(NOT CMAKE_BUILD_EARLY_EXPANSION) - include(${MICROPY_DIR}/py/usermod.cmake) - include(${MICROPY_DIR}/extmod/extmod.cmake) - - list(REMOVE_ITEM MICROPY_SOURCE_EXTMOD - ${MICROPY_EXTMOD_DIR}/vfs.c - ${MICROPY_EXTMOD_DIR}/vfs_blockdev.c - ${MICROPY_EXTMOD_DIR}/vfs_fat.c - ${MICROPY_EXTMOD_DIR}/vfs_fat_diskio.c - ${MICROPY_EXTMOD_DIR}/vfs_fat_file.c - ${MICROPY_EXTMOD_DIR}/vfs_lfs.c - ${MICROPY_EXTMOD_DIR}/vfs_posix.c - ${MICROPY_EXTMOD_DIR}/vfs_posix_file.c - ${MICROPY_EXTMOD_DIR}/vfs_reader.c - ) - - list(APPEND MICROPY_SOURCE_EXTMOD - ${COMPONENT_DIR}/vfs_fat/vfs_native_file.c - ${COMPONENT_DIR}/vfs_fat/vfs_native_misc.c - ${COMPONENT_DIR}/vfs_fat/vfs_native.c - ${COMPONENT_DIR}/vfs_fat/vfs_reader.c - ${COMPONENT_DIR}/vfs_fat/vfs.c - ) -endif() - -set(MICROPY_QSTRDEFS_PORT - ${MICROPY_PORT_DIR}/qstrdefsport.h -) - -set(MICROPY_SOURCE_SHARED - ${MICROPY_DIR}/shared/readline/readline.c - ${MICROPY_DIR}/shared/netutils/netutils.c - ${MICROPY_DIR}/shared/timeutils/timeutils.c - ${MICROPY_DIR}/shared/runtime/interrupt_char.c - ${MICROPY_DIR}/shared/runtime/stdout_helpers.c - ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c - ${MICROPY_DIR}/shared/runtime/pyexec.c -) - -set(MICROPY_SOURCE_LIB - ${MICROPY_DIR}/lib/littlefs/lfs1.c - ${MICROPY_DIR}/lib/littlefs/lfs1_util.c - ${MICROPY_DIR}/lib/littlefs/lfs2.c - ${MICROPY_DIR}/lib/littlefs/lfs2_util.c - ${MICROPY_DIR}/lib/mbedtls_errors/mp_mbedtls_errors.c - # ${MICROPY_DIR}/lib/oofatfs/ff.c - # ${MICROPY_DIR}/lib/oofatfs/ffunicode.c -) -if(IDF_TARGET STREQUAL "esp32c3") - list(APPEND MICROPY_SOURCE_LIB ${MICROPY_DIR}/shared/runtime/gchelper_generic.c) -endif() - -set(MICROPY_SOURCE_DRIVERS - ${MICROPY_DIR}/drivers/bus/softspi.c - ${MICROPY_DIR}/drivers/dht/dht.c -) - -set(MICROPY_SOURCE_PORT - ${COMPONENT_DIR}/main.c - ${COMPONENT_DIR}/modconsts.c - ${MICROPY_PORT_DIR}/main.c - ${MICROPY_PORT_DIR}/uart.c - ${MICROPY_PORT_DIR}/usb.c - ${MICROPY_PORT_DIR}/usb_serial_jtag.c - ${MICROPY_PORT_DIR}/gccollect.c - ${MICROPY_PORT_DIR}/mphalport.c - #${MICROPY_PORT_DIR}/fatfs_port.c - ${MICROPY_PORT_DIR}/help.c - ${MICROPY_PORT_DIR}/modutime.c - #${MICROPY_PORT_DIR}/moduos.c - ${COMPONENT_DIR}/vfs_fat/moduos.c - ${MICROPY_PORT_DIR}/machine_bitstream.c - ${MICROPY_PORT_DIR}/machine_timer.c - ${MICROPY_PORT_DIR}/machine_pin.c - ${MICROPY_PORT_DIR}/machine_touchpad.c - ${MICROPY_PORT_DIR}/machine_adc.c - ${MICROPY_PORT_DIR}/machine_dac.c - ${COMPONENT_DIR}/esp32/machine_i2c.c - ${MICROPY_PORT_DIR}/machine_i2s.c - ${MICROPY_PORT_DIR}/machine_uart.c - ${MICROPY_PORT_DIR}/modmachine.c - ${MICROPY_PORT_DIR}/modnetwork.c - ${MICROPY_PORT_DIR}/network_lan.c - ${MICROPY_PORT_DIR}/network_ppp.c - ${MICROPY_PORT_DIR}/network_wlan.c - ${MICROPY_PORT_DIR}/mpnimbleport.c - ${MICROPY_PORT_DIR}/modsocket.c - ${MICROPY_PORT_DIR}/modesp.c - ${MICROPY_PORT_DIR}/esp32_nvs.c - ${MICROPY_PORT_DIR}/esp32_partition.c - ${MICROPY_PORT_DIR}/esp32_rmt.c - ${MICROPY_PORT_DIR}/esp32_ulp.c - ${MICROPY_PORT_DIR}/modesp32.c - ${COMPONENT_DIR}/esp32/machine_hw_spi.c - ${MICROPY_PORT_DIR}/machine_wdt.c - ${MICROPY_PORT_DIR}/mpthreadport.c - ${MICROPY_PORT_DIR}/machine_rtc.c - #${MICROPY_PORT_DIR}/machine_sdcard.c -) - -set(MICROPY_SOURCE_QSTR - ${MICROPY_SOURCE_PY} - ${MICROPY_SOURCE_EXTMOD} - ${MICROPY_SOURCE_USERMOD} - ${MICROPY_SOURCE_SHARED} - ${MICROPY_SOURCE_LIB} - ${MICROPY_SOURCE_PORT} - ${MICROPY_SOURCE_BOARD} - ${COMPONENT_DIR}/modconsts.c - ${EXTMODS} - ${COMPONENT_DIR}/mpconfigoverrides.h -) - -set(IDF_COMPONENTS - app_update - bootloader_support - bt - driver - esp_common - esp_eth - esp_event - esp_ringbuf - esp_rom - esp_wifi - freertos - heap - log - lwip - mbedtls - mdns - newlib - nvs_flash - sdmmc - soc - spi_flash - tcpip_adapter - ulp - vfs - xtensa - fatfs - wear_levelling - spiffs - driver_sdcard - buses - wpa_supplicant -) - -if(IDF_VERSION_MINOR GREATER_EQUAL 1 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) - list(APPEND IDF_COMPONENTS esp_netif) -endif() - -if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) - list(APPEND IDF_COMPONENTS esp_system) - list(APPEND IDF_COMPONENTS esp_timer) -endif() - -if(IDF_VERSION_MINOR GREATER_EQUAL 3 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) - list(APPEND IDF_COMPONENTS esp_hw_support) - list(APPEND IDF_COMPONENTS esp_pm) - list(APPEND IDF_COMPONENTS hal) -endif() - -if(IDF_TARGET STREQUAL "esp32") - list(APPEND IDF_COMPONENTS esp32) -elseif(IDF_TARGET STREQUAL "esp32c3") - list(APPEND IDF_COMPONENTS esp32c3) - list(APPEND IDF_COMPONENTS riscv) -elseif(IDF_TARGET STREQUAL "esp32s2") - list(APPEND IDF_COMPONENTS esp32s2) - list(APPEND IDF_COMPONENTS tinyusb) -elseif(IDF_TARGET STREQUAL "esp32s3") - list(APPEND IDF_COMPONENTS esp32s3) - list(APPEND IDF_COMPONENTS tinyusb) -endif() - -# Register the main IDF component. idf_component_register( - SRCS - ${MICROPY_SOURCE_PY} - ${MICROPY_SOURCE_EXTMOD} - ${MICROPY_SOURCE_SHARED} - ${MICROPY_SOURCE_LIB} - ${MICROPY_SOURCE_DRIVERS} - ${MICROPY_SOURCE_PORT} - ${MICROPY_SOURCE_BOARD} - INCLUDE_DIRS - ${MICROPY_INC_CORE} - ${MICROPY_INC_USERMOD} - ${MICROPY_PORT_DIR} - ${MICROPY_BOARD_DIR} - ${CMAKE_BINARY_DIR} - "./" - "vfs_fat/" - REQUIRES - ${IDF_COMPONENTS} -) - -add_custom_command( - OUTPUT - ${COMPONENT_DIR}/mpconfigoverrides.h - COMMAND echo extmods: ${EXTMODS} && - python3 mpconfigover_generator.py -b ./ \"${EXTMODS_NAMES}\" && - cp patches/ports/esp32/mpconfigport.h micropython/ports/esp32 && - cp patches/ports/esp32/help.c micropython/ports/esp32 && - cp patches/mpy-cross/main.c micropython/mpy-cross && - cp patches/py/stackctrl.c micropython/py - WORKING_DIRECTORY ${COMPONENT_DIR} - DEPENDS ${EXTMODS} -) - -# Set the MicroPython target as the current (main) IDF component target. -set(MICROPY_TARGET ${COMPONENT_TARGET}) - -# Define mpy-cross flags, for use with frozen code. -set(MICROPY_CROSS_FLAGS -march=xtensawin) - -# Set compile options for this port. -target_compile_definitions(${MICROPY_TARGET} PUBLIC - ${MICROPY_DEF_CORE} - MICROPY_ESP_IDF_4=1 -) - -# Disable some warnings to keep the build output clean. -target_compile_options(${MICROPY_TARGET} PUBLIC - -Wno-clobbered - -Wno-deprecated-declarations - -Wno-missing-field-initializers + SRCS "" + INCLUDE_DIRS "" + PRIV_INCLUDE_DIRS + ${CMAKE_CURRENT_LIST_DIR}/../../.. + ${CMAKE_CURRENT_LIST_DIR}/../../../py + ${CMAKE_CURRENT_LIST_DIR}/../../.. ) - -# Add additional extmod and usermod components. -target_link_libraries(${MICROPY_TARGET} micropy_extmod_btree) -target_link_libraries(${MICROPY_TARGET} usermod) - - -# Collect all of the include directories and compile definitions for the IDF components. -foreach(comp ${IDF_COMPONENTS}) - micropy_gather_target_properties(__idf_${comp}) -endforeach() - -if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5) - # These paths cannot currently be found by the IDF_COMPONENTS search loop above, - # so add them explicitly. - list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/${IDF_TARGET}/include) - list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/include) - if(IDF_VERSION_MINOR GREATER_EQUAL 3) - list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/additions/include) - list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/tinyusb/src) - endif() -endif() - -# Include the main MicroPython cmake rules. -include(${MICROPY_DIR}/py/mkrules.cmake) diff --git a/components/pynvs/CMakeLists.txt b/components/pynvs/CMakeLists.txt index b1e0c24..cefadbd 100644 --- a/components/pynvs/CMakeLists.txt +++ b/components/pynvs/CMakeLists.txt @@ -1,6 +1,26 @@ set(srcs "modnvs.c") set(includes ".") -idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS ${includes} - REQUIRES lwip micropython) +# Compute the MicroPython root relative to this component +set(MP_ROOT ${PROJECT_DIR}/../..) + +set(IDF_COMPONENTS + nvs_flash + esp_driver_gpio + esp_driver_spi + esp_mm + micropython +) + +idf_component_register( + SRCS "${srcs}" + INCLUDE_DIRS ${includes} + PRIV_INCLUDE_DIRS + ${MP_ROOT} # micropython/ + ${MP_ROOT}/py # micropython/py + ${PROJECT_DIR} # micropython/ports/esp32 + ${MICROPY_BOARD_DIR} # board headers (mpconfigboard.h) + ${CMAKE_CURRENT_LIST_DIR}/.. + ${BUILD_DIR} + REQUIRES ${IDF_COMPONENTS} +) diff --git a/components/pynvs/modnvs.c b/components/pynvs/modnvs.c index 6aa3c6b..34f9c8e 100644 --- a/components/pynvs/modnvs.c +++ b/components/pynvs/modnvs.c @@ -9,6 +9,8 @@ #include "nvs_flash.h" #include "nvs.h" +#define STATIC static + esp_err_t driver_nvs_init() { return ESP_OK; } //------------------------------------------------------------------------ @@ -143,7 +145,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_machine_nvs_set_int_obj, mod_machine_nvs_se STATIC mp_obj_t mod_machine_nvs_get_int (mp_obj_t _handle, mp_obj_t _key) { const char *handle = mp_obj_str_get_str(_handle); const char *key = mp_obj_str_get_str(_key); - int value = 0; + int32_t value = 0; nvs_handle my_handle; esp_err_t res = nvs_open(handle, NVS_READWRITE, &my_handle); @@ -277,3 +279,4 @@ const mp_obj_module_t nvs_module = { .base = {&mp_type_module}, .globals = (mp_obj_dict_t *)&nvs_module_globals, }; +MP_REGISTER_MODULE(MP_QSTR_nvs, nvs_module); diff --git a/python_modules/common/audio.py b/python_modules/common/audio.py index d96ef94..e639d3c 100644 --- a/python_modules/common/audio.py +++ b/python_modules/common/audio.py @@ -3,7 +3,6 @@ _no_channels = 4 # We can't play more than this number of channels concurrently without glitches _started = False -handles = {} def _start_audio_if_needed(): global _started @@ -11,34 +10,24 @@ def _start_audio_if_needed(): sndmixer.begin(_no_channels) _started = True -def _clean_channel(channel_id): - global handles - if channel_id in handles: - file = handles[channel_id] - if file is not None: - file.close() - del handles[channel_id] def _add_channel(filename, on_finished=None): - global handles - stream = True try: file = open(filename, 'rb') except: return -1 lower = filename.lower() if(lower.endswith('.mp3')): - channel_id = sndmixer.mp3_stream(file) + channel_id = sndmixer.mp3(file.read()) elif(lower.endswith('.wav')): - channel_id = sndmixer.wav_stream(file) + channel_id = sndmixer.wav(file.read()) elif(lower.endswith('.ogg') or lower.endswith('.opus')): - channel_id = sndmixer.opus_stream(file) # No support for looping yet + channel_id = sndmixer.opus(file.read()) # No support for looping yet elif(lower.endswith('.mod') or lower.endswith('.s3m') or lower.endswith('.xm')): channel_id = sndmixer.mod(file.read()) # No support for streaming mod files or looping yet - stream = False else: print('Audio: unknown filetype') channel_id = -1 @@ -47,16 +36,13 @@ def _add_channel(filename, on_finished=None): return -1 def finish_callback(_): - _clean_channel(channel_id) if on_finished is not None: try: on_finished() except: pass - handles[channel_id] = file - if stream: - sndmixer.on_finished(channel_id, finish_callback) + file.close() return channel_id def play(filename, volume=None, loop=False, sync_beat=None, start_at_next=None, on_finished=None): diff --git a/python_modules/common/system.py b/python_modules/common/system.py index 753e291..cab52ab 100644 --- a/python_modules/common/system.py +++ b/python_modules/common/system.py @@ -1,87 +1,87 @@ -import machine, time, os, term -import _device as device -import rtcmem - -def reboot(): - device.prepareForSleep() - machine.deepsleep(1) - -def sleep(duration=0, status=False): - if not device.configureWakeupSource(): - print("No wakeup source available, rebooting...") - reboot() - return - if (duration >= 86400000): #One day - duration = 0 - if status: - if duration < 1: - term.header(True, "Sleeping until a touch button is pressed!") - else: - term.header(True, "Sleeping for "+str(duration)+"ms...") - device.prepareForSleep() - machine.deepsleep(duration) - -def start(app, status=False): - """ - if status: - if app == "" or app == "launcher": - term.header(True, "Loading menu...") - else: - term.header(True, "Loading application "+app+"...") - device.showLoadingScreen(app) - """ - rtcmem.write_string(app) - reboot() - -def home(status=False): - start("", status) - -def launcher(status=False): - start("dashboard.launcher", status) - -def shell(status=False): - start("shell", status) - -# Over-the-air updating - -def ota(status=False): - """ - if status: - term.header(True, "Starting update...") - device.showLoadingScreen("OTA update") - """ - rtcmem.write(0,1) # Boot mode selection magic - rtcmem.write(1,254) - reboot() - -def eraseStorage(): - rtcmem.write(0,2) - rtcmem.write(1,253) - reboot() - -def serialWarning(): - device.showMessage("This app can only be controlled using the USB serial port!", "/media/usb.png") - -def crashedWarning(): - device.showMessage("FATAL ERROR\nthe app has crashed", "/media/alert.png") - -def isColdBoot(): - if machine.wake_reason() == (7, 0): - return True - return False - -def isWakeup(fromTimer=True, fromExt0=True, fromExt1=True, fromUlp=True): - if fromExt0 and machine.wake_reason() == (3, 1): - return True - if fromExt1 and machine.wake_reason() == (3, 2): - return True - if fromTimer and machine.wake_reason() == (3, 4): - return True - if fromUlp and machine.wake_reason() == (3, 5): - return True - return False - -__current_app__ = None - -def currentApp(): - return __current_app__ +import machine, time, os, term +import _device as device +import rtcmem + +def reboot(): + device.prepareForSleep() + machine.deepsleep(1) + +def sleep(duration=0, status=False): + if not device.configureWakeupSource(): + print("No wakeup source available, rebooting...") + reboot() + return + if (duration >= 86400000): #One day + duration = 0 + if status: + if duration < 1: + term.header(True, "Sleeping until a touch button is pressed!") + else: + term.header(True, "Sleeping for "+str(duration)+"ms...") + device.prepareForSleep() + machine.deepsleep(duration) + +def start(app, status=False): + """ + if status: + if app == "" or app == "launcher": + term.header(True, "Loading menu...") + else: + term.header(True, "Loading application "+app+"...") + device.showLoadingScreen(app) + """ + rtcmem.write_string(app) + reboot() + +def home(status=False): + start("", status) + +def launcher(status=False): + start("dashboard.launcher", status) + +def shell(status=False): + start("shell", status) + +# Over-the-air updating + +def ota(status=False): + """ + if status: + term.header(True, "Starting update...") + device.showLoadingScreen("OTA update") + """ + rtcmem.write(0,1) # Boot mode selection magic + rtcmem.write(1,254) + reboot() + +def eraseStorage(): + rtcmem.write(0,2) + rtcmem.write(1,253) + reboot() + +def serialWarning(): + device.showMessage("This app can only be controlled using the USB serial port!", "/media/usb.png") + +def crashedWarning(): + device.showMessage("FATAL ERROR\nthe app has crashed", "/media/alert.png") + +def isColdBoot(): + if machine.wake_reason() == (7, 0): + return True + return False + +def isWakeup(fromTimer=True, fromExt0=True, fromExt1=True, fromUlp=True): + if fromExt0 and machine.wake_reason() == (3, 1): + return True + if fromExt1 and machine.wake_reason() == (3, 2): + return True + if fromTimer and machine.wake_reason() == (3, 4): + return True + if fromUlp and machine.wake_reason() == (3, 5): + return True + return False + +__current_app__ = None + +def currentApp(): + return __current_app__ diff --git a/python_modules/mch2022/hardware/__init__.py b/python_modules/mch2022/hardware/__init__.py index 890ea24..5c1cbfe 100644 --- a/python_modules/mch2022/hardware/__init__.py +++ b/python_modules/mch2022/hardware/__init__.py @@ -1,5 +1,6 @@ from machine import Pin -import sdcard +from machine import SDCard +import uos PIN_SDPOWER = 19 PIN_NEOPIXEL = 5 @@ -17,4 +18,5 @@ def disable_power(): def mountsd(): enable_power() - sdcard.mountsd() \ No newline at end of file + sd = SDCard() + uos.mount(sd, "/sd") From d23d28ae0319dd747adaff9fce84c31a845cc561 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 12 Apr 2026 02:16:06 +0200 Subject: [PATCH 2/8] Remove esp-idf submodule --- .gitmodules | 3 --- esp-idf | 1 - 2 files changed, 4 deletions(-) delete mode 160000 esp-idf diff --git a/.gitmodules b/.gitmodules index 3c0dab6..2f32154 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "firmware/components/micropython/micropython"] path = components/micropython/micropython url = https://github.com/micropython/micropython.git -[submodule "esp-idf"] - path = esp-idf - url = https://github.com/espressif/esp-idf.git [submodule "firmware/python_modules/micropython-lib"] path = python_modules/micropython-lib url = https://github.com/micropython/micropython-lib diff --git a/esp-idf b/esp-idf deleted file mode 160000 index 3cec3a0..0000000 --- a/esp-idf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3cec3a0026098d1b027f2103ec154a15baf97318 From cb7517cb5f5f3b46c2d467b23811cde207961bf3 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 12 Apr 2026 02:16:33 +0200 Subject: [PATCH 3/8] Add sdk download function from new projects to Makefile --- .gitignore | 3 +++ Makefile | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index f0742c8..7af0f2f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ sdkconfig sdkconfig.old partitions.csv sdkconfig.defaults +esp-idf +esp-idf-tools + diff --git a/Makefile b/Makefile index 6e8d40b..fa4e2cf 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,13 @@ PORT ?= /dev/ttyACM0 + +IDF_PATH ?= $(shell cat .IDF_PATH 2>/dev/null || echo `pwd`/esp-idf) +IDF_TOOLS_PATH ?= $(shell cat .IDF_TOOLS_PATH 2>/dev/null || echo `pwd`/esp-idf-tools) +IDF_BRANCH ?= v5.5.1 +IDF_EXPORT_QUIET ?= 1 +IDF_GITHUB_ASSETS ?= dl.espressif.com/github_assets +MAKEFLAGS += --silent + BUILDDIR ?= build -IDF_PATH ?= $(shell pwd)/esp-idf IDF_EXPORT_QUIET ?= 0 SHELL := /usr/bin/env bash @@ -8,9 +15,16 @@ SHELL := /usr/bin/env bash all: prepare build -prepare: +.PHONY: sdk +sdk: + if test -d "$(IDF_PATH)"; then echo -e "ESP-IDF target folder exists!\r\nPlease remove the folder or un-set the environment variable."; exit 1; fi + if test -d "$(IDF_TOOLS_PATH)"; then echo -e "ESP-IDF tools target folder exists!\r\nPlease remove the folder or un-set the environment variable."; exit 1; fi + git clone --recursive --branch "$(IDF_BRANCH)" https://github.com/espressif/esp-idf.git "$(IDF_PATH)" --depth=1 --shallow-submodules + cd "$(IDF_PATH)"; git submodule update --init --recursive + cd "$(IDF_PATH)"; bash install.sh all + +prepare: sdk git submodule update --init --recursive - cd esp-idf; bash install.sh; cd .. cd components/micropython/micropython/mpy-cross; make cp configs/default_defconfig sdkconfig cp partition_tables/default.csv partitions.csv From f28c5ad175df20003f8c2e4e8d59ce10671353e1 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 12 Apr 2026 02:16:57 +0200 Subject: [PATCH 4/8] Add env sourceable script for starting ESP-IDF shell --- env | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 env diff --git a/env b/env new file mode 100644 index 0000000..62f7ee3 --- /dev/null +++ b/env @@ -0,0 +1,7 @@ +export IDF_PATH=$(pwd)/esp-idf +export IDF_TOOLS_PATH=$(pwd)/esp-idf-tools + +echo "ESP-IDF: $IDF_PATH" +echo "TOOLS: $IDF_TOOLS_PATH" + +source esp-idf/export.sh \ No newline at end of file From 5abefa6250c0bd2cb16716115902bee615765bb6 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 12 Apr 2026 02:17:40 +0200 Subject: [PATCH 5/8] Ignore managed components folder & dependencies lock file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 7af0f2f..1deafbd 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ partitions.csv sdkconfig.defaults esp-idf esp-idf-tools +dependencies.lock +managed_components From e09074edfd18c87ab6d97fded6aa7ad5ceecb6d9 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 12 Apr 2026 02:18:01 +0200 Subject: [PATCH 6/8] Add badge-bsp as dependency to main --- main/idf_component.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 main/idf_component.yml diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..4842ca3 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + idf: ">=5.5.1" + badgeteam/badge-bsp: "^0.9.1" From bb16d2273cf436da52db33d3f796a3b41a3643d9 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 12 Apr 2026 02:18:28 +0200 Subject: [PATCH 7/8] Correct path to Python, remove non-existent include directory from launcher driver --- components/driver_framebuffer/CMakeLists.txt | 4 ++-- components/driver_launcher/CMakeLists.txt | 5 ----- components/driver_rtcmem/CMakeLists.txt | 3 +-- components/pynvs/CMakeLists.txt | 3 +-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/components/driver_framebuffer/CMakeLists.txt b/components/driver_framebuffer/CMakeLists.txt index ad82f97..c283187 100644 --- a/components/driver_framebuffer/CMakeLists.txt +++ b/components/driver_framebuffer/CMakeLists.txt @@ -71,6 +71,7 @@ set(IDF_COMPONENTS esp_partition esp_timer esp_mm + driver_badge_bsp ) set(includes @@ -78,8 +79,7 @@ set(includes "png" ) -# Compute the MicroPython root relative to this component -set(MP_ROOT ${PROJECT_DIR}/../..) +set(MP_ROOT ${PROJECT_DIR}/components/micropython/micropython) idf_component_register( SRCS "${srcs}" diff --git a/components/driver_launcher/CMakeLists.txt b/components/driver_launcher/CMakeLists.txt index b54ec3c..782e924 100644 --- a/components/driver_launcher/CMakeLists.txt +++ b/components/driver_launcher/CMakeLists.txt @@ -6,12 +6,7 @@ else() set(srcs "") endif() -set(include - "include" - ) - idf_component_register( SRCS "${srcs}" - INCLUDE_DIRS "${include}" REQUIRES micropython ) diff --git a/components/driver_rtcmem/CMakeLists.txt b/components/driver_rtcmem/CMakeLists.txt index e9d18a3..2ee0f7f 100644 --- a/components/driver_rtcmem/CMakeLists.txt +++ b/components/driver_rtcmem/CMakeLists.txt @@ -7,8 +7,7 @@ set(includes "include" ) -# Compute the MicroPython root relative to this component -set(MP_ROOT ${PROJECT_DIR}/../..) +set(MP_ROOT ${PROJECT_DIR}/components/micropython/micropython) set(IDF_COMPONENTS nvs_flash diff --git a/components/pynvs/CMakeLists.txt b/components/pynvs/CMakeLists.txt index cefadbd..c002689 100644 --- a/components/pynvs/CMakeLists.txt +++ b/components/pynvs/CMakeLists.txt @@ -1,8 +1,7 @@ set(srcs "modnvs.c") set(includes ".") -# Compute the MicroPython root relative to this component -set(MP_ROOT ${PROJECT_DIR}/../..) +set(MP_ROOT ${PROJECT_DIR}/components/micropython/micropython) set(IDF_COMPONENTS nvs_flash From ef9476d7ac24023d4b687d325ba77fd411480710 Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 12 Apr 2026 02:23:42 +0200 Subject: [PATCH 8/8] Update Micropython submodule to v1.28.0 --- components/micropython/micropython | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/micropython/micropython b/components/micropython/micropython index da4b38e..e0e9fbb 160000 --- a/components/micropython/micropython +++ b/components/micropython/micropython @@ -1 +1 @@ -Subproject commit da4b38e7562dfa451917f9d7f344a7f26de8c7bd +Subproject commit e0e9fbb17ed6fd06bb76e266ae554784c9c80804