Merge branch 'main' into type_hints
This commit is contained in:
commit
9e3fa863f1
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get install -y eatmydata
|
sudo apt-get install -y eatmydata
|
||||||
sudo eatmydata apt-get install -y gettext librsvg2-bin mingw-w64
|
sudo eatmydata apt-get install -y gettext librsvg2-bin mingw-w64
|
||||||
pip install requests sh click setuptools cpp-coveralls "Sphinx<4" sphinx-rtd-theme recommonmark sphinx-autoapi sphinxcontrib-svg2pdfconverter polib pyyaml astroid
|
pip install requests sh click setuptools cpp-coveralls "Sphinx<4" sphinx-rtd-theme recommonmark sphinx-autoapi sphinxcontrib-svg2pdfconverter polib pyyaml astroid isort
|
||||||
- name: Versions
|
- name: Versions
|
||||||
run: |
|
run: |
|
||||||
gcc --version
|
gcc --version
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 0d2c083a2fb57a1562d4806775f45273abbfbfae
|
Subproject commit 9596a5904ed757e6fbffcf03e7aa77ae9ecf5223
|
7
main.c
7
main.c
@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
#include "background.h"
|
#include "background.h"
|
||||||
#include "mpconfigboard.h"
|
#include "mpconfigboard.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
#include "supervisor/cpu.h"
|
#include "supervisor/cpu.h"
|
||||||
#include "supervisor/memory.h"
|
#include "supervisor/memory.h"
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
@ -100,8 +101,6 @@ void start_mp(supervisor_allocation* heap) {
|
|||||||
reset_status_led();
|
reset_status_led();
|
||||||
autoreload_stop();
|
autoreload_stop();
|
||||||
|
|
||||||
background_tasks_reset();
|
|
||||||
|
|
||||||
// Stack limit should be less than real stack size, so we have a chance
|
// Stack limit should be less than real stack size, so we have a chance
|
||||||
// to recover from limit hit. (Limit is measured in bytes.)
|
// to recover from limit hit. (Limit is measured in bytes.)
|
||||||
mp_stack_ctrl_init();
|
mp_stack_ctrl_init();
|
||||||
@ -161,6 +160,8 @@ void stop_mp(void) {
|
|||||||
MP_STATE_VM(vfs_cur) = vfs;
|
MP_STATE_VM(vfs_cur) = vfs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
background_callback_reset();
|
||||||
|
|
||||||
gc_deinit();
|
gc_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,6 +493,8 @@ void gc_collect(void) {
|
|||||||
// have lost their references in the VM even though they are mounted.
|
// have lost their references in the VM even though they are mounted.
|
||||||
gc_collect_root((void**)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t));
|
gc_collect_root((void**)&MP_STATE_VM(vfs_mount_table), sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t));
|
||||||
|
|
||||||
|
background_callback_gc_collect();
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
#if CIRCUITPY_DISPLAYIO
|
||||||
displayio_gc_collect();
|
displayio_gc_collect();
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#include "shared-bindings/audiocore/RawSample.h"
|
#include "shared-bindings/audiocore/RawSample.h"
|
||||||
#include "shared-bindings/audiocore/WaveFile.h"
|
#include "shared-bindings/audiocore/WaveFile.h"
|
||||||
#include "supervisor/shared/tick.h"
|
#include "supervisor/background_callback.h"
|
||||||
|
|
||||||
#include "py/mpstate.h"
|
#include "py/mpstate.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
@ -61,7 +61,6 @@ void audio_dma_free_channel(uint8_t channel) {
|
|||||||
assert(audio_dma_allocated[channel]);
|
assert(audio_dma_allocated[channel]);
|
||||||
audio_dma_disable_channel(channel);
|
audio_dma_disable_channel(channel);
|
||||||
audio_dma_allocated[channel] = false;
|
audio_dma_allocated[channel] = false;
|
||||||
supervisor_disable_tick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_dma_disable_channel(uint8_t channel) {
|
void audio_dma_disable_channel(uint8_t channel) {
|
||||||
@ -73,7 +72,6 @@ void audio_dma_disable_channel(uint8_t channel) {
|
|||||||
void audio_dma_enable_channel(uint8_t channel) {
|
void audio_dma_enable_channel(uint8_t channel) {
|
||||||
if (channel >= AUDIO_DMA_CHANNEL_COUNT)
|
if (channel >= AUDIO_DMA_CHANNEL_COUNT)
|
||||||
return;
|
return;
|
||||||
supervisor_enable_tick();
|
|
||||||
dma_enable_channel(channel);
|
dma_enable_channel(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,6 +257,15 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
|
|||||||
dma->beat_size *= 2;
|
dma->beat_size *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SAM_D5X_E5X
|
||||||
|
int irq = dma->event_channel < 4 ? EVSYS_0_IRQn + dma->event_channel : EVSYS_4_IRQn;
|
||||||
|
#else
|
||||||
|
int irq = EVSYS_IRQn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NVIC_DisableIRQ(irq);
|
||||||
|
NVIC_ClearPendingIRQ(irq);
|
||||||
|
|
||||||
DmacDescriptor* first_descriptor = dma_descriptor(dma_channel);
|
DmacDescriptor* first_descriptor = dma_descriptor(dma_channel);
|
||||||
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
|
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
|
||||||
if (single_buffer) {
|
if (single_buffer) {
|
||||||
@ -281,6 +288,8 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
|
|||||||
dma_configure(dma_channel, dma_trigger_source, true);
|
dma_configure(dma_channel, dma_trigger_source, true);
|
||||||
audio_dma_enable_channel(dma_channel);
|
audio_dma_enable_channel(dma_channel);
|
||||||
|
|
||||||
|
NVIC_EnableIRQ(irq);
|
||||||
|
|
||||||
return AUDIO_DMA_OK;
|
return AUDIO_DMA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,9 +330,6 @@ void audio_dma_reset(void) {
|
|||||||
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
|
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
|
||||||
audio_dma_state[i] = NULL;
|
audio_dma_state[i] = NULL;
|
||||||
audio_dma_pending[i] = false;
|
audio_dma_pending[i] = false;
|
||||||
if (audio_dma_allocated[i]) {
|
|
||||||
supervisor_disable_tick();
|
|
||||||
}
|
|
||||||
audio_dma_allocated[i] = false;
|
audio_dma_allocated[i] = false;
|
||||||
audio_dma_disable_channel(i);
|
audio_dma_disable_channel(i);
|
||||||
dma_descriptor(i)->BTCTRL.bit.VALID = false;
|
dma_descriptor(i)->BTCTRL.bit.VALID = false;
|
||||||
@ -343,29 +349,39 @@ bool audio_dma_get_playing(audio_dma_t* dma) {
|
|||||||
return (status & DMAC_CHINTFLAG_TERR) == 0;
|
return (status & DMAC_CHINTFLAG_TERR) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARN(tannewt): DO NOT print from here. Printing calls background tasks such as this and causes a
|
// WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
|
||||||
// stack overflow.
|
// background tasks such as this and causes a stack overflow.
|
||||||
|
STATIC void dma_callback_fun(void *arg) {
|
||||||
void audio_dma_background(void) {
|
audio_dma_t* dma = arg;
|
||||||
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
|
if (dma == NULL) {
|
||||||
if (audio_dma_pending[i]) {
|
return;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audio_dma_load_next_block(dma);
|
||||||
|
}
|
||||||
|
|
||||||
|
void evsyshandler_common(void) {
|
||||||
|
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
|
||||||
audio_dma_t* dma = audio_dma_state[i];
|
audio_dma_t* dma = audio_dma_state[i];
|
||||||
if (dma == NULL) {
|
if (dma == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool block_done = event_interrupt_active(dma->event_channel);
|
bool block_done = event_interrupt_active(dma->event_channel);
|
||||||
if (!block_done) {
|
if (!block_done) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
background_callback_add(&dma->callback, dma_callback_fun, (void*)dma);
|
||||||
// audio_dma_load_next_block() can call Python code, which can call audio_dma_background()
|
|
||||||
// recursively at the next background processing time. So disallow recursive calls to here.
|
|
||||||
audio_dma_pending[i] = true;
|
|
||||||
audio_dma_load_next_block(dma);
|
|
||||||
audio_dma_pending[i] = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SAM_D5X_E5X
|
||||||
|
void EVSYS_0_Handler(void) { evsyshandler_common(); }
|
||||||
|
void EVSYS_1_Handler(void) { evsyshandler_common(); }
|
||||||
|
void EVSYS_2_Handler(void) { evsyshandler_common(); }
|
||||||
|
void EVSYS_3_Handler(void) { evsyshandler_common(); }
|
||||||
|
void EVSYS_4_Handler(void) { evsyshandler_common(); }
|
||||||
|
#else
|
||||||
|
void EVSYS_Handler(void) { evsyshandler_common(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "shared-module/audiocore/RawSample.h"
|
#include "shared-module/audiocore/RawSample.h"
|
||||||
#include "shared-module/audiocore/WaveFile.h"
|
#include "shared-module/audiocore/WaveFile.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_t sample;
|
mp_obj_t sample;
|
||||||
@ -49,6 +50,7 @@ typedef struct {
|
|||||||
uint8_t* second_buffer;
|
uint8_t* second_buffer;
|
||||||
bool first_descriptor_free;
|
bool first_descriptor_free;
|
||||||
DmacDescriptor* second_descriptor;
|
DmacDescriptor* second_descriptor;
|
||||||
|
background_callback_t callback;
|
||||||
} audio_dma_t;
|
} audio_dma_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -39,63 +39,21 @@
|
|||||||
#include "shared-module/displayio/__init__.h"
|
#include "shared-module/displayio/__init__.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
volatile uint64_t last_finished_tick = 0;
|
|
||||||
|
|
||||||
bool stack_ok_so_far = true;
|
|
||||||
|
|
||||||
static bool running_background_tasks = false;
|
|
||||||
|
|
||||||
#ifdef MONITOR_BACKGROUND_TASKS
|
#ifdef MONITOR_BACKGROUND_TASKS
|
||||||
// PB03 is physical pin "SCL" on the Metro M4 express
|
// PB03 is physical pin "SCL" on the Metro M4 express
|
||||||
// so you can't use this code AND an i2c peripheral
|
// so you can't use this code AND an i2c peripheral
|
||||||
// at the same time unless you change this
|
// at the same time unless you change this
|
||||||
STATIC void start_background_task(void) {
|
void port_start_background_task(void) {
|
||||||
REG_PORT_DIRSET1 = (1<<3);
|
REG_PORT_DIRSET1 = (1<<3);
|
||||||
REG_PORT_OUTSET1 = (1<<3);
|
REG_PORT_OUTSET1 = (1<<3);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void finish_background_task(void) {
|
void port_finish_background_task(void) {
|
||||||
REG_PORT_OUTCLR1 = (1<<3);
|
REG_PORT_OUTCLR1 = (1<<3);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
STATIC void start_background_task(void) {}
|
void port_start_background_task(void) {}
|
||||||
STATIC void finish_background_task(void) {}
|
void port_finish_background_task(void) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void background_tasks_reset(void) {
|
void port_background_task(void) {}
|
||||||
running_background_tasks = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_background_tasks(void) {
|
|
||||||
// Don't call ourselves recursively.
|
|
||||||
if (running_background_tasks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
start_background_task();
|
|
||||||
|
|
||||||
assert_heap_ok();
|
|
||||||
running_background_tasks = true;
|
|
||||||
|
|
||||||
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
|
|
||||||
audio_dma_background();
|
|
||||||
#endif
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
displayio_background();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_NETWORK
|
|
||||||
network_module_background();
|
|
||||||
#endif
|
|
||||||
filesystem_background();
|
|
||||||
usb_background();
|
|
||||||
running_background_tasks = false;
|
|
||||||
assert_heap_ok();
|
|
||||||
|
|
||||||
last_finished_tick = port_get_raw_ticks(NULL);
|
|
||||||
finish_background_task();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool background_tasks_ok(void) {
|
|
||||||
return port_get_raw_ticks(NULL) - last_finished_tick < 1024;
|
|
||||||
}
|
|
||||||
|
@ -29,9 +29,4 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
void background_tasks_reset(void);
|
|
||||||
void run_background_tasks(void);
|
|
||||||
void run_background_vm_tasks(void);
|
|
||||||
bool background_tasks_ok(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
|
#endif // MICROPY_INCLUDED_ATMEL_SAMD_BACKGROUND_H
|
||||||
|
@ -13,6 +13,4 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1
|
|||||||
EXTERNAL_FLASH_DEVICES = GD25Q16C
|
EXTERNAL_FLASH_DEVICES = GD25Q16C
|
||||||
LONGINT_IMPL = MPZ
|
LONGINT_IMPL = MPZ
|
||||||
|
|
||||||
CIRCUITPY_NETWORK = 1
|
|
||||||
MICROPY_PY_WIZNET5K = 5500
|
|
||||||
CIRCUITPY_PS2IO = 1
|
CIRCUITPY_PS2IO = 1
|
||||||
|
@ -11,6 +11,4 @@ EXTERNAL_FLASH_DEVICE_COUNT = 2
|
|||||||
EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, S25FL064L"
|
EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, S25FL064L"
|
||||||
LONGINT_IMPL = MPZ
|
LONGINT_IMPL = MPZ
|
||||||
|
|
||||||
CIRCUITPY_NETWORK = 1
|
|
||||||
MICROPY_PY_WIZNET5K = 5500
|
|
||||||
CIRCUITPY_PS2IO = 1
|
CIRCUITPY_PS2IO = 1
|
||||||
|
@ -13,7 +13,6 @@ LONGINT_IMPL = MPZ
|
|||||||
CIRCUITPY_AUDIOBUSIO = 0
|
CIRCUITPY_AUDIOBUSIO = 0
|
||||||
CIRCUITPY_FRAMEBUFFERIO = 0
|
CIRCUITPY_FRAMEBUFFERIO = 0
|
||||||
CIRCUITPY_DISPLAYIO = 0
|
CIRCUITPY_DISPLAYIO = 0
|
||||||
CIRCUITPY_NETWORK = 0
|
|
||||||
CIRCUITPY_RGBMATRIX = 0
|
CIRCUITPY_RGBMATRIX = 0
|
||||||
CIRCUITPY_PS2IO = 0
|
CIRCUITPY_PS2IO = 0
|
||||||
CIRCUITPY_AUDIOMP3 = 0
|
CIRCUITPY_AUDIOMP3 = 0
|
||||||
|
@ -10,38 +10,32 @@ INTERNAL_FLASH_FILESYSTEM = 1
|
|||||||
LONGINT_IMPL = NONE
|
LONGINT_IMPL = NONE
|
||||||
|
|
||||||
CIRCUITPY_FULL_BUILD = 0
|
CIRCUITPY_FULL_BUILD = 0
|
||||||
# TODO: Turn off analogio for now for space reasons, but restore it
|
|
||||||
# when frozen module gets smaller.
|
|
||||||
CIRCUITPY_ANALOGIO = 0
|
|
||||||
CIRCUITPY_AUDIOBUSIO = 0
|
CIRCUITPY_AUDIOBUSIO = 0
|
||||||
|
CIRCUITPY_AUDIOPWMIO = 0
|
||||||
|
CIRCUITPY_AUDIOMP3 = 0
|
||||||
CIRCUITPY_BITBANGIO = 0
|
CIRCUITPY_BITBANGIO = 0
|
||||||
|
CIRCUITPY_BITBANG_APA102 = 0
|
||||||
CIRCUITPY_FREQUENCYIO = 0
|
CIRCUITPY_FREQUENCYIO = 0
|
||||||
|
CIRCUITPY_GAMEPADSHIFT = 0
|
||||||
CIRCUITPY_I2CPERIPHERAL = 0
|
CIRCUITPY_I2CPERIPHERAL = 0
|
||||||
CIRCUITPY_NEOPIXEL_WRITE = 0
|
CIRCUITPY_NEOPIXEL_WRITE = 0
|
||||||
CIRCUITPY_NETWORK = 0
|
|
||||||
CIRCUITPY_PIXELBUF = 0
|
CIRCUITPY_PIXELBUF = 0
|
||||||
CIRCUITPY_PS2IO = 0
|
CIRCUITPY_PS2IO = 0
|
||||||
|
CIRCUITPY_ROTARYIO = 0
|
||||||
CIRCUITPY_RTC = 0
|
CIRCUITPY_RTC = 0
|
||||||
|
CIRCUITPY_SAMD = 0
|
||||||
CIRCUITPY_TOUCHIO = 0
|
CIRCUITPY_TOUCHIO = 0
|
||||||
CIRCUITPY_USB_HID = 0
|
CIRCUITPY_USB_HID = 0
|
||||||
CIRCUITPY_USB_MIDI = 0
|
CIRCUITPY_USB_MIDI = 0
|
||||||
CIRCUITPY_AUDIOPWMIO = 0
|
|
||||||
CIRCUITPY_AUDIOMP3 = 0
|
|
||||||
CIRCUITPY_BITBANG_APA102 = 0
|
|
||||||
CIRCUITPY_BLEIO = 0
|
|
||||||
CIRCUITPY_GAMEPADSHIFT = 0
|
|
||||||
CIRCUITPY_NETWORK = 0
|
|
||||||
CIRCUITPY_ROTARYIO = 0
|
|
||||||
CIRCUITPY_SAMD = 0
|
|
||||||
CIRCUITPY_TOUCHIO = 0
|
|
||||||
CIRCUITPY_VECTORIO = 0
|
CIRCUITPY_VECTORIO = 0
|
||||||
|
|
||||||
|
CIRCUITPY_ANALOGIO = 1
|
||||||
CIRCUITPY_AUDIOMIXER = 1
|
CIRCUITPY_AUDIOMIXER = 1
|
||||||
CIRCUITPY_AUDIOIO = 1
|
CIRCUITPY_AUDIOIO = 1
|
||||||
CIRCUITPY_DISPLAYIO = 1
|
CIRCUITPY_DISPLAYIO = 1
|
||||||
CIRCUITPY_GAMEPAD = 1
|
CIRCUITPY_GAMEPAD = 1
|
||||||
CIRCUITPY_STAGE = 1
|
|
||||||
CIRCUITPY_MATH = 1
|
CIRCUITPY_MATH = 1
|
||||||
|
CIRCUITPY_STAGE = 1
|
||||||
|
|
||||||
FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pewpew_m4
|
FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pewpew_m4
|
||||||
CIRCUITPY_DISPLAY_FONT = $(TOP)/ports/atmel-samd/boards/ugame10/brutalist-6.bdf
|
CIRCUITPY_DISPLAY_FONT = $(TOP)/ports/atmel-samd/boards/ugame10/brutalist-6.bdf
|
||||||
|
@ -12,6 +12,4 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1
|
|||||||
EXTERNAL_FLASH_DEVICES = AT25SF041A
|
EXTERNAL_FLASH_DEVICES = AT25SF041A
|
||||||
LONGINT_IMPL = MPZ
|
LONGINT_IMPL = MPZ
|
||||||
|
|
||||||
CIRCUITPY_NETWORK = 1
|
|
||||||
MICROPY_PY_WIZNET5K = 5500
|
|
||||||
CIRCUITPY_PS2IO = 1
|
CIRCUITPY_PS2IO = 1
|
||||||
|
@ -9,3 +9,10 @@ CHIP_FAMILY = samd21
|
|||||||
INTERNAL_FLASH_FILESYSTEM = 1
|
INTERNAL_FLASH_FILESYSTEM = 1
|
||||||
LONGINT_IMPL = NONE
|
LONGINT_IMPL = NONE
|
||||||
CIRCUITPY_FULL_BUILD = 0
|
CIRCUITPY_FULL_BUILD = 0
|
||||||
|
|
||||||
|
# Tweak inlining depending on language.
|
||||||
|
ifeq ($(TRANSLATION), zh_Latn_pinyin)
|
||||||
|
CFLAGS_INLINE_LIMIT = 45
|
||||||
|
else
|
||||||
|
CFLAGS_INLINE_LIMIT = 70
|
||||||
|
endif
|
||||||
|
@ -24,10 +24,13 @@ CIRCUITPY_BLEIO = 0
|
|||||||
CIRCUITPY_DISPLAYIO = 0
|
CIRCUITPY_DISPLAYIO = 0
|
||||||
CIRCUITPY_GAMEPAD = 0
|
CIRCUITPY_GAMEPAD = 0
|
||||||
CIRCUITPY_I2CPERIPHERAL = 0
|
CIRCUITPY_I2CPERIPHERAL = 0
|
||||||
CIRCUITPY_NETWORK = 0
|
|
||||||
CIRCUITPY_TOUCHIO = 0
|
CIRCUITPY_TOUCHIO = 0
|
||||||
CIRCUITPY_RGBMATRIX = 0
|
CIRCUITPY_RGBMATRIX = 0
|
||||||
CIRCUITPY_PS2IO = 0
|
CIRCUITPY_PS2IO = 0
|
||||||
CIRCUITPY_USB_HID = 0
|
CIRCUITPY_USB_HID = 0
|
||||||
CIRCUITPY_USB_MIDI = 0
|
CIRCUITPY_USB_MIDI = 0
|
||||||
CIRCUITPY_RTC = 0
|
CIRCUITPY_RTC = 0
|
||||||
|
|
||||||
|
# Enable board-specific modules
|
||||||
|
USER_C_MODULES = boards/winterbloom_big_honking_button/usermods
|
||||||
|
CFLAGS += -DMODULE_BHB_ENABLED=1
|
||||||
|
@ -0,0 +1,120 @@
|
|||||||
|
#include "py/obj.h"
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "shared-bindings/microcontroller/Pin.h"
|
||||||
|
#include "samd/pins.h"
|
||||||
|
#include "sam.h"
|
||||||
|
|
||||||
|
STATIC mp_obj_t _bhb_read_adc(void);
|
||||||
|
|
||||||
|
STATIC mp_obj_t _bhb_init_adc(void) {
|
||||||
|
claim_pin(&pin_PB08);
|
||||||
|
common_hal_never_reset_pin(&pin_PB08);
|
||||||
|
|
||||||
|
/* Enable the APB clock for the ADC. */
|
||||||
|
PM->APBCMASK.reg |= PM_APBCMASK_ADC;
|
||||||
|
|
||||||
|
/* Enable GCLK0 for the ADC */
|
||||||
|
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |
|
||||||
|
GCLK_CLKCTRL_GEN_GCLK0 |
|
||||||
|
GCLK_CLKCTRL_ID_ADC;
|
||||||
|
|
||||||
|
/* Wait for bus synchronization. */
|
||||||
|
while (GCLK->STATUS.bit.SYNCBUSY) {};
|
||||||
|
|
||||||
|
uint32_t bias = (*((uint32_t *) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos;
|
||||||
|
uint32_t linearity = (*((uint32_t *) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos;
|
||||||
|
linearity |= ((*((uint32_t *) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5;
|
||||||
|
|
||||||
|
/* Wait for bus synchronization. */
|
||||||
|
while (ADC->STATUS.bit.SYNCBUSY) {};
|
||||||
|
|
||||||
|
/* Write the calibration data. */
|
||||||
|
ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity);
|
||||||
|
|
||||||
|
/* Use the internal VCC reference. This is 1/2 of what's on VCCA.
|
||||||
|
since VCCA is 3.3v, this is 1.65v.
|
||||||
|
*/
|
||||||
|
ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1;
|
||||||
|
|
||||||
|
/* Capture 64 samples. */
|
||||||
|
ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_64 | ADC_AVGCTRL_ADJRES(4);
|
||||||
|
|
||||||
|
/* Set the clock prescaler to 32, which is the same as the CircuitPython default.
|
||||||
|
Set the resolution to 16 for averaging
|
||||||
|
*/
|
||||||
|
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV32 |
|
||||||
|
ADC_CTRLB_RESSEL_16BIT;
|
||||||
|
|
||||||
|
/* Configure the input parameters.
|
||||||
|
|
||||||
|
- GAIN_DIV2 means that the input voltage is halved. This is important
|
||||||
|
because the voltage reference is 1/2 of VCCA. So if you want to
|
||||||
|
measure 0-3.3v, you need to halve the input as well.
|
||||||
|
|
||||||
|
- MUXNEG_GND means that the ADC should compare the input value to GND.
|
||||||
|
|
||||||
|
- MUXPOS_PIN3 means that the ADC should read from AIN2, or PB08.
|
||||||
|
*/
|
||||||
|
ADC->INPUTCTRL.reg = ADC_INPUTCTRL_GAIN_DIV2 |
|
||||||
|
ADC_INPUTCTRL_MUXNEG_GND |
|
||||||
|
ADC_INPUTCTRL_MUXPOS_PIN2;
|
||||||
|
|
||||||
|
|
||||||
|
/* Set PB08 as an input pin. */
|
||||||
|
PORT->Group[1].DIRCLR.reg = PORT_PB08;
|
||||||
|
|
||||||
|
/* Enable the peripheral multiplexer for PB08. */
|
||||||
|
PORT->Group[1].PINCFG[8].reg |= PORT_PINCFG_PMUXEN;
|
||||||
|
|
||||||
|
/* Set PB08 to function B which is analog input. */
|
||||||
|
PORT->Group[1].PMUX[4].reg |= PORT_PMUX_PMUXE_B;
|
||||||
|
|
||||||
|
/* Wait for bus synchronization. */
|
||||||
|
while (ADC->STATUS.bit.SYNCBUSY) {};
|
||||||
|
|
||||||
|
/* Enable the ADC. */
|
||||||
|
ADC->CTRLA.bit.ENABLE = true;
|
||||||
|
|
||||||
|
/* Make one read and throw it away, as per the datasheet. */
|
||||||
|
_bhb_read_adc();
|
||||||
|
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_obj_t _bhb_read_adc(void) {
|
||||||
|
/* Wait for bus synchronization. */
|
||||||
|
while (ADC->STATUS.bit.SYNCBUSY) {};
|
||||||
|
|
||||||
|
/* Start the ADC using a software trigger. */
|
||||||
|
ADC->SWTRIG.bit.START = true;
|
||||||
|
|
||||||
|
/* Wait for the result ready flag to be set. */
|
||||||
|
while (ADC->INTFLAG.bit.RESRDY == 0);
|
||||||
|
|
||||||
|
/* Clear the flag. */
|
||||||
|
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
||||||
|
|
||||||
|
/* Read the value. */
|
||||||
|
uint32_t result = ADC->RESULT.reg;
|
||||||
|
|
||||||
|
return MP_OBJ_NEW_SMALL_INT(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(_bhb_init_adc_obj, _bhb_init_adc);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(_bhb_read_adc_obj, _bhb_read_adc);
|
||||||
|
|
||||||
|
STATIC const mp_rom_map_elem_t _bhb_module_globals_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__bhb) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_init_adc), MP_ROM_PTR(&_bhb_init_adc_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_read_adc), MP_ROM_PTR(&_bhb_read_adc_obj) },
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(_bhb_module_globals, _bhb_module_globals_table);
|
||||||
|
|
||||||
|
const mp_obj_module_t _bhb_user_cmodule = {
|
||||||
|
.base = { &mp_type_module },
|
||||||
|
.globals = (mp_obj_dict_t*)&_bhb_module_globals,
|
||||||
|
};
|
||||||
|
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR__bhb, _bhb_user_cmodule, MODULE_BHB_ENABLED);
|
@ -0,0 +1,6 @@
|
|||||||
|
USERMODULES_DIR := $(USERMOD_DIR)
|
||||||
|
|
||||||
|
# Add all C files to SRC_USERMOD.
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/bhb.c
|
||||||
|
|
||||||
|
CFLAGS_USERMOD += -I$(USERMODULES_DIR)
|
@ -23,7 +23,6 @@ CIRCUITPY_DISPLAYIO = 0
|
|||||||
CIRCUITPY_FRAMEBUFFERIO = 0
|
CIRCUITPY_FRAMEBUFFERIO = 0
|
||||||
CIRCUITPY_GAMEPAD = 0
|
CIRCUITPY_GAMEPAD = 0
|
||||||
CIRCUITPY_I2CPERIPHERAL = 0
|
CIRCUITPY_I2CPERIPHERAL = 0
|
||||||
CIRCUITPY_NETWORK = 0
|
|
||||||
CIRCUITPY_TOUCHIO = 0
|
CIRCUITPY_TOUCHIO = 0
|
||||||
CIRCUITPY_RGBMATRIX = 0
|
CIRCUITPY_RGBMATRIX = 0
|
||||||
CIRCUITPY_PS2IO = 0
|
CIRCUITPY_PS2IO = 0
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "hpl_gclk_config.h"
|
#include "hpl_gclk_config.h"
|
||||||
|
|
||||||
#include "shared-bindings/time/__init__.h"
|
#include "shared-bindings/time/__init__.h"
|
||||||
|
#include "supervisor/shared/tick.h"
|
||||||
#include "supervisor/shared/translate.h"
|
#include "supervisor/shared/translate.h"
|
||||||
|
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
@ -132,7 +133,7 @@ void frequencyin_interrupt_handler(uint8_t index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if we've reached the upper limit of detection
|
// Check if we've reached the upper limit of detection
|
||||||
if (!background_tasks_ok() || self->errored_too_fast) {
|
if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
|
||||||
self->errored_too_fast = true;
|
self->errored_too_fast = true;
|
||||||
frequencyin_emergency_cancel_capture(i);
|
frequencyin_emergency_cancel_capture(i);
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "samd/timers.h"
|
#include "samd/timers.h"
|
||||||
#include "shared-bindings/microcontroller/__init__.h"
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
#include "shared-bindings/pulseio/PulseIn.h"
|
#include "shared-bindings/pulseio/PulseIn.h"
|
||||||
|
#include "supervisor/shared/tick.h"
|
||||||
#include "supervisor/shared/translate.h"
|
#include "supervisor/shared/translate.h"
|
||||||
|
|
||||||
// This timer is shared amongst all PulseIn objects as a higher resolution clock.
|
// This timer is shared amongst all PulseIn objects as a higher resolution clock.
|
||||||
@ -87,7 +88,7 @@ void pulsein_interrupt_handler(uint8_t channel) {
|
|||||||
uint32_t current_count = tc->COUNT16.COUNT.reg;
|
uint32_t current_count = tc->COUNT16.COUNT.reg;
|
||||||
|
|
||||||
pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
|
pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
|
||||||
if (!background_tasks_ok() || self->errored_too_fast) {
|
if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
|
||||||
self->errored_too_fast = true;
|
self->errored_too_fast = true;
|
||||||
common_hal_pulseio_pulsein_pause(self);
|
common_hal_pulseio_pulsein_pause(self);
|
||||||
return;
|
return;
|
||||||
|
@ -54,8 +54,7 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0
|
|||||||
# The ifndef's allow overriding in mpconfigboard.mk.
|
# The ifndef's allow overriding in mpconfigboard.mk.
|
||||||
|
|
||||||
ifndef CIRCUITPY_NETWORK
|
ifndef CIRCUITPY_NETWORK
|
||||||
CIRCUITPY_NETWORK = 1
|
CIRCUITPY_NETWORK = 0
|
||||||
MICROPY_PY_WIZNET5K = 5500
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef CIRCUITPY_PS2IO
|
ifndef CIRCUITPY_PS2IO
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include "hpl/gclk/hpl_gclk_base.h"
|
#include "hpl/gclk/hpl_gclk_base.h"
|
||||||
#include "hal_gpio.h"
|
#include "hal_gpio.h"
|
||||||
#include "lib/tinyusb/src/device/usbd.h"
|
#include "lib/tinyusb/src/device/usbd.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
|
#include "supervisor/usb.h"
|
||||||
|
|
||||||
void init_usb_hardware(void) {
|
void init_usb_hardware(void) {
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
@ -61,24 +63,24 @@ void init_usb_hardware(void) {
|
|||||||
|
|
||||||
#ifdef SAMD21
|
#ifdef SAMD21
|
||||||
void USB_Handler(void) {
|
void USB_Handler(void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SAM_D5X_E5X
|
#ifdef SAM_D5X_E5X
|
||||||
void USB_0_Handler (void) {
|
void USB_0_Handler (void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void USB_1_Handler (void) {
|
void USB_1_Handler (void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void USB_2_Handler (void) {
|
void USB_2_Handler (void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void USB_3_Handler (void) {
|
void USB_3_Handler (void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,24 +30,6 @@
|
|||||||
#include "supervisor/filesystem.h"
|
#include "supervisor/filesystem.h"
|
||||||
#include "supervisor/shared/stack.h"
|
#include "supervisor/shared/stack.h"
|
||||||
|
|
||||||
static bool running_background_tasks = false;
|
void port_background_task(void) {}
|
||||||
|
void port_start_background_task(void) {}
|
||||||
void background_tasks_reset(void) {
|
void port_finish_background_task(void) {}
|
||||||
running_background_tasks = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_background_tasks(void) {
|
|
||||||
// Don't call ourselves recursively.
|
|
||||||
if (running_background_tasks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_heap_ok();
|
|
||||||
running_background_tasks = true;
|
|
||||||
|
|
||||||
usb_background();
|
|
||||||
filesystem_background();
|
|
||||||
|
|
||||||
running_background_tasks = false;
|
|
||||||
assert_heap_ok();
|
|
||||||
}
|
|
||||||
|
@ -27,7 +27,4 @@
|
|||||||
#ifndef MICROPY_INCLUDED_CXD56_BACKGROUND_H
|
#ifndef MICROPY_INCLUDED_CXD56_BACKGROUND_H
|
||||||
#define MICROPY_INCLUDED_CXD56_BACKGROUND_H
|
#define MICROPY_INCLUDED_CXD56_BACKGROUND_H
|
||||||
|
|
||||||
void background_tasks_reset(void);
|
|
||||||
void run_background_tasks(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_CXD56_BACKGROUND_H
|
#endif // MICROPY_INCLUDED_CXD56_BACKGROUND_H
|
||||||
|
@ -35,27 +35,12 @@
|
|||||||
#include "shared-module/displayio/__init__.h"
|
#include "shared-module/displayio/__init__.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool running_background_tasks = false;
|
|
||||||
|
|
||||||
void background_tasks_reset(void) {
|
|
||||||
running_background_tasks = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_background_tasks(void) {
|
|
||||||
// Don't call ourselves recursively.
|
|
||||||
if (running_background_tasks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void port_background_task(void) {
|
||||||
// Zero delay in case FreeRTOS wants to switch to something else.
|
// Zero delay in case FreeRTOS wants to switch to something else.
|
||||||
vTaskDelay(0);
|
vTaskDelay(0);
|
||||||
running_background_tasks = true;
|
|
||||||
filesystem_background();
|
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
displayio_background();
|
|
||||||
#endif
|
|
||||||
running_background_tasks = false;
|
|
||||||
|
|
||||||
assert_heap_ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void port_start_background_task(void) {}
|
||||||
|
|
||||||
|
void port_finish_background_task(void) {}
|
||||||
|
@ -29,7 +29,4 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
void background_tasks_reset(void);
|
|
||||||
void run_background_tasks(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ESP32S2_BACKGROUND_H
|
#endif // MICROPY_INCLUDED_ESP32S2_BACKGROUND_H
|
||||||
|
@ -29,32 +29,6 @@
|
|||||||
#include "supervisor/usb.h"
|
#include "supervisor/usb.h"
|
||||||
#include "supervisor/shared/stack.h"
|
#include "supervisor/shared/stack.h"
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
void port_background_task(void) {}
|
||||||
#include "shared-module/displayio/__init__.h"
|
void port_start_background_task(void) {}
|
||||||
#endif
|
void port_finish_background_task(void) {}
|
||||||
|
|
||||||
static bool running_background_tasks = false;
|
|
||||||
|
|
||||||
void background_tasks_reset(void) {
|
|
||||||
running_background_tasks = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_background_tasks(void) {
|
|
||||||
// Don't call ourselves recursively.
|
|
||||||
if (running_background_tasks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
running_background_tasks = true;
|
|
||||||
filesystem_background();
|
|
||||||
|
|
||||||
#if USB_AVAILABLE
|
|
||||||
usb_background();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
displayio_background();
|
|
||||||
#endif
|
|
||||||
running_background_tasks = false;
|
|
||||||
|
|
||||||
assert_heap_ok();
|
|
||||||
}
|
|
||||||
|
@ -27,9 +27,4 @@
|
|||||||
#ifndef MICROPY_INCLUDED_LITEX_BACKGROUND_H
|
#ifndef MICROPY_INCLUDED_LITEX_BACKGROUND_H
|
||||||
#define MICROPY_INCLUDED_LITEX_BACKGROUND_H
|
#define MICROPY_INCLUDED_LITEX_BACKGROUND_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
void background_tasks_reset(void);
|
|
||||||
void run_background_tasks(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_LITEX_BACKGROUND_H
|
#endif // MICROPY_INCLUDED_LITEX_BACKGROUND_H
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "py/mpstate.h"
|
#include "py/mpstate.h"
|
||||||
#include "py/gc.h"
|
#include "py/gc.h"
|
||||||
|
#include "supervisor/usb.h"
|
||||||
|
|
||||||
#include "csr.h"
|
#include "csr.h"
|
||||||
#include "generated/soc.h"
|
#include "generated/soc.h"
|
||||||
@ -49,7 +50,7 @@ void isr(void) {
|
|||||||
|
|
||||||
#ifdef CFG_TUSB_MCU
|
#ifdef CFG_TUSB_MCU
|
||||||
if (irqs & (1 << USB_INTERRUPT))
|
if (irqs & (1 << USB_INTERRUPT))
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
#endif
|
#endif
|
||||||
if (irqs & (1 << TIMER0_INTERRUPT))
|
if (irqs & (1 << TIMER0_INTERRUPT))
|
||||||
SysTick_Handler();
|
SysTick_Handler();
|
||||||
|
@ -24,58 +24,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "background.h"
|
|
||||||
|
|
||||||
//#include "audio_dma.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/filesystem.h"
|
|
||||||
#include "supervisor/shared/tick.h"
|
|
||||||
#include "supervisor/usb.h"
|
|
||||||
|
|
||||||
#include "py/runtime.h"
|
|
||||||
#include "shared-module/network/__init__.h"
|
|
||||||
#include "supervisor/linker.h"
|
|
||||||
#include "supervisor/shared/stack.h"
|
|
||||||
|
|
||||||
#ifdef CIRCUITPY_DISPLAYIO
|
|
||||||
#include "shared-module/displayio/__init__.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
volatile uint64_t last_finished_tick = 0;
|
|
||||||
|
|
||||||
bool stack_ok_so_far = true;
|
|
||||||
|
|
||||||
static bool running_background_tasks = false;
|
|
||||||
|
|
||||||
void background_tasks_reset(void) {
|
|
||||||
running_background_tasks = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PLACE_IN_ITCM(run_background_tasks)(void) {
|
|
||||||
// Don't call ourselves recursively.
|
|
||||||
if (running_background_tasks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assert_heap_ok();
|
|
||||||
running_background_tasks = true;
|
|
||||||
|
|
||||||
|
void port_background_task(void) {
|
||||||
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
|
#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO
|
||||||
audio_dma_background();
|
audio_dma_background();
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
displayio_background();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_NETWORK
|
|
||||||
network_module_background();
|
|
||||||
#endif
|
|
||||||
filesystem_background();
|
|
||||||
usb_background();
|
|
||||||
running_background_tasks = false;
|
|
||||||
assert_heap_ok();
|
|
||||||
|
|
||||||
last_finished_tick = supervisor_ticks_ms64();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool background_tasks_ok(void) {
|
|
||||||
return supervisor_ticks_ms64() - last_finished_tick < 1000;
|
|
||||||
}
|
}
|
||||||
|
void port_start_background_task(void) {}
|
||||||
|
void port_finish_background_task(void) {}
|
||||||
|
@ -28,11 +28,4 @@
|
|||||||
#ifndef MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
|
#ifndef MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
|
||||||
#define MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
|
#define MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
void background_tasks_reset(void);
|
|
||||||
void run_background_tasks(void);
|
|
||||||
void run_background_vm_tasks(void);
|
|
||||||
bool background_tasks_ok(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
|
#endif // MICROPY_INCLUDED_MIMXRT10XX_BACKGROUND_H
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
// // last ms.
|
// // last ms.
|
||||||
// current_us = 1000 - current_us;
|
// current_us = 1000 - current_us;
|
||||||
// pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
|
// pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
|
||||||
// if (!background_tasks_ok() || self->errored_too_fast) {
|
// if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
|
||||||
// self->errored_too_fast = true;
|
// self->errored_too_fast = true;
|
||||||
// common_hal_pulseio_pulsein_pause(self);
|
// common_hal_pulseio_pulsein_pause(self);
|
||||||
// return;
|
// return;
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "fsl_clock.h"
|
#include "fsl_clock.h"
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
|
#include "supervisor/usb.h"
|
||||||
|
|
||||||
void init_usb_hardware(void) {
|
void init_usb_hardware(void) {
|
||||||
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
|
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
|
||||||
@ -56,5 +57,5 @@ void init_usb_hardware(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void USB_OTG1_IRQHandler(void) {
|
void USB_OTG1_IRQHandler(void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
|
@ -46,36 +46,14 @@
|
|||||||
#include "common-hal/_bleio/bonding.h"
|
#include "common-hal/_bleio/bonding.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool running_background_tasks = false;
|
void port_start_background_task(void) {}
|
||||||
|
void port_finish_background_task(void) {}
|
||||||
|
|
||||||
void background_tasks_reset(void) {
|
void port_background_task(void) {
|
||||||
running_background_tasks = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_background_tasks(void) {
|
|
||||||
// Don't call ourselves recursively.
|
|
||||||
if (running_background_tasks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
running_background_tasks = true;
|
|
||||||
filesystem_background();
|
|
||||||
usb_background();
|
|
||||||
#if CIRCUITPY_AUDIOPWMIO
|
#if CIRCUITPY_AUDIOPWMIO
|
||||||
audiopwmout_background();
|
audiopwmout_background();
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_AUDIOBUSIO
|
#if CIRCUITPY_AUDIOBUSIO
|
||||||
i2s_background();
|
i2s_background();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_BLEIO
|
|
||||||
supervisor_bluetooth_background();
|
|
||||||
bonding_background();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
displayio_background();
|
|
||||||
#endif
|
|
||||||
running_background_tasks = false;
|
|
||||||
|
|
||||||
assert_heap_ok();
|
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,4 @@
|
|||||||
#ifndef MICROPY_INCLUDED_NRF_BACKGROUND_H
|
#ifndef MICROPY_INCLUDED_NRF_BACKGROUND_H
|
||||||
#define MICROPY_INCLUDED_NRF_BACKGROUND_H
|
#define MICROPY_INCLUDED_NRF_BACKGROUND_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
void background_tasks_reset(void);
|
|
||||||
void run_background_tasks(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_NRF_BACKGROUND_H
|
#endif // MICROPY_INCLUDED_NRF_BACKGROUND_H
|
||||||
|
@ -8,7 +8,3 @@ MCU_CHIP = nrf52840
|
|||||||
QSPI_FLASH_FILESYSTEM = 1
|
QSPI_FLASH_FILESYSTEM = 1
|
||||||
EXTERNAL_FLASH_DEVICE_COUNT = 1
|
EXTERNAL_FLASH_DEVICE_COUNT = 1
|
||||||
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
|
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
|
||||||
|
|
||||||
# Support for the Ethernet FeatherWing
|
|
||||||
CIRCUITPY_NETWORK = 1
|
|
||||||
MICROPY_PY_WIZNET5K = 5500
|
|
||||||
|
@ -8,7 +8,3 @@ MCU_CHIP = nrf52840
|
|||||||
QSPI_FLASH_FILESYSTEM = 1
|
QSPI_FLASH_FILESYSTEM = 1
|
||||||
EXTERNAL_FLASH_DEVICE_COUNT = 1
|
EXTERNAL_FLASH_DEVICE_COUNT = 1
|
||||||
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
|
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
|
||||||
|
|
||||||
# Support for the Ethernet FeatherWing
|
|
||||||
CIRCUITPY_NETWORK = 1
|
|
||||||
MICROPY_PY_WIZNET5K = 5500
|
|
||||||
|
@ -8,7 +8,3 @@ MCU_CHIP = nrf52840
|
|||||||
QSPI_FLASH_FILESYSTEM = 1
|
QSPI_FLASH_FILESYSTEM = 1
|
||||||
EXTERNAL_FLASH_DEVICE_COUNT = 1
|
EXTERNAL_FLASH_DEVICE_COUNT = 1
|
||||||
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
|
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
|
||||||
|
|
||||||
# Support for the Ethernet FeatherWing
|
|
||||||
CIRCUITPY_NETWORK = 1
|
|
||||||
MICROPY_PY_WIZNET5K = 5500
|
|
||||||
|
@ -50,24 +50,23 @@ void common_hal_mcu_delay_us(uint32_t delay) {
|
|||||||
|
|
||||||
static volatile uint32_t nesting_count = 0;
|
static volatile uint32_t nesting_count = 0;
|
||||||
static uint8_t is_nested_critical_region;
|
static uint8_t is_nested_critical_region;
|
||||||
static uint8_t sd_is_enabled = false;
|
|
||||||
void common_hal_mcu_disable_interrupts() {
|
void common_hal_mcu_disable_interrupts() {
|
||||||
sd_softdevice_is_enabled(&sd_is_enabled);
|
if (nesting_count == 0) {
|
||||||
if (sd_is_enabled) {
|
// Unlike __disable_irq(), this should only be called the first time
|
||||||
|
// "is_nested_critical_region" is sd's equivalent of our nesting count
|
||||||
|
// so a nested call would store 0 in the global and make the later
|
||||||
|
// exit call not actually reenable interrupts
|
||||||
|
//
|
||||||
|
// This only disables interrupts of priority 2 through 7; levels 0, 1,
|
||||||
|
// and 4, are exclusive to softdevice and should never be used, so
|
||||||
|
// this limitation is not important.
|
||||||
sd_nvic_critical_region_enter(&is_nested_critical_region);
|
sd_nvic_critical_region_enter(&is_nested_critical_region);
|
||||||
} else {
|
}
|
||||||
__disable_irq();
|
|
||||||
__DMB();
|
__DMB();
|
||||||
nesting_count++;
|
nesting_count++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_mcu_enable_interrupts() {
|
void common_hal_mcu_enable_interrupts() {
|
||||||
// Don't check here if SD is enabled, because we'll crash if interrupts
|
|
||||||
// were turned off and sd_softdevice_is_enabled is called.
|
|
||||||
if (sd_is_enabled) {
|
|
||||||
sd_nvic_critical_region_exit(is_nested_critical_region);
|
|
||||||
} else {
|
|
||||||
if (nesting_count == 0) {
|
if (nesting_count == 0) {
|
||||||
// This is very very bad because it means there was mismatched disable/enables so we
|
// This is very very bad because it means there was mismatched disable/enables so we
|
||||||
// crash.
|
// crash.
|
||||||
@ -78,8 +77,7 @@ void common_hal_mcu_enable_interrupts() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
__DMB();
|
__DMB();
|
||||||
__enable_irq();
|
sd_nvic_critical_region_exit(is_nested_critical_region);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
|
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
|
||||||
|
@ -313,12 +313,21 @@ void port_sleep_until_interrupt(void) {
|
|||||||
// instruction will returned as long as an interrupt is
|
// instruction will returned as long as an interrupt is
|
||||||
// available, even though the actual handler won't fire until
|
// available, even though the actual handler won't fire until
|
||||||
// we re-enable interrupts.
|
// we re-enable interrupts.
|
||||||
common_hal_mcu_disable_interrupts();
|
//
|
||||||
|
// We do not use common_hal_mcu_disable_interrupts here because
|
||||||
|
// we truly require that interrupts be disabled, while
|
||||||
|
// common_hal_mcu_disable_interrupts actually just masks the
|
||||||
|
// interrupts that are not required to allow the softdevice to
|
||||||
|
// function (whether or not SD is enabled)
|
||||||
|
int nested = __get_PRIMASK();
|
||||||
|
__disable_irq();
|
||||||
if (!tud_task_event_ready()) {
|
if (!tud_task_event_ready()) {
|
||||||
__DSB();
|
__DSB();
|
||||||
__WFI();
|
__WFI();
|
||||||
}
|
}
|
||||||
common_hal_mcu_enable_interrupts();
|
if (!nested) {
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "lib/utils/interrupt_char.h"
|
#include "lib/utils/interrupt_char.h"
|
||||||
#include "lib/mp-readline/readline.h"
|
#include "lib/mp-readline/readline.h"
|
||||||
#include "lib/tinyusb/src/device/usbd.h"
|
#include "lib/tinyusb/src/device/usbd.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
|
|
||||||
#ifdef SOFTDEVICE_PRESENT
|
#ifdef SOFTDEVICE_PRESENT
|
||||||
#include "nrf_sdm.h"
|
#include "nrf_sdm.h"
|
||||||
@ -42,7 +43,9 @@ extern void tusb_hal_nrf_power_event(uint32_t event);
|
|||||||
|
|
||||||
void init_usb_hardware(void) {
|
void init_usb_hardware(void) {
|
||||||
|
|
||||||
// 2 is max priority (0, 1 are reserved for SD)
|
// 2 is max priority (0, 1, and 4 are reserved for SD)
|
||||||
|
// 5 is max priority that still allows calling SD functions such as
|
||||||
|
// sd_softdevice_is_enabled
|
||||||
NVIC_SetPriority(USBD_IRQn, 2);
|
NVIC_SetPriority(USBD_IRQn, 2);
|
||||||
|
|
||||||
// USB power may already be ready at this time -> no event generated
|
// USB power may already be ready at this time -> no event generated
|
||||||
@ -89,5 +92,5 @@ void init_usb_hardware(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void USBD_IRQHandler(void) {
|
void USBD_IRQHandler(void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
|
@ -33,28 +33,6 @@
|
|||||||
#include "shared-module/displayio/__init__.h"
|
#include "shared-module/displayio/__init__.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool running_background_tasks = false;
|
void port_background_task(void) {}
|
||||||
|
void port_start_background_task(void) {}
|
||||||
void background_tasks_reset(void) {
|
void port_finish_background_task(void) {}
|
||||||
running_background_tasks = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_background_tasks(void) {
|
|
||||||
// Don't call ourselves recursively.
|
|
||||||
if (running_background_tasks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
running_background_tasks = true;
|
|
||||||
filesystem_background();
|
|
||||||
|
|
||||||
#if USB_AVAILABLE
|
|
||||||
usb_background();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_DISPLAYIO
|
|
||||||
displayio_background();
|
|
||||||
#endif
|
|
||||||
running_background_tasks = false;
|
|
||||||
|
|
||||||
assert_heap_ok();
|
|
||||||
}
|
|
||||||
|
@ -27,9 +27,4 @@
|
|||||||
#ifndef MICROPY_INCLUDED_STM32_BACKGROUND_H
|
#ifndef MICROPY_INCLUDED_STM32_BACKGROUND_H
|
||||||
#define MICROPY_INCLUDED_STM32_BACKGROUND_H
|
#define MICROPY_INCLUDED_STM32_BACKGROUND_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
void background_tasks_reset(void);
|
|
||||||
void run_background_tasks(void);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_STM32_BACKGROUND_H
|
#endif // MICROPY_INCLUDED_STM32_BACKGROUND_H
|
||||||
|
@ -130,5 +130,5 @@ void init_usb_hardware(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OTG_FS_IRQHandler(void) {
|
void OTG_FS_IRQHandler(void) {
|
||||||
tud_int_handler(0);
|
usb_irq_handler();
|
||||||
}
|
}
|
||||||
|
4
py/mpz.c
4
py/mpz.c
@ -444,6 +444,10 @@ STATIC size_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, size_t jlen, mpz_dig_t *
|
|||||||
}
|
}
|
||||||
|
|
||||||
ilen = id - oidig;
|
ilen = id - oidig;
|
||||||
|
// check to prevent usb starvation
|
||||||
|
#ifdef RUN_BACKGROUND_TASKS
|
||||||
|
RUN_BACKGROUND_TASKS;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return ilen;
|
return ilen;
|
||||||
|
@ -40,6 +40,9 @@
|
|||||||
|
|
||||||
//| """Network Interface Management
|
//| """Network Interface Management
|
||||||
//|
|
//|
|
||||||
|
//| .. warning:: This module is disabled in 6.x and will removed in 7.x. Please use networking
|
||||||
|
//| libraries instead.
|
||||||
|
//|
|
||||||
//| This module provides a registry of configured NICs.
|
//| This module provides a registry of configured NICs.
|
||||||
//| It is used by the 'socket' module to look up a suitable
|
//| It is used by the 'socket' module to look up a suitable
|
||||||
//| NIC when a socket is created."""
|
//| NIC when a socket is created."""
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
|
|
||||||
//| """TCP, UDP and RAW socket support
|
//| """TCP, UDP and RAW socket support
|
||||||
//|
|
//|
|
||||||
|
//| .. warning:: This module is disabled in 6.x and will removed in 7.x. Please use networking
|
||||||
|
//| libraries instead. (Native networking will provide a socket compatible class.)
|
||||||
|
//|
|
||||||
//| Create TCP, UDP and RAW sockets for communicating over the Internet."""
|
//| Create TCP, UDP and RAW sockets for communicating over the Internet."""
|
||||||
//|
|
//|
|
||||||
|
|
||||||
|
@ -49,20 +49,7 @@ static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_ar
|
|||||||
//|
|
//|
|
||||||
STATIC mp_obj_t vectorio_polygon_obj_get_points(mp_obj_t self_in) {
|
STATIC mp_obj_t vectorio_polygon_obj_get_points(mp_obj_t self_in) {
|
||||||
vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
|
vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
mp_obj_t list = mp_obj_new_list(0, NULL);
|
return common_hal_vectorio_polygon_get_points(self);
|
||||||
|
|
||||||
size_t len = 0;
|
|
||||||
mp_obj_t *items;
|
|
||||||
mp_obj_list_get(common_hal_vectorio_polygon_get_points(self), &len, &items);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i += 2) {
|
|
||||||
mp_obj_t tuple[] = { items[i], items[i+1] };
|
|
||||||
mp_obj_list_append(
|
|
||||||
list,
|
|
||||||
mp_obj_new_tuple(2, tuple)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_points_obj, vectorio_polygon_obj_get_points);
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_points_obj, vectorio_polygon_obj_get_points);
|
||||||
|
|
||||||
|
@ -35,7 +35,12 @@
|
|||||||
|
|
||||||
#include "shared-module/network/__init__.h"
|
#include "shared-module/network/__init__.h"
|
||||||
|
|
||||||
//| """Support for WizNet hardware, including the WizNet 5500 Ethernet adaptor."""
|
//| """Support for WizNet hardware, including the WizNet 5500 Ethernet adaptor.
|
||||||
|
//|
|
||||||
|
//|
|
||||||
|
//| .. warning:: This module is disabled in 6.x and will removed in 7.x. Please use networking
|
||||||
|
//| libraries instead.
|
||||||
|
//| """
|
||||||
//|
|
//|
|
||||||
|
|
||||||
extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
|
extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
|
||||||
|
@ -36,11 +36,12 @@
|
|||||||
|
|
||||||
#include "shared-module/audiomp3/MP3Decoder.h"
|
#include "shared-module/audiomp3/MP3Decoder.h"
|
||||||
#include "supervisor/shared/translate.h"
|
#include "supervisor/shared/translate.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
#include "lib/mp3/src/mp3common.h"
|
#include "lib/mp3/src/mp3common.h"
|
||||||
|
|
||||||
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
|
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
|
||||||
|
|
||||||
/** Fill the input buffer if it is less than half full.
|
/** Fill the input buffer unconditionally.
|
||||||
*
|
*
|
||||||
* Returns true if the input buffer contains any useful data,
|
* Returns true if the input buffer contains any useful data,
|
||||||
* false otherwise. (The input buffer will be padded to the end with
|
* false otherwise. (The input buffer will be padded to the end with
|
||||||
@ -50,10 +51,7 @@
|
|||||||
*
|
*
|
||||||
* Sets self->eof if any read of the file returns 0 bytes
|
* Sets self->eof if any read of the file returns 0 bytes
|
||||||
*/
|
*/
|
||||||
STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
|
STATIC bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t* self) {
|
||||||
// If buffer is over half full, do nothing
|
|
||||||
if (self->inbuf_offset < self->inbuf_length/2) return true;
|
|
||||||
|
|
||||||
// If we didn't previously reach the end of file, we can try reading now
|
// If we didn't previously reach the end of file, we can try reading now
|
||||||
if (!self->eof) {
|
if (!self->eof) {
|
||||||
|
|
||||||
@ -87,6 +85,26 @@ STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
|
|||||||
return self->inbuf_offset < self->inbuf_length;
|
return self->inbuf_offset < self->inbuf_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Update the inbuf from a background callback.
|
||||||
|
*
|
||||||
|
* This variant is introduced so that at the site of the
|
||||||
|
* add_background_callback_core call, the prototype matches.
|
||||||
|
*/
|
||||||
|
STATIC void mp3file_update_inbuf_cb(void* self) {
|
||||||
|
mp3file_update_inbuf_always(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fill the input buffer if it is less than half full.
|
||||||
|
*
|
||||||
|
* Returns the same as mp3file_update_inbuf_always.
|
||||||
|
*/
|
||||||
|
STATIC bool mp3file_update_inbuf_half(audiomp3_mp3file_obj_t* self) {
|
||||||
|
// If buffer is over half full, do nothing
|
||||||
|
if (self->inbuf_offset < self->inbuf_length/2) return true;
|
||||||
|
|
||||||
|
return mp3file_update_inbuf_always(self);
|
||||||
|
}
|
||||||
|
|
||||||
#define READ_PTR(self) (self->inbuf + self->inbuf_offset)
|
#define READ_PTR(self) (self->inbuf + self->inbuf_offset)
|
||||||
#define BYTES_LEFT(self) (self->inbuf_length - self->inbuf_offset)
|
#define BYTES_LEFT(self) (self->inbuf_length - self->inbuf_offset)
|
||||||
#define CONSUME(self, n) (self->inbuf_offset += n)
|
#define CONSUME(self, n) (self->inbuf_offset += n)
|
||||||
@ -94,7 +112,7 @@ STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
|
|||||||
// http://id3.org/d3v2.3.0
|
// http://id3.org/d3v2.3.0
|
||||||
// http://id3.org/id3v2.3.0
|
// http://id3.org/id3v2.3.0
|
||||||
STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
|
STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
|
||||||
mp3file_update_inbuf(self);
|
mp3file_update_inbuf_half(self);
|
||||||
if (BYTES_LEFT(self) < 10) {
|
if (BYTES_LEFT(self) < 10) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -129,11 +147,11 @@ STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
|
|||||||
*/
|
*/
|
||||||
STATIC bool mp3file_find_sync_word(audiomp3_mp3file_obj_t* self) {
|
STATIC bool mp3file_find_sync_word(audiomp3_mp3file_obj_t* self) {
|
||||||
do {
|
do {
|
||||||
mp3file_update_inbuf(self);
|
mp3file_update_inbuf_half(self);
|
||||||
int offset = MP3FindSyncWord(READ_PTR(self), BYTES_LEFT(self));
|
int offset = MP3FindSyncWord(READ_PTR(self), BYTES_LEFT(self));
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
CONSUME(self, offset);
|
CONSUME(self, offset);
|
||||||
mp3file_update_inbuf(self);
|
mp3file_update_inbuf_half(self);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
CONSUME(self, MAX(0, BYTES_LEFT(self) - 16));
|
CONSUME(self, MAX(0, BYTES_LEFT(self) - 16));
|
||||||
@ -209,12 +227,14 @@ 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) {
|
void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file_obj_t* file) {
|
||||||
|
background_callback_begin_critical_section();
|
||||||
|
|
||||||
self->file = file;
|
self->file = file;
|
||||||
f_lseek(&self->file->fp, 0);
|
f_lseek(&self->file->fp, 0);
|
||||||
self->inbuf_offset = self->inbuf_length;
|
self->inbuf_offset = self->inbuf_length;
|
||||||
self->eof = 0;
|
self->eof = 0;
|
||||||
self->other_channel = -1;
|
self->other_channel = -1;
|
||||||
mp3file_update_inbuf(self);
|
mp3file_update_inbuf_half(self);
|
||||||
mp3file_find_sync_word(self);
|
mp3file_find_sync_word(self);
|
||||||
// It **SHOULD** not be necessary to do this; the buffer should be filled
|
// It **SHOULD** not be necessary to do this; the buffer should be filled
|
||||||
// with fresh content before it is returned by get_buffer(). The fact that
|
// with fresh content before it is returned by get_buffer(). The fact that
|
||||||
@ -224,7 +244,9 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file
|
|||||||
memset(self->buffers[0], 0, MAX_BUFFER_LEN);
|
memset(self->buffers[0], 0, MAX_BUFFER_LEN);
|
||||||
memset(self->buffers[1], 0, MAX_BUFFER_LEN);
|
memset(self->buffers[1], 0, MAX_BUFFER_LEN);
|
||||||
MP3FrameInfo fi;
|
MP3FrameInfo fi;
|
||||||
if(!mp3file_get_next_frame_info(self, &fi)) {
|
bool result = mp3file_get_next_frame_info(self, &fi);
|
||||||
|
background_callback_end_critical_section();
|
||||||
|
if (!result) {
|
||||||
mp_raise_msg(&mp_type_RuntimeError,
|
mp_raise_msg(&mp_type_RuntimeError,
|
||||||
translate("Failed to parse MP3 file"));
|
translate("Failed to parse MP3 file"));
|
||||||
}
|
}
|
||||||
@ -277,13 +299,15 @@ 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
|
// We don't reset the buffer index in case we're looping and we have an odd number of buffer
|
||||||
// loads
|
// loads
|
||||||
|
background_callback_begin_critical_section();
|
||||||
f_lseek(&self->file->fp, 0);
|
f_lseek(&self->file->fp, 0);
|
||||||
self->inbuf_offset = self->inbuf_length;
|
self->inbuf_offset = self->inbuf_length;
|
||||||
self->eof = 0;
|
self->eof = 0;
|
||||||
self->other_channel = -1;
|
self->other_channel = -1;
|
||||||
mp3file_update_inbuf(self);
|
mp3file_update_inbuf_half(self);
|
||||||
mp3file_skip_id3v2(self);
|
mp3file_skip_id3v2(self);
|
||||||
mp3file_find_sync_word(self);
|
mp3file_find_sync_word(self);
|
||||||
|
background_callback_end_critical_section();
|
||||||
}
|
}
|
||||||
|
|
||||||
audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t* self,
|
audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t* self,
|
||||||
@ -321,6 +345,14 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
|
|||||||
uint8_t *inbuf = READ_PTR(self);
|
uint8_t *inbuf = READ_PTR(self);
|
||||||
int err = MP3Decode(self->decoder, &inbuf, &bytes_left, buffer, 0);
|
int err = MP3Decode(self->decoder, &inbuf, &bytes_left, buffer, 0);
|
||||||
CONSUME(self, BYTES_LEFT(self) - bytes_left);
|
CONSUME(self, BYTES_LEFT(self) - bytes_left);
|
||||||
|
|
||||||
|
if (self->inbuf_offset >= 512) {
|
||||||
|
background_callback_add(
|
||||||
|
&self->inbuf_fill_cb,
|
||||||
|
mp3file_update_inbuf_cb,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return GET_BUFFER_DONE;
|
return GET_BUFFER_DONE;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
|
#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
|
||||||
#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
|
#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MP3FILE_H
|
||||||
|
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
#include "extmod/vfs_fat.h"
|
#include "extmod/vfs_fat.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
|
|
||||||
@ -36,6 +37,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
struct _MP3DecInfo *decoder;
|
struct _MP3DecInfo *decoder;
|
||||||
|
background_callback_t inbuf_fill_cb;
|
||||||
uint8_t* inbuf;
|
uint8_t* inbuf;
|
||||||
uint32_t inbuf_length;
|
uint32_t inbuf_length;
|
||||||
uint32_t inbuf_offset;
|
uint32_t inbuf_offset;
|
||||||
|
@ -137,7 +137,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self,
|
|||||||
// Set the group after initialization otherwise we may send pixels while we delay in
|
// Set the group after initialization otherwise we may send pixels while we delay in
|
||||||
// initialization.
|
// initialization.
|
||||||
common_hal_displayio_display_show(self, &circuitpython_splash);
|
common_hal_displayio_display_show(self, &circuitpython_splash);
|
||||||
self->auto_refresh = auto_refresh;
|
common_hal_displayio_display_set_auto_refresh(self, auto_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) {
|
bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) {
|
||||||
@ -383,6 +383,13 @@ bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self
|
|||||||
void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self,
|
void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self,
|
||||||
bool auto_refresh) {
|
bool auto_refresh) {
|
||||||
self->first_manual_refresh = !auto_refresh;
|
self->first_manual_refresh = !auto_refresh;
|
||||||
|
if (auto_refresh != self->auto_refresh) {
|
||||||
|
if (auto_refresh) {
|
||||||
|
supervisor_enable_tick();
|
||||||
|
} else {
|
||||||
|
supervisor_disable_tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
self->auto_refresh = auto_refresh;
|
self->auto_refresh = auto_refresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,6 +416,7 @@ void displayio_display_background(displayio_display_obj_t* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void release_display(displayio_display_obj_t* self) {
|
void release_display(displayio_display_obj_t* self) {
|
||||||
|
common_hal_displayio_display_set_auto_refresh(self, false);
|
||||||
release_display_core(&self->core);
|
release_display_core(&self->core);
|
||||||
#if (CIRCUITPY_PULSEIO)
|
#if (CIRCUITPY_PULSEIO)
|
||||||
if (self->backlight_pwm.base.type == &pulseio_pwmout_type) {
|
if (self->backlight_pwm.base.type == &pulseio_pwmout_type) {
|
||||||
@ -423,7 +431,7 @@ void release_display(displayio_display_obj_t* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void reset_display(displayio_display_obj_t* self) {
|
void reset_display(displayio_display_obj_t* self) {
|
||||||
self->auto_refresh = true;
|
common_hal_displayio_display_set_auto_refresh(self, true);
|
||||||
self->auto_brightness = true;
|
self->auto_brightness = true;
|
||||||
common_hal_displayio_display_show(self, NULL);
|
common_hal_displayio_display_show(self, NULL);
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,7 @@ void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self)
|
|||||||
displayio_display_core_begin_transaction(&self->core);
|
displayio_display_core_begin_transaction(&self->core);
|
||||||
self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1);
|
self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1);
|
||||||
displayio_display_core_end_transaction(&self->core);
|
displayio_display_core_end_transaction(&self->core);
|
||||||
|
supervisor_enable_tick();
|
||||||
self->refreshing = true;
|
self->refreshing = true;
|
||||||
|
|
||||||
displayio_display_core_finish_refresh(&self->core);
|
displayio_display_core_finish_refresh(&self->core);
|
||||||
@ -301,6 +302,7 @@ bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* s
|
|||||||
|
|
||||||
if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) {
|
if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) {
|
||||||
if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) {
|
if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) {
|
||||||
|
supervisor_disable_tick();
|
||||||
self->refreshing = false;
|
self->refreshing = false;
|
||||||
// Run stop sequence but don't wait for busy because busy is set when sleeping.
|
// Run stop sequence but don't wait for busy because busy is set when sleeping.
|
||||||
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
|
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
|
||||||
@ -342,6 +344,7 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) {
|
|||||||
refresh_done = supervisor_ticks_ms64() - self->core.last_refresh > self->refresh_time;
|
refresh_done = supervisor_ticks_ms64() - self->core.last_refresh > self->refresh_time;
|
||||||
}
|
}
|
||||||
if (refresh_done) {
|
if (refresh_done) {
|
||||||
|
supervisor_disable_tick();
|
||||||
self->refreshing = false;
|
self->refreshing = false;
|
||||||
// Run stop sequence but don't wait for busy because busy is set when sleeping.
|
// Run stop sequence but don't wait for busy because busy is set when sleeping.
|
||||||
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
|
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
|
||||||
@ -352,6 +355,7 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) {
|
|||||||
void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) {
|
void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) {
|
||||||
if (self->refreshing) {
|
if (self->refreshing) {
|
||||||
wait_for_busy(self);
|
wait_for_busy(self);
|
||||||
|
supervisor_disable_tick();
|
||||||
self->refreshing = false;
|
self->refreshing = false;
|
||||||
// Run stop sequence but don't wait for busy because busy is set when sleeping.
|
// Run stop sequence but don't wait for busy because busy is set when sleeping.
|
||||||
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
|
send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len);
|
||||||
|
@ -190,9 +190,7 @@ void reset_displays(void) {
|
|||||||
common_hal_displayio_epaperdisplay_show(display, NULL);
|
common_hal_displayio_epaperdisplay_show(display, NULL);
|
||||||
#if CIRCUITPY_FRAMEBUFFERIO
|
#if CIRCUITPY_FRAMEBUFFERIO
|
||||||
} else if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) {
|
} else if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) {
|
||||||
framebufferio_framebufferdisplay_obj_t* display = &displays[i].framebuffer_display;
|
framebufferio_framebufferdisplay_reset(&displays[i].framebuffer_display);
|
||||||
display->auto_refresh = true;
|
|
||||||
common_hal_framebufferio_framebufferdisplay_show(display, NULL);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu
|
|||||||
// Set the group after initialization otherwise we may send pixels while we delay in
|
// Set the group after initialization otherwise we may send pixels while we delay in
|
||||||
// initialization.
|
// initialization.
|
||||||
common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash);
|
common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash);
|
||||||
self->auto_refresh = auto_refresh;
|
common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, auto_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_framebufferio_framebufferdisplay_show(framebufferio_framebufferdisplay_obj_t* self, displayio_group_t* root_group) {
|
bool common_hal_framebufferio_framebufferdisplay_show(framebufferio_framebufferdisplay_obj_t* self, displayio_group_t* root_group) {
|
||||||
@ -280,6 +280,13 @@ bool common_hal_framebufferio_framebufferdisplay_get_auto_refresh(framebufferio_
|
|||||||
void common_hal_framebufferio_framebufferdisplay_set_auto_refresh(framebufferio_framebufferdisplay_obj_t* self,
|
void common_hal_framebufferio_framebufferdisplay_set_auto_refresh(framebufferio_framebufferdisplay_obj_t* self,
|
||||||
bool auto_refresh) {
|
bool auto_refresh) {
|
||||||
self->first_manual_refresh = !auto_refresh;
|
self->first_manual_refresh = !auto_refresh;
|
||||||
|
if (auto_refresh != self->auto_refresh) {
|
||||||
|
if (auto_refresh) {
|
||||||
|
supervisor_enable_tick();
|
||||||
|
} else {
|
||||||
|
supervisor_disable_tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
self->auto_refresh = auto_refresh;
|
self->auto_refresh = auto_refresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,12 +304,13 @@ void framebufferio_framebufferdisplay_background(framebufferio_framebufferdispla
|
|||||||
}
|
}
|
||||||
|
|
||||||
void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
|
void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
|
||||||
|
common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, false);
|
||||||
release_display_core(&self->core);
|
release_display_core(&self->core);
|
||||||
self->framebuffer_protocol->deinit(self->framebuffer);
|
self->framebuffer_protocol->deinit(self->framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
|
void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
|
||||||
self->auto_refresh = true;
|
common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true);
|
||||||
common_hal_framebufferio_framebufferdisplay_show(self, NULL);
|
common_hal_framebufferio_framebufferdisplay_show(self, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,3 +318,8 @@ void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisp
|
|||||||
gc_collect_ptr(self->framebuffer);
|
gc_collect_ptr(self->framebuffer);
|
||||||
displayio_display_core_collect_ptrs(&self->core);
|
displayio_display_core_collect_ptrs(&self->core);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self) {
|
||||||
|
common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true);
|
||||||
|
common_hal_framebufferio_framebufferdisplay_show(self, NULL);
|
||||||
|
}
|
||||||
|
@ -55,6 +55,7 @@ typedef struct {
|
|||||||
void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self);
|
void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self);
|
||||||
void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self);
|
void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self);
|
||||||
void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self);
|
void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self);
|
||||||
|
void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self);
|
||||||
|
|
||||||
void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self);
|
void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self);
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple
|
|||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
mp_obj_t *items;
|
mp_obj_t *items;
|
||||||
mp_obj_list_get(points_tuple_list, &len, &items);
|
mp_obj_list_get(points_tuple_list, &len, &items);
|
||||||
VECTORIO_POLYGON_DEBUG("polygon_points_list len: %d\n", len);
|
VECTORIO_POLYGON_DEBUG(" self.len: %d, len: %d, ", self->len, len);
|
||||||
|
|
||||||
if ( len < 3 ) {
|
if ( len < 3 ) {
|
||||||
mp_raise_TypeError_varg(translate("Polygon needs at least 3 points"));
|
mp_raise_TypeError_varg(translate("Polygon needs at least 3 points"));
|
||||||
@ -28,9 +28,11 @@ static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple
|
|||||||
|
|
||||||
if ( self->len < 2*len ) {
|
if ( self->len < 2*len ) {
|
||||||
if ( self->points_list != NULL ) {
|
if ( self->points_list != NULL ) {
|
||||||
|
VECTORIO_POLYGON_DEBUG("free(%d), ", sizeof(self->points_list));
|
||||||
gc_free( self->points_list );
|
gc_free( self->points_list );
|
||||||
}
|
}
|
||||||
self->points_list = gc_alloc( 2 * len * sizeof(int), false, false );
|
self->points_list = gc_alloc( 2 * len * sizeof(int), false, false );
|
||||||
|
VECTORIO_POLYGON_DEBUG("alloc(%p, %d)", self->points_list, 2 * len * sizeof(int));
|
||||||
}
|
}
|
||||||
self->len = 2*len;
|
self->len = 2*len;
|
||||||
|
|
||||||
@ -56,22 +58,35 @@ static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple
|
|||||||
|
|
||||||
|
|
||||||
void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list) {
|
void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list) {
|
||||||
VECTORIO_POLYGON_DEBUG("%p polygon_construct\n", self);
|
VECTORIO_POLYGON_DEBUG("%p polygon_construct: ", self);
|
||||||
self->points_list = NULL;
|
self->points_list = NULL;
|
||||||
self->len = 0;
|
self->len = 0;
|
||||||
self->on_dirty.obj = NULL;
|
self->on_dirty.obj = NULL;
|
||||||
_clobber_points_list( self, points_list );
|
_clobber_points_list( self, points_list );
|
||||||
|
VECTORIO_POLYGON_DEBUG("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self) {
|
mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self) {
|
||||||
return self->points_list;
|
VECTORIO_POLYGON_DEBUG("%p common_hal_vectorio_polygon_get_points {len: %d, points_list: %p}\n", self, self->len, self->points_list);
|
||||||
|
mp_obj_t list = mp_obj_new_list(self->len/2, NULL);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < self->len; i += 2) {
|
||||||
|
mp_obj_t tuple[] = { mp_obj_new_int(self->points_list[i]), mp_obj_new_int(self->points_list[i+1]) };
|
||||||
|
mp_obj_list_append(
|
||||||
|
list,
|
||||||
|
mp_obj_new_tuple(2, tuple)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
void common_hal_vectorio_polygon_set_points(vectorio_polygon_t *self, mp_obj_t points_list) {
|
void common_hal_vectorio_polygon_set_points(vectorio_polygon_t *self, mp_obj_t points_list) {
|
||||||
|
VECTORIO_POLYGON_DEBUG("%p common_hal_vectorio_polygon_set_points: ", self);
|
||||||
_clobber_points_list( self, points_list );
|
_clobber_points_list( self, points_list );
|
||||||
if (self->on_dirty.obj != NULL) {
|
if (self->on_dirty.obj != NULL) {
|
||||||
self->on_dirty.event(self->on_dirty.obj);
|
self->on_dirty.event(self->on_dirty.obj);
|
||||||
}
|
}
|
||||||
|
VECTORIO_POLYGON_DEBUG("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_vectorio_polygon_set_on_dirty(vectorio_polygon_t *self, vectorio_event_t notification) {
|
void common_hal_vectorio_polygon_set_on_dirty(vectorio_polygon_t *self, vectorio_event_t notification) {
|
||||||
|
@ -223,8 +223,8 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ
|
|||||||
pixel_to_get_x = (input_pixel.y - self->absolute_transform->dy * self->x - self->absolute_transform->y) / self->absolute_transform->dy;
|
pixel_to_get_x = (input_pixel.y - self->absolute_transform->dy * self->x - self->absolute_transform->y) / self->absolute_transform->dy;
|
||||||
pixel_to_get_y = (input_pixel.x - self->absolute_transform->dx * self->y - self->absolute_transform->x) / self->absolute_transform->dx;
|
pixel_to_get_y = (input_pixel.x - self->absolute_transform->dx * self->y - self->absolute_transform->x) / self->absolute_transform->dx;
|
||||||
} else {
|
} else {
|
||||||
pixel_to_get_x = (input_pixel.x - self->absolute_transform->dx * self->x) / self->absolute_transform->dx;
|
pixel_to_get_x = (input_pixel.x - self->absolute_transform->dx * self->x - self->absolute_transform->x) / self->absolute_transform->dx;
|
||||||
pixel_to_get_y = (input_pixel.y - self->absolute_transform->dy * self->y) / self->absolute_transform->dy;
|
pixel_to_get_y = (input_pixel.y - self->absolute_transform->dy * self->y - self->absolute_transform->y) / self->absolute_transform->dy;
|
||||||
}
|
}
|
||||||
VECTORIO_SHAPE_PIXEL_DEBUG(" get_pixel %p (%3d, %3d) -> ( %3d, %3d )", self->ishape.shape, input_pixel.x, input_pixel.y, pixel_to_get_x, pixel_to_get_y);
|
VECTORIO_SHAPE_PIXEL_DEBUG(" get_pixel %p (%3d, %3d) -> ( %3d, %3d )", self->ishape.shape, input_pixel.x, input_pixel.y, pixel_to_get_x, pixel_to_get_y);
|
||||||
#ifdef VECTORIO_PERF
|
#ifdef VECTORIO_PERF
|
||||||
|
87
supervisor/background_callback.h
Normal file
87
supervisor/background_callback.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H
|
||||||
|
#define CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H
|
||||||
|
|
||||||
|
/** Background callbacks are a linked list of tasks to call in the background.
|
||||||
|
*
|
||||||
|
* Include a member of type `background_callback_t` inside an object
|
||||||
|
* which needs to queue up background work, and zero-initialize it.
|
||||||
|
*
|
||||||
|
* To schedule the work, use background_callback_add, with fun as the
|
||||||
|
* function to call and data pointing to the object itself.
|
||||||
|
*
|
||||||
|
* Next time run_background_tasks_if_tick is called, the callback will
|
||||||
|
* be run and removed from the linked list.
|
||||||
|
*
|
||||||
|
* Queueing a task that is already queued does nothing. Unconditionally
|
||||||
|
* re-queueing it from its own background task will cause it to run during the
|
||||||
|
* very next background-tasks invocation, leading to a CircuitPython freeze, so
|
||||||
|
* don't do that.
|
||||||
|
*
|
||||||
|
* background_callback_add can be called from interrupt context.
|
||||||
|
*/
|
||||||
|
typedef void (*background_callback_fun)(void *data);
|
||||||
|
typedef struct background_callback {
|
||||||
|
background_callback_fun fun;
|
||||||
|
void *data;
|
||||||
|
struct background_callback *next;
|
||||||
|
struct background_callback *prev;
|
||||||
|
} background_callback_t;
|
||||||
|
|
||||||
|
/* Add a background callback for which 'fun' and 'data' were previously set */
|
||||||
|
void background_callback_add_core(background_callback_t *cb);
|
||||||
|
|
||||||
|
/* Add a background callback to the given function with the given data. When
|
||||||
|
* the callback involves an object on the GC heap, the 'data' must be a pointer
|
||||||
|
* to that object itself, not an internal pointer. Otherwise, it can be the
|
||||||
|
* case that no other references to the object itself survive, and the object
|
||||||
|
* becomes garbage collected while an outstanding background callback still
|
||||||
|
* exists.
|
||||||
|
*/
|
||||||
|
void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data);
|
||||||
|
|
||||||
|
/* Run all background callbacks. Normally, this is done by the supervisor
|
||||||
|
* whenever the list is non-empty */
|
||||||
|
void background_callback_run_all(void);
|
||||||
|
|
||||||
|
/* During soft reset, remove all pending callbacks and clear the critical section flag */
|
||||||
|
void background_callback_reset(void);
|
||||||
|
|
||||||
|
/* Sometimes background callbacks must be blocked. Use these functions to
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Background callbacks may stop objects from being collected
|
||||||
|
*/
|
||||||
|
void background_callback_gc_collect(void);
|
||||||
|
|
||||||
|
#endif
|
@ -91,4 +91,12 @@ void port_interrupt_after_ticks(uint32_t ticks);
|
|||||||
// Sleep the CPU until an interrupt is received.
|
// Sleep the CPU until an interrupt is received.
|
||||||
void port_sleep_until_interrupt(void);
|
void port_sleep_until_interrupt(void);
|
||||||
|
|
||||||
|
// Execute port specific actions during background tasks.
|
||||||
|
void port_background_task(void);
|
||||||
|
|
||||||
|
// Take port specific actions at the beginning and end of background tasks.
|
||||||
|
// This is used e.g., to set a monitoring pin for debug purposes. "Actual
|
||||||
|
// work" should be done in port_background_task() instead.
|
||||||
|
void port_start_background_task(void);
|
||||||
|
void port_finish_background_task(void);
|
||||||
#endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H
|
#endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H
|
||||||
|
138
supervisor/shared/background_callback.c
Normal file
138
supervisor/shared/background_callback.c
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 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 <string.h>
|
||||||
|
|
||||||
|
#include "py/gc.h"
|
||||||
|
#include "py/mpconfig.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
|
#include "supervisor/shared/tick.h"
|
||||||
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
|
|
||||||
|
STATIC volatile background_callback_t *callback_head, *callback_tail;
|
||||||
|
|
||||||
|
#define CALLBACK_CRITICAL_BEGIN (common_hal_mcu_disable_interrupts())
|
||||||
|
#define CALLBACK_CRITICAL_END (common_hal_mcu_enable_interrupts())
|
||||||
|
|
||||||
|
void background_callback_add_core(background_callback_t *cb) {
|
||||||
|
CALLBACK_CRITICAL_BEGIN;
|
||||||
|
if (cb->prev || callback_head == cb) {
|
||||||
|
CALLBACK_CRITICAL_END;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cb->next = 0;
|
||||||
|
cb->prev = (background_callback_t*)callback_tail;
|
||||||
|
if (callback_tail) {
|
||||||
|
callback_tail->next = cb;
|
||||||
|
cb->prev = (background_callback_t*)callback_tail;
|
||||||
|
}
|
||||||
|
if (!callback_head) {
|
||||||
|
callback_head = cb;
|
||||||
|
}
|
||||||
|
callback_tail = cb;
|
||||||
|
CALLBACK_CRITICAL_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data) {
|
||||||
|
cb->fun = fun;
|
||||||
|
cb->data = data;
|
||||||
|
background_callback_add_core(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool in_background_callback;
|
||||||
|
void background_callback_run_all() {
|
||||||
|
if (!callback_head) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CALLBACK_CRITICAL_BEGIN;
|
||||||
|
if (in_background_callback) {
|
||||||
|
CALLBACK_CRITICAL_END;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
in_background_callback = true;
|
||||||
|
background_callback_t *cb = (background_callback_t*)callback_head;
|
||||||
|
callback_head = NULL;
|
||||||
|
callback_tail = NULL;
|
||||||
|
while (cb) {
|
||||||
|
background_callback_t *next = cb->next;
|
||||||
|
cb->next = cb->prev = NULL;
|
||||||
|
background_callback_fun fun = cb->fun;
|
||||||
|
void *data = cb->data;
|
||||||
|
CALLBACK_CRITICAL_END;
|
||||||
|
// Leave the critical section in order to run the callback function
|
||||||
|
if (fun) {
|
||||||
|
fun(data);
|
||||||
|
}
|
||||||
|
CALLBACK_CRITICAL_BEGIN;
|
||||||
|
cb = next;
|
||||||
|
}
|
||||||
|
in_background_callback = false;
|
||||||
|
CALLBACK_CRITICAL_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void background_callback_begin_critical_section() {
|
||||||
|
CALLBACK_CRITICAL_BEGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void background_callback_end_critical_section() {
|
||||||
|
CALLBACK_CRITICAL_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void background_callback_reset() {
|
||||||
|
CALLBACK_CRITICAL_BEGIN;
|
||||||
|
background_callback_t *cb = (background_callback_t*)callback_head;
|
||||||
|
while(cb) {
|
||||||
|
background_callback_t *next = cb->next;
|
||||||
|
memset(cb, 0, sizeof(*cb));
|
||||||
|
cb = next;
|
||||||
|
}
|
||||||
|
callback_head = NULL;
|
||||||
|
callback_tail = NULL;
|
||||||
|
in_background_callback = false;
|
||||||
|
CALLBACK_CRITICAL_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void background_callback_gc_collect(void) {
|
||||||
|
// We don't enter the callback critical section here. We rely on
|
||||||
|
// gc_collect_ptr _NOT_ entering background callbacks, so it is not
|
||||||
|
// possible for the list to be cleared.
|
||||||
|
//
|
||||||
|
// However, it is possible for the list to be extended. We make the
|
||||||
|
// minor assumption that no newly added callback is for a
|
||||||
|
// collectable object. That is, we only plug the hole where an
|
||||||
|
// object becomes collectable AFTER it is added but before the
|
||||||
|
// callback is run, not the hole where an object was ALREADY
|
||||||
|
// collectable but adds a background task for itself.
|
||||||
|
//
|
||||||
|
// It's necessary to traverse the whole list here, as the callbacks
|
||||||
|
// themselves can be in non-gc memory, and some of the cb->data
|
||||||
|
// objects themselves might be in non-gc memory.
|
||||||
|
background_callback_t *cb = (background_callback_t*)callback_head;
|
||||||
|
while(cb) {
|
||||||
|
gc_collect_ptr(cb->data);
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
}
|
@ -29,10 +29,19 @@
|
|||||||
#include "py/mpstate.h"
|
#include "py/mpstate.h"
|
||||||
#include "supervisor/linker.h"
|
#include "supervisor/linker.h"
|
||||||
#include "supervisor/filesystem.h"
|
#include "supervisor/filesystem.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/shared/autoreload.h"
|
#include "supervisor/shared/autoreload.h"
|
||||||
|
#include "supervisor/shared/stack.h"
|
||||||
|
|
||||||
static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
|
#if CIRCUITPY_BLEIO
|
||||||
|
#include "supervisor/shared/bluetooth.h"
|
||||||
|
#include "common-hal/_bleio/bonding.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_DISPLAYIO
|
||||||
|
#include "shared-module/displayio/__init__.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_GAMEPAD
|
#if CIRCUITPY_GAMEPAD
|
||||||
#include "shared-module/gamepad/__init__.h"
|
#include "shared-module/gamepad/__init__.h"
|
||||||
@ -42,6 +51,10 @@ static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
|
|||||||
#include "shared-module/gamepadshift/__init__.h"
|
#include "shared-module/gamepadshift/__init__.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_NETWORK
|
||||||
|
#include "shared-module/network/__init__.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "shared-bindings/microcontroller/__init__.h"
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
|
|
||||||
#if CIRCUITPY_WATCHDOG
|
#if CIRCUITPY_WATCHDOG
|
||||||
@ -51,6 +64,44 @@ static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
|
|||||||
#define WATCHDOG_EXCEPTION_CHECK() 0
|
#define WATCHDOG_EXCEPTION_CHECK() 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
|
||||||
|
|
||||||
|
static background_callback_t tick_callback;
|
||||||
|
|
||||||
|
volatile uint64_t last_finished_tick = 0;
|
||||||
|
|
||||||
|
void supervisor_background_tasks(void *unused) {
|
||||||
|
port_start_background_task();
|
||||||
|
|
||||||
|
assert_heap_ok();
|
||||||
|
|
||||||
|
#if CIRCUITPY_DISPLAYIO
|
||||||
|
displayio_background();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_NETWORK
|
||||||
|
network_module_background();
|
||||||
|
#endif
|
||||||
|
filesystem_background();
|
||||||
|
|
||||||
|
#if CIRCUITPY_BLEIO
|
||||||
|
supervisor_bluetooth_background();
|
||||||
|
bonding_background();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
port_background_task();
|
||||||
|
|
||||||
|
assert_heap_ok();
|
||||||
|
|
||||||
|
last_finished_tick = port_get_raw_ticks(NULL);
|
||||||
|
|
||||||
|
port_finish_background_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool supervisor_background_tasks_ok(void) {
|
||||||
|
return port_get_raw_ticks(NULL) - last_finished_tick < 1024;
|
||||||
|
}
|
||||||
|
|
||||||
void supervisor_tick(void) {
|
void supervisor_tick(void) {
|
||||||
#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
|
#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
|
||||||
filesystem_tick();
|
filesystem_tick();
|
||||||
@ -68,6 +119,7 @@ void supervisor_tick(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
background_callback_add(&tick_callback, supervisor_background_tasks, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t supervisor_ticks_ms64() {
|
uint64_t supervisor_ticks_ms64() {
|
||||||
@ -83,14 +135,9 @@ uint32_t supervisor_ticks_ms32() {
|
|||||||
return supervisor_ticks_ms64();
|
return supervisor_ticks_ms64();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void run_background_tasks(void);
|
|
||||||
|
|
||||||
void PLACE_IN_ITCM(supervisor_run_background_tasks_if_tick)() {
|
void PLACE_IN_ITCM(supervisor_run_background_tasks_if_tick)() {
|
||||||
// TODO: Add a global that can be set by anyone to indicate we should run background tasks. That
|
background_callback_run_all();
|
||||||
// way we can short circuit the background tasks early. We used to do it based on time but it
|
|
||||||
// breaks cases where we wake up for a short period and then sleep. If we skipped the last
|
|
||||||
// background task or more before sleeping we may end up starving a task like USB.
|
|
||||||
run_background_tasks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_hal_delay_ms(mp_uint_t delay) {
|
void mp_hal_delay_ms(mp_uint_t delay) {
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#define __INCLUDED_SUPERVISOR_TICK_H
|
#define __INCLUDED_SUPERVISOR_TICK_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/** @brief To be called once every ms
|
/** @brief To be called once every ms
|
||||||
*
|
*
|
||||||
@ -36,13 +37,6 @@
|
|||||||
* interrupt context.
|
* interrupt context.
|
||||||
*/
|
*/
|
||||||
extern void supervisor_tick(void);
|
extern void supervisor_tick(void);
|
||||||
/** @brief Cause background tasks to be called soon
|
|
||||||
*
|
|
||||||
* Normally, background tasks are only run once per tick. For other cases where
|
|
||||||
* an event noticed from an interrupt context needs to be completed by a background
|
|
||||||
* task activity, the interrupt can call supervisor_fake_tick.
|
|
||||||
*/
|
|
||||||
extern void supervisor_fake_tick(void);
|
|
||||||
/** @brief Get the lower 32 bits of the time in milliseconds
|
/** @brief Get the lower 32 bits of the time in milliseconds
|
||||||
*
|
*
|
||||||
* This can be more efficient than supervisor_ticks_ms64, for sites where a wraparound
|
* This can be more efficient than supervisor_ticks_ms64, for sites where a wraparound
|
||||||
@ -67,4 +61,12 @@ extern void supervisor_run_background_if_tick(void);
|
|||||||
extern void supervisor_enable_tick(void);
|
extern void supervisor_enable_tick(void);
|
||||||
extern void supervisor_disable_tick(void);
|
extern void supervisor_disable_tick(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return true if tick-based background tasks ran within the last 1s
|
||||||
|
*
|
||||||
|
* Note that when ticks are not enabled, this function can return false; this is
|
||||||
|
* intended.
|
||||||
|
*/
|
||||||
|
extern bool supervisor_background_tasks_ok(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "py/objstr.h"
|
#include "py/objstr.h"
|
||||||
#include "shared-bindings/microcontroller/Processor.h"
|
#include "shared-bindings/microcontroller/Processor.h"
|
||||||
#include "shared-module/usb_midi/__init__.h"
|
#include "shared-module/usb_midi/__init__.h"
|
||||||
|
#include "supervisor/background_callback.h"
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/usb.h"
|
#include "supervisor/usb.h"
|
||||||
#include "lib/utils/interrupt_char.h"
|
#include "lib/utils/interrupt_char.h"
|
||||||
@ -63,8 +64,8 @@ void usb_init(void) {
|
|||||||
tusb_init();
|
tusb_init();
|
||||||
|
|
||||||
#if MICROPY_KBD_EXCEPTION
|
#if MICROPY_KBD_EXCEPTION
|
||||||
// Set Ctrl+C as wanted char, tud_cdc_rx_wanted_cb() callback will be invoked when Ctrl+C is received
|
// Set Ctrl+C as wanted char, tud_cdc_rx_wanted_cb() usb_callback will be invoked when Ctrl+C is received
|
||||||
// This callback always got invoked regardless of mp_interrupt_char value since we only set it once here
|
// This usb_callback always got invoked regardless of mp_interrupt_char value since we only set it once here
|
||||||
tud_cdc_set_wanted_char(CHAR_CTRL_C);
|
tud_cdc_set_wanted_char(CHAR_CTRL_C);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -82,6 +83,16 @@ void usb_background(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static background_callback_t usb_callback;
|
||||||
|
static void usb_background_do(void* unused) {
|
||||||
|
usb_background();
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_irq_handler(void) {
|
||||||
|
tud_int_handler(0);
|
||||||
|
background_callback_add(&usb_callback, usb_background_do, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// tinyusb callbacks
|
// tinyusb callbacks
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
@ -2,6 +2,7 @@ SRC_SUPERVISOR = \
|
|||||||
main.c \
|
main.c \
|
||||||
supervisor/port.c \
|
supervisor/port.c \
|
||||||
supervisor/shared/autoreload.c \
|
supervisor/shared/autoreload.c \
|
||||||
|
supervisor/shared/background_callback.c \
|
||||||
supervisor/shared/board.c \
|
supervisor/shared/board.c \
|
||||||
supervisor/shared/filesystem.c \
|
supervisor/shared/filesystem.c \
|
||||||
supervisor/shared/flash.c \
|
supervisor/shared/flash.c \
|
||||||
|
@ -29,10 +29,15 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// Ports must call this as frequently as they can in order to keep the USB connection
|
// Ports must call this as frequently as they can in order to keep the USB
|
||||||
// alive and responsive.
|
// connection alive and responsive. Normally this is called from background
|
||||||
|
// tasks after the USB IRQ handler is executed, but in specific circumstances
|
||||||
|
// it may be necessary to call it directly.
|
||||||
void usb_background(void);
|
void usb_background(void);
|
||||||
|
|
||||||
|
// Ports must call this from their particular USB IRQ handler
|
||||||
|
void usb_irq_handler(void);
|
||||||
|
|
||||||
// Only inits the USB peripheral clocks and pins. The peripheral will be initialized by
|
// Only inits the USB peripheral clocks and pins. The peripheral will be initialized by
|
||||||
// TinyUSB.
|
// TinyUSB.
|
||||||
void init_usb_hardware(void);
|
void init_usb_hardware(void);
|
||||||
|
@ -6,24 +6,91 @@
|
|||||||
# You can also test a specific library in shared-bindings by putting the path
|
# You can also test a specific library in shared-bindings by putting the path
|
||||||
# to that directory instead
|
# to that directory instead
|
||||||
|
|
||||||
|
import ast
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import astroid
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
top_level = sys.argv[1].strip("/")
|
import isort
|
||||||
stub_directory = sys.argv[2]
|
|
||||||
|
|
||||||
|
IMPORTS_IGNORE = frozenset({'int', 'float', 'bool', 'str', 'bytes', 'tuple', 'list', 'set', 'dict', 'bytearray', 'file', 'buffer'})
|
||||||
|
IMPORTS_TYPING = frozenset({'Any', 'Optional', 'Union', 'Tuple', 'List', 'Sequence'})
|
||||||
|
IMPORTS_TYPESHED = frozenset({'ReadableBuffer', 'WritableBuffer'})
|
||||||
|
|
||||||
|
|
||||||
|
def is_any(node):
|
||||||
|
node_type = type(node)
|
||||||
|
if node is None:
|
||||||
|
return True
|
||||||
|
if node_type == ast.Name and node.id == "Any":
|
||||||
|
return True
|
||||||
|
if (node_type == ast.Attribute and type(node.value) == ast.Name
|
||||||
|
and node.value.id == "typing" and node.attr == "Any"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def report_missing_annotations(tree):
|
||||||
|
for node in ast.walk(tree):
|
||||||
|
node_type = type(node)
|
||||||
|
if node_type == ast.AnnAssign:
|
||||||
|
if is_any(node.annotation):
|
||||||
|
print(f"Missing attribute type on line {node.lineno}")
|
||||||
|
elif node_type == ast.arg:
|
||||||
|
if is_any(node.annotation) and node.arg != "self":
|
||||||
|
print(f"Missing argument type: {node.arg} on line {node.lineno}")
|
||||||
|
elif node_type == ast.FunctionDef:
|
||||||
|
if is_any(node.returns) and node.name != "__init__":
|
||||||
|
print(f"Missing return type: {node.name} on line {node.lineno}")
|
||||||
|
|
||||||
|
|
||||||
|
def extract_imports(tree):
|
||||||
|
modules = set()
|
||||||
|
typing = set()
|
||||||
|
typeshed = set()
|
||||||
|
|
||||||
|
def collect_annotations(anno_tree):
|
||||||
|
if anno_tree is None:
|
||||||
|
return
|
||||||
|
for node in ast.walk(anno_tree):
|
||||||
|
node_type = type(node)
|
||||||
|
if node_type == ast.Name:
|
||||||
|
if node.id in IMPORTS_IGNORE:
|
||||||
|
continue
|
||||||
|
elif node.id in IMPORTS_TYPING:
|
||||||
|
typing.add(node.id)
|
||||||
|
elif node.id in IMPORTS_TYPESHED:
|
||||||
|
typeshed.add(node.id)
|
||||||
|
elif not node.id[0].isupper():
|
||||||
|
modules.add(node.id)
|
||||||
|
|
||||||
|
for node in ast.walk(tree):
|
||||||
|
node_type = type(node)
|
||||||
|
if (node_type == ast.AnnAssign) or (node_type == ast.arg):
|
||||||
|
collect_annotations(node.annotation)
|
||||||
|
elif node_type == ast.FunctionDef:
|
||||||
|
collect_annotations(node.returns)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"modules": sorted(modules),
|
||||||
|
"typing": sorted(typing),
|
||||||
|
"typeshed": sorted(typeshed),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def convert_folder(top_level, stub_directory):
|
def convert_folder(top_level, stub_directory):
|
||||||
ok = 0
|
ok = 0
|
||||||
total = 0
|
total = 0
|
||||||
filenames = sorted(os.listdir(top_level))
|
filenames = sorted(os.listdir(top_level))
|
||||||
pyi_lines = []
|
pyi_lines = []
|
||||||
|
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
full_path = os.path.join(top_level, filename)
|
full_path = os.path.join(top_level, filename)
|
||||||
file_lines = []
|
file_lines = []
|
||||||
if os.path.isdir(full_path):
|
if os.path.isdir(full_path):
|
||||||
mok, mtotal = convert_folder(full_path, os.path.join(stub_directory, filename))
|
(mok, mtotal) = convert_folder(full_path, os.path.join(stub_directory, filename))
|
||||||
ok += mok
|
ok += mok
|
||||||
total += mtotal
|
total += mtotal
|
||||||
elif filename.endswith(".c"):
|
elif filename.endswith(".c"):
|
||||||
@ -48,51 +115,57 @@ def convert_folder(top_level, stub_directory):
|
|||||||
pyi_lines.extend(file_lines)
|
pyi_lines.extend(file_lines)
|
||||||
|
|
||||||
if not pyi_lines:
|
if not pyi_lines:
|
||||||
return ok, total
|
return (ok, total)
|
||||||
|
|
||||||
stub_filename = os.path.join(stub_directory, "__init__.pyi")
|
stub_filename = os.path.join(stub_directory, "__init__.pyi")
|
||||||
print(stub_filename)
|
print(stub_filename)
|
||||||
stub_contents = "".join(pyi_lines)
|
stub_contents = "".join(pyi_lines)
|
||||||
os.makedirs(stub_directory, exist_ok=True)
|
|
||||||
with open(stub_filename, "w") as f:
|
|
||||||
f.write(stub_contents)
|
|
||||||
|
|
||||||
# Validate that the module is a parseable stub.
|
# Validate that the module is a parseable stub.
|
||||||
total += 1
|
total += 1
|
||||||
try:
|
try:
|
||||||
tree = astroid.parse(stub_contents)
|
tree = ast.parse(stub_contents)
|
||||||
for i in tree.body:
|
imports = extract_imports(tree)
|
||||||
if 'name' in i.__dict__:
|
report_missing_annotations(tree)
|
||||||
print()
|
|
||||||
print(i.__dict__['name'])
|
|
||||||
for j in i.body:
|
|
||||||
if isinstance(j, astroid.scoped_nodes.FunctionDef):
|
|
||||||
for k, l in zip(j.args.__dict__['annotations'], j.args.__dict__['args']):
|
|
||||||
# K is type, l is name
|
|
||||||
if l.name != 'self':
|
|
||||||
if not k:
|
|
||||||
print(f"Missing parameter type: {j.__dict__['name']} on line {j.__dict__['lineno']}")
|
|
||||||
elif str(type(k)) == "<class 'astroid.node_classes.Name'>":
|
|
||||||
if k.name == 'Any':
|
|
||||||
print(f"'Any' parameter type: {j.__dict__['name']} on line {j.__dict__['lineno']}")
|
|
||||||
if j.returns:
|
|
||||||
if 'Any' in j.returns.__dict__.values():
|
|
||||||
print(f"Missing return type: {j.__dict__['name']} on line {j.__dict__['lineno']}")
|
|
||||||
elif isinstance(j, astroid.node_classes.AnnAssign):
|
|
||||||
if 'name' in j.__dict__['annotation'].__dict__:
|
|
||||||
if j.__dict__['annotation'].__dict__['name'] == 'Any':
|
|
||||||
print(f"missing attribute type: {j.__dict__['target'].name} on line {j.__dict__['lineno']}")
|
|
||||||
|
|
||||||
ok += 1
|
ok += 1
|
||||||
except astroid.exceptions.AstroidSyntaxError as e:
|
except SyntaxError as e:
|
||||||
e = e.__cause__
|
|
||||||
traceback.print_exception(type(e), e, e.__traceback__)
|
traceback.print_exception(type(e), e, e.__traceback__)
|
||||||
|
return (ok, total)
|
||||||
|
|
||||||
|
# Add import statements
|
||||||
|
import_lines = ["from __future__ import annotations"]
|
||||||
|
import_lines.extend(f"import {m}" for m in imports["modules"])
|
||||||
|
import_lines.append("from typing import " + ", ".join(imports["typing"]))
|
||||||
|
import_lines.append("from _typeshed import " + ", ".join(imports["typeshed"]))
|
||||||
|
import_body = "\n".join(import_lines)
|
||||||
|
m = re.match(r'(\s*""".*?""")', stub_contents, flags=re.DOTALL)
|
||||||
|
if m:
|
||||||
|
stub_contents = m.group(1) + "\n\n" + import_body + "\n\n" + stub_contents[m.end():]
|
||||||
|
else:
|
||||||
|
stub_contents = import_body + "\n\n" + stub_contents
|
||||||
|
stub_contents = isort.code(stub_contents)
|
||||||
|
|
||||||
|
# Adjust blank lines
|
||||||
|
stub_contents = re.sub(r"\n+class", "\n\n\nclass", stub_contents)
|
||||||
|
stub_contents = re.sub(r"\n+def", "\n\n\ndef", stub_contents)
|
||||||
|
stub_contents = re.sub(r"\n+^(\s+)def", lambda m: f"\n\n{m.group(1)}def", stub_contents, flags=re.M)
|
||||||
|
stub_contents = stub_contents.strip() + "\n"
|
||||||
|
|
||||||
|
os.makedirs(stub_directory, exist_ok=True)
|
||||||
|
with open(stub_filename, "w") as f:
|
||||||
|
f.write(stub_contents)
|
||||||
|
|
||||||
print()
|
print()
|
||||||
return ok, total
|
return (ok, total)
|
||||||
|
|
||||||
ok, total = convert_folder(top_level, stub_directory)
|
|
||||||
|
|
||||||
print(f"{ok} ok out of {total}")
|
if __name__ == "__main__":
|
||||||
|
top_level = sys.argv[1].strip("/")
|
||||||
|
stub_directory = sys.argv[2]
|
||||||
|
|
||||||
if ok != total:
|
(ok, total) = convert_folder(top_level, stub_directory)
|
||||||
|
|
||||||
|
print(f"Parsing .pyi files: {total - ok} failed, {ok} passed")
|
||||||
|
|
||||||
|
if ok != total:
|
||||||
sys.exit(total - ok)
|
sys.exit(total - ok)
|
||||||
|
Loading…
Reference in New Issue
Block a user