summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordherrada <33632497+dherrada@users.noreply.github.com>2020-07-21 16:18:51 -0400
committerGitHub <noreply@github.com>2020-07-21 16:18:51 -0400
commit9e3fa863f1d0dcf8eae54554ffc7016eaa6de157 (patch)
tree5130e268b1fad9dec287e93e3505a5a9a61a9249
parent612c6bb86b8762aa9388566eb69db9bbe4e8bbe4 (diff)
parente047ea287f6658f1a1fd10ab31f45f25bce846c1 (diff)
Merge branch 'main' into type_hints
-rw-r--r--.github/workflows/build.yml2
m---------frozen/circuitpython-stage0
-rwxr-xr-xmain.c7
-rw-r--r--ports/atmel-samd/audio_dma.c54
-rw-r--r--ports/atmel-samd/audio_dma.h2
-rw-r--r--ports/atmel-samd/background.c52
-rw-r--r--ports/atmel-samd/background.h5
-rw-r--r--ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.mk2
-rwxr-xr-xports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk2
-rw-r--r--ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk1
-rw-r--r--ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk22
-rw-r--r--ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk2
-rw-r--r--ports/atmel-samd/boards/uchip/mpconfigboard.mk7
-rw-r--r--ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk5
-rw-r--r--ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/bhb.c120
-rw-r--r--ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/micropython.mk6
-rw-r--r--ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk1
-rw-r--r--ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c3
-rw-r--r--ports/atmel-samd/common-hal/pulseio/PulseIn.c3
-rw-r--r--ports/atmel-samd/mpconfigport.mk3
-rw-r--r--ports/atmel-samd/supervisor/usb.c12
-rw-r--r--ports/cxd56/background.c24
-rw-r--r--ports/cxd56/background.h3
-rw-r--r--ports/esp32s2/background.c23
-rw-r--r--ports/esp32s2/background.h3
-rw-r--r--ports/litex/background.c32
-rw-r--r--ports/litex/background.h5
-rw-r--r--ports/litex/mphalport.c3
-rw-r--r--ports/mimxrt10xx/background.c53
-rw-r--r--ports/mimxrt10xx/background.h7
-rw-r--r--ports/mimxrt10xx/common-hal/pulseio/PulseIn.c2
-rw-r--r--ports/mimxrt10xx/supervisor/usb.c3
-rw-r--r--ports/nrf/background.c28
-rw-r--r--ports/nrf/background.h5
-rw-r--r--ports/nrf/boards/particle_argon/mpconfigboard.mk4
-rw-r--r--ports/nrf/boards/particle_boron/mpconfigboard.mk4
-rw-r--r--ports/nrf/boards/particle_xenon/mpconfigboard.mk4
-rw-r--r--ports/nrf/common-hal/microcontroller/__init__.c44
-rw-r--r--ports/nrf/supervisor/port.c13
-rw-r--r--ports/nrf/supervisor/usb.c7
-rw-r--r--ports/stm/background.c28
-rw-r--r--ports/stm/background.h5
-rw-r--r--ports/stm/supervisor/usb.c2
-rw-r--r--py/mpz.c4
-rw-r--r--shared-bindings/network/__init__.c3
-rw-r--r--shared-bindings/socket/__init__.c3
-rw-r--r--shared-bindings/vectorio/Polygon.c15
-rw-r--r--shared-bindings/wiznet/__init__.c7
-rw-r--r--shared-module/audiomp3/MP3Decoder.c54
-rw-r--r--shared-module/audiomp3/MP3Decoder.h2
-rw-r--r--shared-module/displayio/Display.c12
-rw-r--r--shared-module/displayio/EPaperDisplay.c4
-rw-r--r--shared-module/displayio/__init__.c4
-rw-r--r--shared-module/framebufferio/FramebufferDisplay.c17
-rw-r--r--shared-module/framebufferio/FramebufferDisplay.h1
-rw-r--r--shared-module/vectorio/Polygon.c21
-rw-r--r--shared-module/vectorio/VectorShape.c4
-rw-r--r--supervisor/background_callback.h87
-rw-r--r--supervisor/port.h8
-rw-r--r--supervisor/shared/background_callback.c138
-rw-r--r--supervisor/shared/tick.c65
-rw-r--r--supervisor/shared/tick.h16
-rw-r--r--supervisor/shared/usb/usb.c15
-rw-r--r--supervisor/supervisor.mk1
-rw-r--r--supervisor/usb.h9
-rw-r--r--tools/extract_pyi.py149
66 files changed, 811 insertions, 441 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d5ccfb71c..d809ba8cb 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -37,7 +37,7 @@ jobs:
run: |
sudo apt-get install -y eatmydata
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
run: |
gcc --version
diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage
-Subproject 0d2c083a2fb57a1562d4806775f45273abbfbfa
+Subproject 9596a5904ed757e6fbffcf03e7aa77ae9ecf522
diff --git a/main.c b/main.c
index c3787122d..f928d0d62 100755
--- a/main.c
+++ b/main.c
@@ -45,6 +45,7 @@
#include "background.h"
#include "mpconfigboard.h"
+#include "supervisor/background_callback.h"
#include "supervisor/cpu.h"
#include "supervisor/memory.h"
#include "supervisor/port.h"
@@ -100,8 +101,6 @@ void start_mp(supervisor_allocation* heap) {
reset_status_led();
autoreload_stop();
- background_tasks_reset();
-
// Stack limit should be less than real stack size, so we have a chance
// to recover from limit hit. (Limit is measured in bytes.)
mp_stack_ctrl_init();
@@ -161,6 +160,8 @@ void stop_mp(void) {
MP_STATE_VM(vfs_cur) = vfs;
#endif
+ background_callback_reset();
+
gc_deinit();
}
@@ -492,6 +493,8 @@ void gc_collect(void) {
// 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));
+ background_callback_gc_collect();
+
#if CIRCUITPY_DISPLAYIO
displayio_gc_collect();
#endif
diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c
index 93cd96b98..c6c636160 100644
--- a/ports/atmel-samd/audio_dma.c
+++ b/ports/atmel-samd/audio_dma.c
@@ -31,7 +31,7 @@
#include "shared-bindings/audiocore/RawSample.h"
#include "shared-bindings/audiocore/WaveFile.h"
-#include "supervisor/shared/tick.h"
+#include "supervisor/background_callback.h"
#include "py/mpstate.h"
#include "py/runtime.h"
@@ -61,7 +61,6 @@ void audio_dma_free_channel(uint8_t channel) {
assert(audio_dma_allocated[channel]);
audio_dma_disable_channel(channel);
audio_dma_allocated[channel] = false;
- supervisor_disable_tick();
}
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) {
if (channel >= AUDIO_DMA_CHANNEL_COUNT)
return;
- supervisor_enable_tick();
dma_enable_channel(channel);
}
@@ -259,6 +257,15 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma,
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);
setup_audio_descriptor(first_descriptor, dma->beat_size, output_spacing, output_register_address);
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);
audio_dma_enable_channel(dma_channel);
+ NVIC_EnableIRQ(irq);
+
return AUDIO_DMA_OK;
}
@@ -321,9 +330,6 @@ void audio_dma_reset(void) {
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
audio_dma_state[i] = NULL;
audio_dma_pending[i] = false;
- if (audio_dma_allocated[i]) {
- supervisor_disable_tick();
- }
audio_dma_allocated[i] = false;
audio_dma_disable_channel(i);
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;
}
-// WARN(tannewt): DO NOT print from here. Printing calls background tasks such as this and causes a
-// stack overflow.
+// WARN(tannewt): DO NOT print from here, or anything it calls. Printing calls
+// background tasks such as this and causes a stack overflow.
+STATIC void dma_callback_fun(void *arg) {
+ audio_dma_t* dma = arg;
+ if (dma == NULL) {
+ return;
+ }
+
+ audio_dma_load_next_block(dma);
+}
-void audio_dma_background(void) {
+void evsyshandler_common(void) {
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
- if (audio_dma_pending[i]) {
- continue;
- }
audio_dma_t* dma = audio_dma_state[i];
if (dma == NULL) {
continue;
}
-
bool block_done = event_interrupt_active(dma->event_channel);
if (!block_done) {
continue;
}
-
- // 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;
+ background_callback_add(&dma->callback, dma_callback_fun, (void*)dma);
}
}
+
+#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
diff --git a/ports/atmel-samd/audio_dma.h b/ports/atmel-samd/audio_dma.h
index 1ebec6f7e..4fffd06b8 100644
--- a/ports/atmel-samd/audio_dma.h
+++ b/ports/atmel-samd/audio_dma.h
@@ -31,6 +31,7 @@
#include "py/obj.h"
#include "shared-module/audiocore/RawSample.h"
#include "shared-module/audiocore/WaveFile.h"
+#include "supervisor/background_callback.h"
typedef struct {
mp_obj_t sample;
@@ -49,6 +50,7 @@ typedef struct {
uint8_t* second_buffer;
bool first_descriptor_free;
DmacDescriptor* second_descriptor;
+ background_callback_t callback;
} audio_dma_t;
typedef enum {
diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c
index 767c7f3b6..62c233a3f 100644
--- a/ports/atmel-samd/background.c
+++ b/ports/atmel-samd/background.c
@@ -39,63 +39,21 @@
#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;
-
#ifdef MONITOR_BACKGROUND_TASKS
// PB03 is physical pin "SCL" on the Metro M4 express
// so you can't use this code AND an i2c peripheral
// 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_OUTSET1 = (1<<3);
}
-STATIC void finish_background_task(void) {
+void port_finish_background_task(void) {
REG_PORT_OUTCLR1 = (1<<3);
}
#else
-STATIC void start_background_task(void) {}
-STATIC void finish_background_task(void) {}
+void port_start_background_task(void) {}
+void port_finish_background_task(void) {}
#endif
-void background_tasks_reset(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;
-}
+void port_background_task(void) {}
diff --git a/ports/atmel-samd/background.h b/ports/atmel-samd/background.h
index d9866a6ab..2a89c3b1b 100644
--- a/ports/atmel-samd/background.h
+++ b/ports/atmel-samd/background.h
@@ -29,9 +29,4 @@
#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
diff --git a/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.mk b/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.mk
index 28b1434fb..34301da3f 100644
--- a/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/aloriumtech_evo_m51/mpconfigboard.mk
@@ -13,6 +13,4 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1
EXTERNAL_FLASH_DEVICES = GD25Q16C
LONGINT_IMPL = MPZ
-CIRCUITPY_NETWORK = 1
-MICROPY_PY_WIZNET5K = 5500
CIRCUITPY_PS2IO = 1
diff --git a/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk b/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk
index 7a9e5a780..13ae59de4 100755
--- a/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/circuitbrains_deluxe_m4/mpconfigboard.mk
@@ -11,6 +11,4 @@ EXTERNAL_FLASH_DEVICE_COUNT = 2
EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, S25FL064L"
LONGINT_IMPL = MPZ
-CIRCUITPY_NETWORK = 1
-MICROPY_PY_WIZNET5K = 5500
CIRCUITPY_PS2IO = 1
diff --git a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk
index febd2a6c3..9c7fe3398 100644
--- a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk
@@ -13,7 +13,6 @@ LONGINT_IMPL = MPZ
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_DISPLAYIO = 0
-CIRCUITPY_NETWORK = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_PS2IO = 0
CIRCUITPY_AUDIOMP3 = 0
diff --git a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk
index b6490433e..e0adc11b0 100644
--- a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk
@@ -10,38 +10,32 @@ INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = NONE
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_AUDIOPWMIO = 0
+CIRCUITPY_AUDIOMP3 = 0
CIRCUITPY_BITBANGIO = 0
+CIRCUITPY_BITBANG_APA102 = 0
CIRCUITPY_FREQUENCYIO = 0
+CIRCUITPY_GAMEPADSHIFT = 0
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_NEOPIXEL_WRITE = 0
-CIRCUITPY_NETWORK = 0
CIRCUITPY_PIXELBUF = 0
CIRCUITPY_PS2IO = 0
+CIRCUITPY_ROTARYIO = 0
CIRCUITPY_RTC = 0
+CIRCUITPY_SAMD = 0
CIRCUITPY_TOUCHIO = 0
CIRCUITPY_USB_HID = 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_ANALOGIO = 1
CIRCUITPY_AUDIOMIXER = 1
CIRCUITPY_AUDIOIO = 1
CIRCUITPY_DISPLAYIO = 1
CIRCUITPY_GAMEPAD = 1
-CIRCUITPY_STAGE = 1
CIRCUITPY_MATH = 1
+CIRCUITPY_STAGE = 1
FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pewpew_m4
CIRCUITPY_DISPLAY_FONT = $(TOP)/ports/atmel-samd/boards/ugame10/brutalist-6.bdf
diff --git a/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk
index 13863e565..567f1db20 100644
--- a/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/sparkfun_samd51_thing_plus/mpconfigboard.mk
@@ -12,6 +12,4 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1
EXTERNAL_FLASH_DEVICES = AT25SF041A
LONGINT_IMPL = MPZ
-CIRCUITPY_NETWORK = 1
-MICROPY_PY_WIZNET5K = 5500
CIRCUITPY_PS2IO = 1
diff --git a/ports/atmel-samd/boards/uchip/mpconfigboard.mk b/ports/atmel-samd/boards/uchip/mpconfigboard.mk
index 90b5600dc..196068a1e 100644
--- a/ports/atmel-samd/boards/uchip/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/uchip/mpconfigboard.mk
@@ -9,3 +9,10 @@ CHIP_FAMILY = samd21
INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = NONE
CIRCUITPY_FULL_BUILD = 0
+
+# Tweak inlining depending on language.
+ifeq ($(TRANSLATION), zh_Latn_pinyin)
+CFLAGS_INLINE_LIMIT = 45
+else
+CFLAGS_INLINE_LIMIT = 70
+endif
diff --git a/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk b/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk
index e06a2af7e..71586d6e0 100644
--- a/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk
@@ -24,10 +24,13 @@ CIRCUITPY_BLEIO = 0
CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_GAMEPAD = 0
CIRCUITPY_I2CPERIPHERAL = 0
-CIRCUITPY_NETWORK = 0
CIRCUITPY_TOUCHIO = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_PS2IO = 0
CIRCUITPY_USB_HID = 0
CIRCUITPY_USB_MIDI = 0
CIRCUITPY_RTC = 0
+
+# Enable board-specific modules
+USER_C_MODULES = boards/winterbloom_big_honking_button/usermods
+CFLAGS += -DMODULE_BHB_ENABLED=1
diff --git a/ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/bhb.c b/ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/bhb.c
new file mode 100644
index 000000000..54ce173d8
--- /dev/null
+++ b/ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/bhb.c
@@ -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);
diff --git a/ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/micropython.mk b/ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/micropython.mk
new file mode 100644
index 000000000..9374ec34e
--- /dev/null
+++ b/ports/atmel-samd/boards/winterbloom_big_honking_button/usermods/_bhb/micropython.mk
@@ -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)
diff --git a/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk b/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk
index 11592073f..9217cdf23 100644
--- a/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk
+++ b/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk
@@ -23,7 +23,6 @@ CIRCUITPY_DISPLAYIO = 0
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_GAMEPAD = 0
CIRCUITPY_I2CPERIPHERAL = 0
-CIRCUITPY_NETWORK = 0
CIRCUITPY_TOUCHIO = 0
CIRCUITPY_RGBMATRIX = 0
CIRCUITPY_PS2IO = 0
diff --git a/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c b/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
index 1952df563..02d0482dc 100644
--- a/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
+++ b/ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
@@ -46,6 +46,7 @@
#include "hpl_gclk_config.h"
#include "shared-bindings/time/__init__.h"
+#include "supervisor/shared/tick.h"
#include "supervisor/shared/translate.h"
#ifdef SAMD21
@@ -132,7 +133,7 @@ void frequencyin_interrupt_handler(uint8_t index) {
}
// 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;
frequencyin_emergency_cancel_capture(i);
}
diff --git a/ports/atmel-samd/common-hal/pulseio/PulseIn.c b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
index b825579db..ae58b089d 100644
--- a/ports/atmel-samd/common-hal/pulseio/PulseIn.c
+++ b/ports/atmel-samd/common-hal/pulseio/PulseIn.c
@@ -42,6 +42,7 @@
#include "samd/timers.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/pulseio/PulseIn.h"
+#include "supervisor/shared/tick.h"
#include "supervisor/shared/translate.h"
// 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;
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;
common_hal_pulseio_pulsein_pause(self);
return;
diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk
index face79fad..e4cf9ca83 100644
--- a/ports/atmel-samd/mpconfigport.mk
+++ b/ports/atmel-samd/mpconfigport.mk
@@ -54,8 +54,7 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0
# The ifndef's allow overriding in mpconfigboard.mk.
ifndef CIRCUITPY_NETWORK
-CIRCUITPY_NETWORK = 1
-MICROPY_PY_WIZNET5K = 5500
+CIRCUITPY_NETWORK = 0
endif
ifndef CIRCUITPY_PS2IO
diff --git a/ports/atmel-samd/supervisor/usb.c b/ports/atmel-samd/supervisor/usb.c
index 650ed6a39..ea940f898 100644
--- a/ports/atmel-samd/supervisor/usb.c
+++ b/ports/atmel-samd/supervisor/usb.c
@@ -29,6 +29,8 @@
#include "hpl/gclk/hpl_gclk_base.h"
#include "hal_gpio.h"
#include "lib/tinyusb/src/device/usbd.h"
+#include "supervisor/background_callback.h"
+#include "supervisor/usb.h"
void init_usb_hardware(void) {
#ifdef SAMD21
@@ -61,24 +63,24 @@ void init_usb_hardware(void) {
#ifdef SAMD21
void USB_Handler(void) {
- tud_int_handler(0);
+ usb_irq_handler();
}
#endif
#ifdef SAM_D5X_E5X
void USB_0_Handler (void) {
- tud_int_handler(0);
+ usb_irq_handler();
}
void USB_1_Handler (void) {
- tud_int_handler(0);
+ usb_irq_handler();
}
void USB_2_Handler (void) {
- tud_int_handler(0);
+ usb_irq_handler();
}
void USB_3_Handler (void) {
- tud_int_handler(0);
+ usb_irq_handler();
}
#endif
diff --git a/ports/cxd56/background.c b/ports/cxd56/background.c
index ade257dd2..6de6d7275 100644
--- a/ports/cxd56/background.c
+++ b/ports/cxd56/background.c
@@ -30,24 +30,6 @@
#include "supervisor/filesystem.h"
#include "supervisor/shared/stack.h"
-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;
- }
-
- assert_heap_ok();
- running_background_tasks = true;
-
- usb_background();
- filesystem_background();
-
- running_background_tasks = false;
- assert_heap_ok();
-}
+void port_background_task(void) {}
+void port_start_background_task(void) {}
+void port_finish_background_task(void) {}
diff --git a/ports/cxd56/background.h b/ports/cxd56/background.h
index a38e3faed..5f76e6442 100644
--- a/ports/cxd56/background.h
+++ b/ports/cxd56/background.h
@@ -27,7 +27,4 @@
#ifndef 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
diff --git a/ports/esp32s2/background.c b/ports/esp32s2/background.c
index a90fa7d0a..40ce9ecfd 100644
--- a/ports/esp32s2/background.c
+++ b/ports/esp32s2/background.c
@@ -35,27 +35,12 @@
#include "shared-module/displayio/__init__.h"
#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.
vTaskDelay(0);
- running_background_tasks = true;
- filesystem_background();
+}
- #if CIRCUITPY_DISPLAYIO
- displayio_background();
- #endif
- running_background_tasks = false;
+void port_start_background_task(void) {}
- assert_heap_ok();
-}
+void port_finish_background_task(void) {}
diff --git a/ports/esp32s2/background.h b/ports/esp32s2/background.h
index 0e1fb7a56..cb850d4e5 100644
--- a/ports/esp32s2/background.h
+++ b/ports/esp32s2/background.h
@@ -29,7 +29,4 @@
#include <stdbool.h>
-void background_tasks_reset(void);
-void run_background_tasks(void);
-
#endif // MICROPY_INCLUDED_ESP32S2_BACKGROUND_H
diff --git a/ports/litex/background.c b/ports/litex/background.c
index 8c1897043..174d9588a 100644
--- a/ports/litex/background.c
+++ b/ports/litex/background.c
@@ -29,32 +29,6 @@
#include "supervisor/usb.h"
#include "supervisor/shared/stack.h"
-#if CIRCUITPY_DISPLAYIO
-#include "shared-module/displayio/__init__.h"
-#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;
- }
- 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();
-}
+void port_background_task(void) {}
+void port_start_background_task(void) {}
+void port_finish_background_task(void) {}
diff --git a/ports/litex/background.h b/ports/litex/background.h
index 09551c7fb..c80fbbe5c 100644
--- a/ports/litex/background.h
+++ b/ports/litex/background.h
@@ -27,9 +27,4 @@
#ifndef 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
diff --git a/ports/litex/mphalport.c b/ports/litex/mphalport.c
index 84a546795..862f16393 100644
--- a/ports/litex/mphalport.c
+++ b/ports/litex/mphalport.c
@@ -31,6 +31,7 @@
#include "py/mphal.h"
#include "py/mpstate.h"
#include "py/gc.h"
+#include "supervisor/usb.h"
#include "csr.h"
#include "generated/soc.h"
@@ -49,7 +50,7 @@ void isr(void) {
#ifdef CFG_TUSB_MCU
if (irqs & (1 << USB_INTERRUPT))
- tud_int_handler(0);
+ usb_irq_handler();
#endif
if (irqs & (1 << TIMER0_INTERRUPT))
SysTick_Handler();
diff --git a/ports/mimxrt10xx/background.c b/ports/mimxrt10xx/background.c
index ff53ea44f..a8a613d41 100644
--- a/ports/mimxrt10xx/background.c
+++ b/ports/mimxrt10xx/background.c
@@ -24,58 +24,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "background.h"
-//#include "audio_dma.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;
+#include "supervisor/port.h"
+void port_background_task(void) {
#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 = 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) {}
diff --git a/ports/mimxrt10xx/background.h b/ports/mimxrt10xx/background.h
index 52789d038..a3fe102ac 100644
--- a/ports/mimxrt10xx/background.h
+++ b/ports/mimxrt10xx/background.h
@@ -28,11 +28,4 @@
#ifndef 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
diff --git a/ports/mimxrt10xx/common-hal/pulseio/PulseIn.c b/ports/mimxrt10xx/common-hal/pulseio/PulseIn.c
index d8bf2017e..ec0290861 100644
--- a/ports/mimxrt10xx/common-hal/pulseio/PulseIn.c
+++ b/ports/mimxrt10xx/common-hal/pulseio/PulseIn.c
@@ -64,7 +64,7 @@
// // last ms.
// current_us = 1000 - current_us;
// 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;
// common_hal_pulseio_pulsein_pause(self);
// return;
diff --git a/ports/mimxrt10xx/supervisor/usb.c b/ports/mimxrt10xx/supervisor/usb.c
index 1bc7ea9b5..af259405a 100644
--- a/ports/mimxrt10xx/supervisor/usb.c
+++ b/ports/mimxrt10xx/supervisor/usb.c
@@ -27,6 +27,7 @@
#include "fsl_clock.h"
#include "tusb.h"
+#include "supervisor/usb.h"
void init_usb_hardware(void) {
CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
@@ -56,5 +57,5 @@ void init_usb_hardware(void) {
}
void USB_OTG1_IRQHandler(void) {
- tud_int_handler(0);
+ usb_irq_handler();
}
diff --git a/ports/nrf/background.c b/ports/nrf/background.c
index 966c56e0b..10543ddb2 100644
--- a/ports/nrf/background.c
+++ b/ports/nrf/background.c
@@ -46,36 +46,14 @@
#include "common-hal/_bleio/bonding.h"
#endif
-static bool running_background_tasks = false;
+void port_start_background_task(void) {}
+void port_finish_background_task(void) {}
-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();
- usb_background();
+void port_background_task(void) {
#if CIRCUITPY_AUDIOPWMIO
audiopwmout_background();
#endif
#if CIRCUITPY_AUDIOBUSIO
i2s_background();
#endif
-
-#if CIRCUITPY_BLEIO
- supervisor_bluetooth_background();
- bonding_background();
-#endif
-
- #if CIRCUITPY_DISPLAYIO
- displayio_background();
- #endif
- running_background_tasks = false;
-
- assert_heap_ok();
}
diff --git a/ports/nrf/background.h b/ports/nrf/background.h
index d53681c0f..64a768cf9 100644
--- a/ports/nrf/background.h
+++ b/ports/nrf/background.h
@@ -27,9 +27,4 @@
#ifndef 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
diff --git a/ports/nrf/boards/particle_argon/mpconfigboard.mk b/ports/nrf/boards/particle_argon/mpconfigboard.mk
index 2ca08b982..f8d3d2aca 100644
--- a/ports/nrf/boards/particle_argon/mpconfigboard.mk
+++ b/ports/nrf/boards/particle_argon/mpconfigboard.mk
@@ -8,7 +8,3 @@ MCU_CHIP = nrf52840
QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICE_COUNT = 1
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
-
-# Support for the Ethernet FeatherWing
-CIRCUITPY_NETWORK = 1
-MICROPY_PY_WIZNET5K = 5500
diff --git a/ports/nrf/boards/particle_boron/mpconfigboard.mk b/ports/nrf/boards/particle_boron/mpconfigboard.mk
index f03f43a7b..eada97a73 100644
--- a/ports/nrf/boards/particle_boron/mpconfigboard.mk
+++ b/ports/nrf/boards/particle_boron/mpconfigboard.mk
@@ -8,7 +8,3 @@ MCU_CHIP = nrf52840
QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICE_COUNT = 1
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
-
-# Support for the Ethernet FeatherWing
-CIRCUITPY_NETWORK = 1
-MICROPY_PY_WIZNET5K = 5500
diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.mk b/ports/nrf/boards/particle_xenon/mpconfigboard.mk
index 44309bbca..6062da378 100644
--- a/ports/nrf/boards/particle_xenon/mpconfigboard.mk
+++ b/ports/nrf/boards/particle_xenon/mpconfigboard.mk
@@ -8,7 +8,3 @@ MCU_CHIP = nrf52840
QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICE_COUNT = 1
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
-
-# Support for the Ethernet FeatherWing
-CIRCUITPY_NETWORK = 1
-MICROPY_PY_WIZNET5K = 5500
diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c
index f5caf68ef..06aac9409 100644
--- a/ports/nrf/common-hal/microcontroller/__init__.c
+++ b/ports/nrf/common-hal/microcontroller/__init__.c
@@ -50,36 +50,34 @@ void common_hal_mcu_delay_us(uint32_t delay) {
static volatile uint32_t nesting_count = 0;
static uint8_t is_nested_critical_region;
-static uint8_t sd_is_enabled = false;
void common_hal_mcu_disable_interrupts() {
- sd_softdevice_is_enabled(&sd_is_enabled);
- if (sd_is_enabled) {
+ if (nesting_count == 0) {
+ // 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);
- } else {
- __disable_irq();
- __DMB();
- nesting_count++;
}
+ __DMB();
+ nesting_count++;
}
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) {
- // This is very very bad because it means there was mismatched disable/enables so we
- // crash.
- reset_into_safe_mode(HARD_CRASH);
- }
- nesting_count--;
- if (nesting_count > 0) {
- return;
- }
- __DMB();
- __enable_irq();
+ if (nesting_count == 0) {
+ // This is very very bad because it means there was mismatched disable/enables so we
+ // crash.
+ reset_into_safe_mode(HARD_CRASH);
}
+ nesting_count--;
+ if (nesting_count > 0) {
+ return;
+ }
+ __DMB();
+ sd_nvic_critical_region_exit(is_nested_critical_region);
}
void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c
index aee2d63e1..e681e6825 100644
--- a/ports/nrf/supervisor/port.c
+++ b/ports/nrf/supervisor/port.c
@@ -313,12 +313,21 @@ void port_sleep_until_interrupt(void) {
// instruction will returned as long as an interrupt is
// available, even though the actual handler won't fire until
// 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()) {
__DSB();
__WFI();
}
- common_hal_mcu_enable_interrupts();
+ if (!nested) {
+ __enable_irq();
+ }
}
}
diff --git a/ports/nrf/supervisor/usb.c b/ports/nrf/supervisor/usb.c
index 3d2527faa..771e86ce0 100644
--- a/ports/nrf/supervisor/usb.c
+++ b/ports/nrf/supervisor/usb.c
@@ -30,6 +30,7 @@
#include "lib/utils/interrupt_char.h"
#include "lib/mp-readline/readline.h"
#include "lib/tinyusb/src/device/usbd.h"
+#include "supervisor/background_callback.h"
#ifdef SOFTDEVICE_PRESENT
#include "nrf_sdm.h"
@@ -42,7 +43,9 @@ extern void tusb_hal_nrf_power_event(uint32_t event);
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);
// 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) {
- tud_int_handler(0);
+ usb_irq_handler();
}
diff --git a/ports/stm/background.c b/ports/stm/background.c
index 8c1897043..d83a0ccec 100644
--- a/ports/stm/background.c
+++ b/ports/stm/background.c
@@ -33,28 +33,6 @@
#include "shared-module/displayio/__init__.h"
#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;
- }
- 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();
-}
+void port_background_task(void) {}
+void port_start_background_task(void) {}
+void port_finish_background_task(void) {}
diff --git a/ports/stm/background.h b/ports/stm/background.h
index 6225429f8..e57aa40dd 100644
--- a/ports/stm/background.h
+++ b/ports/stm/background.h
@@ -27,9 +27,4 @@
#ifndef 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
diff --git a/ports/stm/supervisor/usb.c b/ports/stm/supervisor/usb.c
index 3dd0acafd..3d53fa374 100644
--- a/ports/stm/supervisor/usb.c
+++ b/ports/stm/supervisor/usb.c
@@ -130,5 +130,5 @@ void init_usb_hardware(void) {
}
void OTG_FS_IRQHandler(void) {
- tud_int_handler(0);
+ usb_irq_handler();
}
diff --git a/py/mpz.c b/py/mpz.c
index 7800cdcc4..41b46f92f 100644
--- a/py/mpz.c
+++ b/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;
+ // check to prevent usb starvation
+ #ifdef RUN_BACKGROUND_TASKS
+ RUN_BACKGROUND_TASKS;
+ #endif
}
return ilen;
diff --git a/shared-bindings/network/__init__.c b/shared-bindings/network/__init__.c
index c6cc33bf7..35bbaa510 100644
--- a/shared-bindings/network/__init__.c
+++ b/shared-bindings/network/__init__.c
@@ -40,6 +40,9 @@
//| """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.
//| It is used by the 'socket' module to look up a suitable
//| NIC when a socket is created."""
diff --git a/shared-bindings/socket/__init__.c b/shared-bindings/socket/__init__.c
index 413940f6d..a2007edf6 100644
--- a/shared-bindings/socket/__init__.c
+++ b/shared-bindings/socket/__init__.c
@@ -39,6 +39,9 @@
//| """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."""
//|
diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c
index 486619eae..b5c9d1c42 100644
--- a/shared-bindings/vectorio/Polygon.c
+++ b/shared-bindings/vectorio/Polygon.c
@@ -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) {
vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
- mp_obj_t list = mp_obj_new_list(0, NULL);
-
- 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;
+ return common_hal_vectorio_polygon_get_points(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_points_obj, vectorio_polygon_obj_get_points);
diff --git a/shared-bindings/wiznet/__init__.c b/shared-bindings/wiznet/__init__.c
index bc7ff150f..8df06b546 100644
--- a/shared-bindings/wiznet/__init__.c
+++ b/shared-bindings/wiznet/__init__.c
@@ -35,7 +35,12 @@
#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;
diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c
index 30357c616..5f3f42a51 100644
--- a/shared-module/audiomp3/MP3Decoder.c
+++ b/shared-module/audiomp3/MP3Decoder.c
@@ -36,11 +36,12 @@
#include "shared-module/audiomp3/MP3Decoder.h"
#include "supervisor/shared/translate.h"
+#include "supervisor/background_callback.h"
#include "lib/mp3/src/mp3common.h"
#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,
* 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
*/
-STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
- // If buffer is over half full, do nothing
- if (self->inbuf_offset < self->inbuf_length/2) return true;
-
+STATIC bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t* self) {
// If we didn't previously reach the end of file, we can try reading now
if (!self->eof) {
@@ -87,6 +85,26 @@ STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
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 BYTES_LEFT(self) (self->inbuf_length - self->inbuf_offset)
#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/id3v2.3.0
STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
- mp3file_update_inbuf(self);
+ mp3file_update_inbuf_half(self);
if (BYTES_LEFT(self) < 10) {
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) {
do {
- mp3file_update_inbuf(self);
+ mp3file_update_inbuf_half(self);
int offset = MP3FindSyncWord(READ_PTR(self), BYTES_LEFT(self));
if (offset >= 0) {
CONSUME(self, offset);
- mp3file_update_inbuf(self);
+ mp3file_update_inbuf_half(self);
return true;
}
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) {
+ background_callback_begin_critical_section();
+
self->file = file;
f_lseek(&self->file->fp, 0);
self->inbuf_offset = self->inbuf_length;
self->eof = 0;
self->other_channel = -1;
- mp3file_update_inbuf(self);
+ mp3file_update_inbuf_half(self);
mp3file_find_sync_word(self);
// 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
@@ -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[1], 0, MAX_BUFFER_LEN);
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,
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
// loads
+ background_callback_begin_critical_section();
f_lseek(&self->file->fp, 0);
self->inbuf_offset = self->inbuf_length;
self->eof = 0;
self->other_channel = -1;
- mp3file_update_inbuf(self);
+ mp3file_update_inbuf_half(self);
mp3file_skip_id3v2(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,
@@ -321,6 +345,14 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
uint8_t *inbuf = READ_PTR(self);
int err = MP3Decode(self->decoder, &inbuf, &bytes_left, buffer, 0);
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) {
return GET_BUFFER_DONE;
}
diff --git a/shared-module/audiomp3/MP3Decoder.h b/shared-module/audiomp3/MP3Decoder.h
index 9ee1d0949..f91f102a2 100644
--- a/shared-module/audiomp3/MP3Decoder.h
+++ b/shared-module/audiomp3/MP3Decoder.h
@@ -28,6 +28,7 @@
#ifndef 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 "py/obj.h"
@@ -36,6 +37,7 @@
typedef struct {
mp_obj_base_t base;
struct _MP3DecInfo *decoder;
+ background_callback_t inbuf_fill_cb;
uint8_t* inbuf;
uint32_t inbuf_length;
uint32_t inbuf_offset;
diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c
index a3d877f1a..46bb6fdb5 100644
--- a/shared-module/displayio/Display.c
+++ b/shared-module/displayio/Display.c
@@ -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
// initialization.
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) {
@@ -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,
bool 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;
}
@@ -409,6 +416,7 @@ void displayio_display_background(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);
#if (CIRCUITPY_PULSEIO)
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) {
- self->auto_refresh = true;
+ common_hal_displayio_display_set_auto_refresh(self, true);
self->auto_brightness = true;
common_hal_displayio_display_show(self, NULL);
}
diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c
index 6a55687b9..6d9e915b4 100644
--- a/shared-module/displayio/EPaperDisplay.c
+++ b/shared-module/displayio/EPaperDisplay.c
@@ -187,6 +187,7 @@ void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self)
displayio_display_core_begin_transaction(&self->core);
self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1);
displayio_display_core_end_transaction(&self->core);
+ supervisor_enable_tick();
self->refreshing = true;
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 (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) {
+ supervisor_disable_tick();
self->refreshing = false;
// 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);
@@ -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;
}
if (refresh_done) {
+ supervisor_disable_tick();
self->refreshing = false;
// 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);
@@ -352,6 +355,7 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) {
void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) {
if (self->refreshing) {
wait_for_busy(self);
+ supervisor_disable_tick();
self->refreshing = false;
// 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);
diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c
index c898bbb98..efc28470f 100644
--- a/shared-module/displayio/__init__.c
+++ b/shared-module/displayio/__init__.c
@@ -190,9 +190,7 @@ void reset_displays(void) {
common_hal_displayio_epaperdisplay_show(display, NULL);
#if CIRCUITPY_FRAMEBUFFERIO
} else if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) {
- framebufferio_framebufferdisplay_obj_t* display = &displays[i].framebuffer_display;
- display->auto_refresh = true;
- common_hal_framebufferio_framebufferdisplay_show(display, NULL);
+ framebufferio_framebufferdisplay_reset(&displays[i].framebuffer_display);
#endif
}
}
diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c
index f296da409..2a90fa0d4 100644
--- a/shared-module/framebufferio/FramebufferDisplay.c
+++ b/shared-module/framebufferio/FramebufferDisplay.c
@@ -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
// initialization.
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) {
@@ -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,
bool 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;
}
@@ -297,12 +304,13 @@ void framebufferio_framebufferdisplay_background(framebufferio_framebufferdispla
}
void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) {
+ common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, false);
release_display_core(&self->core);
self->framebuffer_protocol->deinit(self->framebuffer);
}
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);
}
@@ -310,3 +318,8 @@ void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisp
gc_collect_ptr(self->framebuffer);
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);
+}
diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h
index 1b68d2ab0..ca1ab984a 100644
--- a/shared-module/framebufferio/FramebufferDisplay.h
+++ b/shared-module/framebufferio/FramebufferDisplay.h
@@ -55,6 +55,7 @@ typedef struct {
void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self);
void release_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);
diff --git a/shared-module/vectorio/Polygon.c b/shared-module/vectorio/Polygon.c
index 0025d4bfc..c44c13fd7 100644
--- a/shared-module/vectorio/Polygon.c
+++ b/shared-module/vectorio/Polygon.c
@@ -20,7 +20,7 @@ static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple
size_t len = 0;
mp_obj_t *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 ) {
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->points_list != NULL ) {
+ VECTORIO_POLYGON_DEBUG("free(%d), ", sizeof(self->points_list));
gc_free( self->points_list );
}
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;
@@ -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) {
- VECTORIO_POLYGON_DEBUG("%p polygon_construct\n", self);
+ VECTORIO_POLYGON_DEBUG("%p polygon_construct: ", self);
self->points_list = NULL;
self->len = 0;
self->on_dirty.obj = NULL;
_clobber_points_list( self, points_list );
+ VECTORIO_POLYGON_DEBUG("\n");
}
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) {
+ VECTORIO_POLYGON_DEBUG("%p common_hal_vectorio_polygon_set_points: ", self);
_clobber_points_list( self, points_list );
if (self->on_dirty.obj != NULL) {
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) {
diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c
index bfe8a7b25..81f46b3fa 100644
--- a/shared-module/vectorio/VectorShape.c
+++ b/shared-module/vectorio/VectorShape.c
@@ -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_y = (input_pixel.x - self->absolute_transform->dx * self->y - self->absolute_transform->x) / self->absolute_transform->dx;
} else {
- pixel_to_get_x = (input_pixel.x - self->absolute_transform->dx * self->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_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->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);
#ifdef VECTORIO_PERF
diff --git a/supervisor/background_callback.h b/supervisor/background_callback.h
new file mode 100644
index 000000000..535dd656b
--- /dev/null
+++ b/supervisor/background_callback.h
@@ -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
diff --git a/supervisor/port.h b/supervisor/port.h
index 8a12d34c8..ad5b3cf32 100644
--- a/supervisor/port.h
+++ b/supervisor/port.h
@@ -91,4 +91,12 @@ void port_interrupt_after_ticks(uint32_t ticks);
// Sleep the CPU until an interrupt is received.
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
diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c
new file mode 100644
index 000000000..8e12dd362
--- /dev/null
+++ b/supervisor/shared/background_callback.c
@@ -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;
+ }
+}
diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c
index dd7dba8f3..4af59f78e 100644
--- a/supervisor/shared/tick.c
+++ b/supervisor/shared/tick.c
@@ -29,10 +29,19 @@
#include "py/mpstate.h"
#include "supervisor/linker.h"
#include "supervisor/filesystem.h"
+#include "supervisor/background_callback.h"
#include "supervisor/port.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
#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"
#endif
+#if CIRCUITPY_NETWORK
+#include "shared-module/network/__init__.h"
+#endif
+
#include "shared-bindings/microcontroller/__init__.h"
#if CIRCUITPY_WATCHDOG
@@ -51,6 +64,44 @@ static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
#define WATCHDOG_EXCEPTION_CHECK() 0
#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) {
#if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0
filesystem_tick();
@@ -68,6 +119,7 @@ void supervisor_tick(void) {
#endif
}
#endif
+ background_callback_add(&tick_callback, supervisor_background_tasks, NULL);
}
uint64_t supervisor_ticks_ms64() {
@@ -83,14 +135,9 @@ uint32_t supervisor_ticks_ms32() {
return supervisor_ticks_ms64();
}
-extern void run_background_tasks(void);
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
- // 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();
+ background_callback_run_all();
}
void mp_hal_delay_ms(mp_uint_t delay) {
@@ -104,13 +151,13 @@ void mp_hal_delay_ms(mp_uint_t delay) {
// Check to see if we've been CTRL-Ced by autoreload or the user.
if(MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)))
{
- // clear exception and generate stacktrace
+ // clear exception and generate stacktrace
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(&MP_STATE_VM(mp_kbd_exception));
}
if( MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception)) ||
WATCHDOG_EXCEPTION_CHECK()) {
- // stop sleeping immediately
+ // stop sleeping immediately
break;
}
remaining = end_tick - port_get_raw_ticks(NULL);
diff --git a/supervisor/shared/tick.h b/supervisor/shared/tick.h
index e7e808058..3a01bd622 100644
--- a/supervisor/shared/tick.h
+++ b/supervisor/shared/tick.h
@@ -28,6 +28,7 @@
#define __INCLUDED_SUPERVISOR_TICK_H
#include <stdint.h>
+#include <stdbool.h>
/** @brief To be called once every ms
*
@@ -36,13 +37,6 @@
* interrupt context.
*/
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
*
* 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_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
diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c
index edf810118..36b5ec05d 100644
--- a/supervisor/shared/usb/usb.c
+++ b/supervisor/shared/usb/usb.c
@@ -27,6 +27,7 @@
#include "py/objstr.h"
#include "shared-bindings/microcontroller/Processor.h"
#include "shared-module/usb_midi/__init__.h"
+#include "supervisor/background_callback.h"
#include "supervisor/port.h"
#include "supervisor/usb.h"
#include "lib/utils/interrupt_char.h"
@@ -63,8 +64,8 @@ void usb_init(void) {
tusb_init();
#if MICROPY_KBD_EXCEPTION
- // Set Ctrl+C as wanted char, tud_cdc_rx_wanted_cb() 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
+ // Set Ctrl+C as wanted char, tud_cdc_rx_wanted_cb() usb_callback will be invoked when Ctrl+C is received
+ // 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);
#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
//--------------------------------------------------------------------+
diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk
index 21803ae0a..188536686 100644
--- a/supervisor/supervisor.mk
+++ b/supervisor/supervisor.mk
@@ -2,6 +2,7 @@ SRC_SUPERVISOR = \
main.c \
supervisor/port.c \
supervisor/shared/autoreload.c \
+ supervisor/shared/background_callback.c \
supervisor/shared/board.c \
supervisor/shared/filesystem.c \
supervisor/shared/flash.c \
diff --git a/supervisor/usb.h b/supervisor/usb.h
index 29280c725..2a447c368 100644
--- a/supervisor/usb.h
+++ b/supervisor/usb.h
@@ -29,10 +29,15 @@
#include <stdbool.h>
-// Ports must call this as frequently as they can in order to keep the USB connection
-// alive and responsive.
+// Ports must call this as frequently as they can in order to keep the USB
+// 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);
+// 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
// TinyUSB.
void init_usb_hardware(void);
diff --git a/tools/extract_pyi.py b/tools/extract_pyi.py
index f9c91c786..ab223877e 100644
--- a/tools/extract_pyi.py
+++ b/tools/extract_pyi.py
@@ -6,24 +6,91 @@
# You can also test a specific library in shared-bindings by putting the path
# to that directory instead
+import ast
import os
+import re
import sys
-import astroid
import traceback
-top_level = sys.argv[1].strip("/")
-stub_directory = sys.argv[2]
+import isort
+
+
+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):
ok = 0
total = 0
filenames = sorted(os.listdir(top_level))
pyi_lines = []
+
for filename in filenames:
full_path = os.path.join(top_level, filename)
file_lines = []
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
total += mtotal
elif filename.endswith(".c"):
@@ -48,51 +115,57 @@ def convert_folder(top_level, stub_directory):
pyi_lines.extend(file_lines)
if not pyi_lines:
- return ok, total
+ return (ok, total)
stub_filename = os.path.join(stub_directory, "__init__.pyi")
print(stub_filename)
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.
total += 1
try:
- tree = astroid.parse(stub_contents)
- for i in tree.body:
- if 'name' in i.__dict__:
- 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']}")
-
+ tree = ast.parse(stub_contents)
+ imports = extract_imports(tree)
+ report_missing_annotations(tree)
ok += 1
- except astroid.exceptions.AstroidSyntaxError as e:
- e = e.__cause__
+ except SyntaxError as e:
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()
- return ok, total
+ return (ok, total)
+
+
+if __name__ == "__main__":
+ top_level = sys.argv[1].strip("/")
+ stub_directory = sys.argv[2]
-ok, total = convert_folder(top_level, stub_directory)
+ (ok, total) = convert_folder(top_level, stub_directory)
-print(f"{ok} ok out of {total}")
+ print(f"Parsing .pyi files: {total - ok} failed, {ok} passed")
-if ok != total:
- sys.exit(total - ok)
+ if ok != total:
+ sys.exit(total - ok)