diff --git a/lib/mp3 b/lib/mp3 index 7a5de1ad777e..aac02afd9f24 160000 --- a/lib/mp3 +++ b/lib/mp3 @@ -1 +1 @@ -Subproject commit 7a5de1ad777e95b0f4fab7bbd35678c7d319b1b5 +Subproject commit aac02afd9f24d2ee930f650156654ab9211a306a diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 9eed90b71af5..8fb21c953f4e 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -152,7 +152,8 @@ CFLAGS += \ -DESP_PLATFORM=1 \ -DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\" \ -DMBEDTLS_PADLOCK_FILE=\"ports/espressif/esp-idf/components/mbedtls/mbedtls/library/padlock.h\" \ - -DUNITY_INCLUDE_CONFIG_H -DWITH_POSIX + -DUNITY_INCLUDE_CONFIG_H -DWITH_POSIX \ + -DMP3DEC_GENERIC # Make our canary value match FreeRTOS's # This define is in FreeRTOS as tskSTACK_FILL_BYTE 0xa5U which we expand out to a full word. @@ -303,7 +304,9 @@ SRC_C += \ peripherals/i2c.c \ peripherals/$(IDF_TARGET)/pins.c +ifeq ($(CIRCUITPY_SSL),1) SRC_C += lib/mbedtls_config/crt_bundle.c +endif SRC_C += $(wildcard common-hal/espidf/*.c) diff --git a/ports/espressif/common-hal/audiobusio/I2SOut.c b/ports/espressif/common-hal/audiobusio/I2SOut.c index 59e8604fb7d7..54a4d243fd9a 100644 --- a/ports/espressif/common-hal/audiobusio/I2SOut.c +++ b/ports/espressif/common-hal/audiobusio/I2SOut.c @@ -53,7 +53,7 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, i2s_std_config_t i2s_config = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000), - .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), + .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), .gpio_cfg = { .mclk = main_clock != NULL ? main_clock->number : I2S_GPIO_UNUSED, .bclk = bit_clock->number, diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index 9ebf325b9798..cc7768758735 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -35,9 +35,14 @@ #include "shared-module/audiocore/__init__.h" -#define CIRCUITPY_BUFFER_COUNT 3 -#define CIRCUITPY_BUFFER_SIZE 1023 -#define CIRCUITPY_OUTPUT_SLOTS 2 +// The maximum DMA buffer size (in bytes) +#define I2S_DMA_BUFFER_MAX_SIZE 4092 +// The number of DMA buffers to allocate +#define CIRCUITPY_BUFFER_COUNT (3) +// The maximum DMA buffer size in frames (at stereo 16-bit) +#define CIRCUITPY_BUFFER_SIZE (I2S_DMA_BUFFER_MAX_SIZE / 4) +// The number of output channels is fixed at 2 +#define CIRCUITPY_OUTPUT_SLOTS (2) static void i2s_fill_buffer(i2s_t *self) { if (self->next_buffer_size == 0) { diff --git a/ports/espressif/common-hal/audiomp3/__init__.c b/ports/espressif/common-hal/audiomp3/__init__.c new file mode 100644 index 000000000000..994da3d21ad0 --- /dev/null +++ b/ports/espressif/common-hal/audiomp3/__init__.c @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "py/mpprint.h" +#include "esp_heap_caps.h" +#include "shared-module/audiomp3/__init__.h" +#include "supervisor/port_heap.h" + +void *mp3_alloc(size_t sz) { + void *ptr = heap_caps_malloc(sz, MALLOC_CAP_8BIT); + if (ptr) { + memset(ptr, 0, sz); + } + return ptr; +} + +void mp3_free(void *ptr) { + heap_caps_free(ptr); +} diff --git a/ports/espressif/common-hal/socketpool/Socket.c b/ports/espressif/common-hal/socketpool/Socket.c index 2e10735351d4..e45f2aa6290f 100644 --- a/ports/espressif/common-hal/socketpool/Socket.c +++ b/ports/espressif/common-hal/socketpool/Socket.c @@ -31,8 +31,10 @@ #include "py/mperrno.h" #include "py/runtime.h" #include "shared-bindings/socketpool/SocketPool.h" +#if CIRCUITPY_SSL #include "shared-bindings/ssl/SSLSocket.h" #include "shared-module/ssl/SSLSocket.h" +#endif #include "supervisor/port.h" #include "supervisor/shared/tick.h" #include "supervisor/workflow.h" @@ -362,12 +364,14 @@ size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self, } void socketpool_socket_close(socketpool_socket_obj_t *self) { + #if CIRCUITPY_SSL if (self->ssl_socket) { ssl_sslsocket_obj_t *ssl_socket = self->ssl_socket; self->ssl_socket = NULL; common_hal_ssl_sslsocket_close(ssl_socket); return; } + #endif self->connected = false; int fd = self->num; // Ignore bogus/closed sockets diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 1a97d1b6ded3..e85242dfd290 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -74,4 +74,11 @@ #define CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP (0) #endif +// Protect the background queue with a lock because both cores may modify it. +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +extern portMUX_TYPE background_task_mutex; +#define CALLBACK_CRITICAL_BEGIN (taskENTER_CRITICAL(&background_task_mutex)) +#define CALLBACK_CRITICAL_END (taskEXIT_CRITICAL(&background_task_mutex)) + #endif // MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 1b67a8db5830..445c5c69d6a4 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -22,7 +22,6 @@ CIRCUITPY_ANALOGBUFIO ?= 1 CIRCUITPY_AUDIOBUSIO ?= 1 CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0 CIRCUITPY_AUDIOIO ?= 0 -CIRCUITPY_AUDIOMP3 ?= 0 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_CANIO ?= 1 CIRCUITPY_COUNTIO ?= 1 @@ -143,12 +142,17 @@ endif ifeq ($(CIRCUITPY_ESP_FLASH_SIZE),4MB) CIRCUITPY_BITMAPFILTER ?= 0 OPTIMIZATION_FLAGS ?= -Os +# Until the 4MB C6 partition table is updated, disable mp3 on the 4MB C6 parts +ifeq ($(IDF_TARGET),esp32c6) +CIRCUITPY_AUDIOMP3 ?= 0 +endif endif -# No room for dualbank on boards with 2MB flash +# No room for dualbank or mp3 on boards with 2MB flash ifeq ($(CIRCUITPY_ESP_FLASH_SIZE),2MB) CIRCUITPY_BITMAPFILTER ?= 0 CIRCUITPY_DUALBANK = 0 +CIRCUITPY_AUDIOMP3 = 0 endif # Modules dependent on other modules @@ -178,3 +182,6 @@ USB_NUM_IN_ENDPOINTS = 5 # Usually lots of flash space available CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1 + +CIRCUITPY_AUDIOMP3 ?= 1 +CIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR ?= 1 diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 7aaf1332d782..da8d10afc147 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -522,3 +522,5 @@ extern void app_main(void); void app_main(void) { main(); } + +portMUX_TYPE background_task_mutex = portMUX_INITIALIZER_UNLOCKED; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 36af49a1a794..d01869e54426 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -782,7 +782,11 @@ SRC_MOD += $(addprefix lib/mp3/src/, \ subband.c \ trigtabs.c \ ) -$(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "py/misc.h" -D'MPDEC_ALLOCATOR(x)=m_malloc(x)' -D'MPDEC_FREE(x)=m_free(x)' +$(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "shared-module/audiomp3/__init__.h" -D'MPDEC_ALLOCATOR(x)=mp3_alloc(x)' -D'MPDEC_FREE(x)=mp3_free(x)' -fwrapv +ifeq ($(CIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR),1) +SRC_COMMON_HAL_ALL += \ + audiomp3/__init__.c +endif endif ifeq ($(CIRCUITPY_GIFIO),1) diff --git a/shared-bindings/audiomp3/MP3Decoder.c b/shared-bindings/audiomp3/MP3Decoder.c index 3cb1ac4a687b..18d17e1d2eed 100644 --- a/shared-bindings/audiomp3/MP3Decoder.c +++ b/shared-bindings/audiomp3/MP3Decoder.c @@ -94,7 +94,9 @@ STATIC mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_ar arg = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), arg, MP_ROM_QSTR(MP_QSTR_rb)); } - audiomp3_mp3file_obj_t *self = mp_obj_malloc(audiomp3_mp3file_obj_t, &audiomp3_mp3file_type); + audiomp3_mp3file_obj_t *self = m_new_obj_with_finaliser(audiomp3_mp3file_obj_t); + self->base.type = &audiomp3_mp3file_type; + if (!mp_obj_is_type(arg, &mp_type_fileio)) { mp_raise_TypeError(MP_ERROR_TEXT("file must be a file opened in byte mode")); } @@ -260,6 +262,7 @@ STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&audiomp3_mp3file_open_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiomp3_mp3file_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audiomp3_mp3file_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomp3_mp3file___exit___obj) }, diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c index 51cb37d91600..08349bde70ba 100644 --- a/shared-module/audiomp3/MP3Decoder.c +++ b/shared-module/audiomp3/MP3Decoder.c @@ -226,7 +226,7 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t *self, } void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, pyb_file_obj_t *file) { - background_callback_begin_critical_section(); + background_callback_prevent(); self->file = file; f_lseek(&self->file->fp, 0); @@ -244,7 +244,7 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, pyb_file memset(self->buffers[1], 0, MAX_BUFFER_LEN); MP3FrameInfo fi; bool result = mp3file_get_next_frame_info(self, &fi); - background_callback_end_critical_section(); + background_callback_allow(); if (!result) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Failed to parse MP3 file")); @@ -296,7 +296,7 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self, } // We don't reset the buffer index in case we're looping and we have an odd number of buffer // loads - background_callback_begin_critical_section(); + background_callback_prevent(); f_lseek(&self->file->fp, 0); self->inbuf_offset = self->inbuf_length; self->eof = 0; @@ -305,7 +305,7 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self, mp3file_update_inbuf_half(self); mp3file_skip_id3v2(self); mp3file_find_sync_word(self); - background_callback_end_critical_section(); + background_callback_allow(); } audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *self, diff --git a/shared-module/audiomp3/__init__.c b/shared-module/audiomp3/__init__.c index e69de29bb2d1..5141f4ab05b4 100644 --- a/shared-module/audiomp3/__init__.c +++ b/shared-module/audiomp3/__init__.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/mpconfig.h" +#include "py/misc.h" +#include "shared-module/audiomp3/__init__.h" + +MP_WEAK void *mp3_alloc(size_t sz) { + return m_malloc_maybe(sz); +} + +MP_WEAK void mp3_free(void *ptr) { + m_free(ptr); +} diff --git a/shared-module/audiomp3/__init__.h b/shared-module/audiomp3/__init__.h index e7b1f3aab534..6d8a8514ed24 100644 --- a/shared-module/audiomp3/__init__.h +++ b/shared-module/audiomp3/__init__.h @@ -24,7 +24,9 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H -#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H +#pragma once -#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H +#include + +extern void *mp3_alloc(size_t sz); +extern void mp3_free(void *ptr); diff --git a/supervisor/background_callback.h b/supervisor/background_callback.h index 36b0017f0cae..4be62c081eb2 100644 --- a/supervisor/background_callback.h +++ b/supervisor/background_callback.h @@ -89,8 +89,8 @@ void background_callback_reset(void); * bracket the section of code where this is the case. These calls nest, and * begins must be balanced with ends. */ -void background_callback_begin_critical_section(void); -void background_callback_end_critical_section(void); +void background_callback_prevent(void); +void background_callback_allow(void); /* * Background callbacks may stop objects from being collected diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index 776435ac5570..a8c0f071faf9 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -76,18 +76,19 @@ inline bool background_callback_pending(void) { return callback_head != NULL; } -static bool in_background_callback; +static int background_prevention_count; + void PLACE_IN_ITCM(background_callback_run_all)() { port_background_task(); if (!background_callback_pending()) { return; } CALLBACK_CRITICAL_BEGIN; - if (in_background_callback) { + if (background_prevention_count) { CALLBACK_CRITICAL_END; return; } - in_background_callback = true; + ++background_prevention_count; background_callback_t *cb = (background_callback_t *)callback_head; callback_head = NULL; callback_tail = NULL; @@ -104,15 +105,19 @@ void PLACE_IN_ITCM(background_callback_run_all)() { CALLBACK_CRITICAL_BEGIN; cb = next; } - in_background_callback = false; + --background_prevention_count; CALLBACK_CRITICAL_END; } -void background_callback_begin_critical_section() { +void background_callback_prevent() { CALLBACK_CRITICAL_BEGIN; + ++background_prevention_count; + CALLBACK_CRITICAL_END; } -void background_callback_end_critical_section() { +void background_callback_allow() { + CALLBACK_CRITICAL_BEGIN; + --background_prevention_count; CALLBACK_CRITICAL_END; } @@ -146,7 +151,7 @@ void background_callback_reset() { } callback_head = new_head; callback_tail = new_tail; - in_background_callback = false; + background_prevention_count = 0; CALLBACK_CRITICAL_END; }