30 Commits

Author SHA1 Message Date
e4422b860e rp2: Fix stacks for multicore operation
Unfortunately, no way to override this from board config.
2025-03-23 19:11:24 +01:00
0f26771a44 rp2: Modify linker script to run MP3 decoder from RAM 2025-03-04 22:57:09 +01:00
Mike Bell
29275e2c58 rp2/rp2_flash: Workaround multicore lockout not being reset.
With regression test.

See upstream bug https://github.com/raspberrypi/pico-sdk/issues/2201

Tested-by: Angus Gratton <angus@redyak.com.au>
Signed-off-by: Mike Bell <mdb036@gmail.com>
2025-03-04 20:12:18 +01:00
Damien George
732c2989c5 lib/pico-sdk: Update to version 2.1.1.
Release notes: https://github.com/raspberrypi/pico-sdk/releases/tag/2.1.1

Signed-off-by: Damien George <damien@micropython.org>
2025-03-04 19:49:20 +01:00
Peter Harper
ef5c3c043c rp2/mphalport: Add mp_hal_is_pin_reserved() function.
As cyw43 pins might be dynamic, add a function that returns if a pin is
reserved.  This is used by `MICROPY_HW_PIN_RESERVED` to prevent the pin IRQ
from being reset across a soft-reset.

Signed-off-by: Peter Harper <peter.harper@raspberrypi.com>
2025-03-04 19:41:59 +01:00
Peter Harper
ba21be5215 rp2/cyw43_configport: Define cyw43 pins.
The cyw43 pins used to be hardcoded and `CYW43_PIN_WL_HOST_WAKE` and
`CYW43_PIN_WL_REG_ON` were in the `pico_w.h` board header.

This has been changed so the board header just defines the "default
version of the pins, e.g. `CYW43_DEFAULT_PIN_WL_HOST_WAKE`,
`CYW43_DEFAULT_PIN_WL_REG_ON` etc.

Set the pin values in `cyw43_configport.`h so `cyw43-driver` sees them and
allow them to be changed at runtime (dynamic) if required.

Signed-off-by: Peter Harper <peter.harper@raspberrypi.com>
2025-03-04 19:40:17 +01:00
Phil Howard
8ba7af3a70 rp2/CMakeLists.txt: Add components required by bootrom.h.
Signed-off-by: Peter Harper <peter.harper@raspberrypi.com>
2025-03-04 19:38:19 +01:00
Peter Harper
08513e1a32 lib/pico-sdk: Update to version 2.1.0.
Brings in support for Pico 2 W, among other things.

Signed-off-by: Peter Harper <peter.harper@raspberrypi.com>
2025-03-04 19:38:19 +01:00
Damien George
ecfdd5d6f9 all: Bump version to 1.24.1.
Signed-off-by: Damien George <damien@micropython.org>
2024-11-29 23:53:11 +11:00
Angus Gratton
564ef28ad2 py/objfloat: Workaround non-constant NAN definition on Windows MSVC.
Recent MSVC versions have changed the definition of NAN to a non-constant
expression!  This is a bug, C standard says it should be a constant.

Good explanation and workaround at: https://stackoverflow.com/a/79199887

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-28 23:56:21 +11:00
robert-hh
7118942a8c nrf/drivers/ticker: Reset slow ticker callback count on soft reboot.
The micro:bit board (and probably other boards using the music or display
module) locked up on soft reboot.  Reason was a buffer overflow caused by
an index counter, which was not reset on soft_reboot.

That's fixed in this commit.  Tested with a micro:bit board, performing a
series of soft reboots.

Signed-off-by: robert-hh <robert@hammelrath.com>
2024-11-28 23:08:33 +11:00
Corran Webster
948863c0b8 extmod/modframebuf: Fix 0 radius bug in FrameBuffer.ellipse.
This fixes a bug in FrameBuffer.ellipse where it goes into an infinite loop
if both radii are 0.

This fixes the bug with a simple pre-check to see if both radii are 0, and
in that case sets a single pixel at the center. This is consistent with the
behaviour of the method when called with just one of the radii set to 0,
where it will draw a horizontal or vertical line of 1 pixel width.

The pixel is set with setpixel_checked so it should handle out-of-bounds
drawing correctly.

This fix also includes three new tests: one for the default behaviour, one
for drawing out-of-bounds, and one for when the sector mask is 0.

Fixes issue #16053.

Signed-off-by: Corran Webster <cwebster@unital.dev>
2024-11-28 23:08:29 +11:00
Angus Gratton
33f50d4f20 esp32: Fix machine.TouchPad startup on ESP32-S2 and S3.
Closes #13178.

TouchPad confirmed working on both chips, and fixes the the ESP32-S3
reading constant max value. Was unable to reproduce the bug on ESP32-S2 but
this may be due to my test setup, and it still works with the fix.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-28 23:08:26 +11:00
Angus Gratton
eb0027b82f esp32: Use hardware version for touchpad macro defines.
ESP32 has hardware V1 and S2/S3 has V2, and future chips
may have different versions.

This should still compile to the same binary before and after.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-28 23:08:22 +11:00
Angus Gratton
03bc561edb esp32: Fix setting WLAN channel in AP mode.
- Previously the call to esp_wifi_set_channel() would be immediately
  overridden by calling esp_wifi_config(...) with the previous channel set.

- AP interface doesn't seem to need more than esp_wifi_config(...) to work.
  It will automatically configure 40MHz bandwidth and place the secondary
  channel using similar logic to what was being explicitly calculated here.

- However, calling esp_wifi_set_channel() on the STA interface is necessary
  if using this interface with ESP-NOW (without connecting to an AP). So
  the esp_wifi_set_channel() call is kept in for this purpose. Without
  this, tests/multi_espnow/70_channel.py fails.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-28 23:08:18 +11:00
Angus Gratton
49b83ed44a extmod/network_cyw43: Allow configuring active AP interface.
Configuring the AP for cyw43 writes to some buffers that are only sent to
the modem when the interface is brought up. This means you can't configure
the AP after calling active(True), the new settings seem to be accepted but
the radio doesn't change.

This is different to the WLAN behaviour on other ports. The esp8266 port
requires calling active(True) on the AP before configuring, even.

Fix this by bouncing the AP interface after a config change, if it's
active. Configuring with active(False) still works the same as before.

Adds a static variable to track interface active state, rather than relying
on the LWIP interface state. This is because the interface state is updated
by a driver callback and there's a race: if code calls active(True) and
then config(a=b) then the driver doesn't know it's active yet and the
changes aren't correctly applied.

It is possible this pattern will cause the AP to come up briefly with the
default "PICOabcd" SSID before being reconfigured, however (due to the
aforementioned race condition) it seems like this may not happen at all
before the new config is applied.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-20 14:44:53 +11:00
Damien George
4f4d683ea5 extmod/network_cyw43: Fix uninitialised variable in status('stations').
The `num_stas` was uninitialised and if it happened to take the value 0
then no results were returned.  It now has the correct maximum value.

Signed-off-by: Damien George <damien@micropython.org>
2024-11-20 14:27:16 +11:00
Angus Gratton
67f893852a extmod/network_cyw43: Fix isconnected() result on AP interface.
This function is documented to return True if any stations are connected to
the AP. Without this fix it returns True whenever the driver has brought
the AP interface up.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-20 14:27:11 +11:00
Damien George
20a6d82872 extmod/vfs_blockdev: Support bool return from Python read/write blocks.
Commit f4ab9d9247 inadvertently broke some
Python block devices, for example esp32 and stm32 SDCard classes.  Those
classes return a bool from their `readblocks` and `writeblocks` methods
instead of an integer errno code.  With that change, both `False` and
`True` return values are now be interpreted as non-zero and hence the block
device call fails.

The fix in this commit is to allow a bool and explicitly convert `True` to
0 and `False` to `-MP_EIO`.

Signed-off-by: Damien George <damien@micropython.org>
2024-11-18 23:27:13 +11:00
Damien George
0c580f71ae esp32/modsocket: Fix getaddrinfo hints to set AI_CANONNAME.
Because the `ai_canonname` field is subsequently used.

ESP32_GENERIC_S3 (at least) crashes with IDF 5.2.3 without this set.

Signed-off-by: Damien George <damien@micropython.org>
2024-11-18 23:27:13 +11:00
Damien George
4e78c611b4 tools/mpremote: Support trailing slash on dest for non-recursive copy.
This fixes a regression in db59e55fe7: prior
to that commit `mpremote` supported trailing slashes on the destination of
a normal (non-recursive) copy.

Add back support for that, with the semantics that a trailing slash
requires the destination to be an existing directory.

Also add a test for this.

Signed-off-by: Damien George <damien@micropython.org>
2024-11-18 23:27:13 +11:00
Damien George
159b54b7da tools/mpremote: Add test for forced copy.
Signed-off-by: Damien George <damien@micropython.org>
2024-11-18 23:27:13 +11:00
Damien George
c1a85bb6de tools/mpremote: Make sure stdout and stderr output appear in order.
mpremote error messages now go to stderr, so make sure stdout is flushed
before printing them.

Also update the test runner to capture error messages.

Signed-off-by: Damien George <damien@micropython.org>
2024-11-18 23:27:13 +11:00
Angus Gratton
72799f9973 esp32: Workaround native code execution crash on ESP32-S2.
Seemingly ESP-IDF incorrectly marks RTC FAST memory region
as MALLOC_CAP_EXEC on ESP32-S2 when it isn't. This memory is
the lowest priority, so it only is returned if D/IRAM is exhausted.

Apply this workaround to treat the allocation as failed if it gives us
non-executable RAM back, rather than crashing.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-18 23:27:13 +11:00
Angus Gratton
164c549248 esp32/machine_pwm: Restore PWM support for ESP-IDF v5.0.x and v5.1.x.
The cleanup in 548babf8 relies on some functions not available in older
ESP-IDF. Temporarily restore them, until we drop support for ESP-IDF <5.2.

PWM functionality should end up the same regardless of ESP-IDF version, and
also no different from MicroPython V1.23.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2024-11-18 23:27:13 +11:00
Damien George
6f327684b7 extmod/modlwip: Fix IGMP address type when IPv6 is enabled.
This was missed in 628abf8f25.  The the bug
was that, when IPv6 is enabled, the `sizeof(ip_addr_t)` is much larger than
IPv4 size, which is what's needed for IGMP addressing.

Fixes issue #16100.

Signed-off-by: Damien George <damien@micropython.org>
2024-11-18 23:27:13 +11:00
Jan Sturm
a7d3bc2308 py/objdeque: Fix buffer overflow in deque_subscr.
In `deque_subscr()`, if `index_val` equals `self->alloc`, the index
correction `index_val -= self->alloc` does not execute, leading to an
out-of-bounds access in `self->items[index_val]`.

The fix in this commit ensures that the index correction is applied
whenever `index_val >= self->alloc`, preventing access beyond the allocated
buffer size.

Signed-off-by: Jan Sturm <jansturm92@googlemail.com>
2024-11-18 23:27:13 +11:00
Alessandro Gatti
c0afff8f22 pic16bit: Make it build with recent XC16 versions.
The PIC16 port didn't catch up with the other ports, so it required a bit
of work to make it build with the latest version of XC16.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
2024-11-18 23:27:13 +11:00
Andrew Leech
785c92df76 esp32/machine_pwm: Use IDF functions to calculate resolution correctly.
This commit fixes PWM configuration across C3, C6, S2 and S3 chips, which
was broken by 6d799378ba.  Without this fix
the PWM frequency is limited to a maximum of 2446Hz (on S2 at least).

Signed-off-by: Andrew Leech <andrew@alelec.net>
2024-11-18 23:27:13 +11:00
Glenn Moloney
5c7ac55232 tools/mpremote: Fix UnboundLocalError in Transport.fs_writefile().
The variable `written` was being used before it was defined in the
`fs_writefile()` method of the Transport class.  This was causing an
`UnboundLocalError` to be raised when the `progress_callback` was not
provided.

Fixes issue #16084.

Signed-off-by: Glenn Moloney <glenn.moloney@gmail.com>
2024-11-18 23:27:13 +11:00
36 changed files with 452 additions and 91 deletions

View File

@@ -536,6 +536,10 @@ static mp_obj_t framebuf_ellipse(size_t n_args, const mp_obj_t *args_in) {
} else {
mask |= ELLIPSE_MASK_ALL;
}
if (args[2] == 0 && args[3] == 0) {
setpixel_checked(self, args[0], args[1], args[4], mask & ELLIPSE_MASK_ALL);
return mp_const_none;
}
mp_int_t two_asquare = 2 * args[2] * args[2];
mp_int_t two_bsquare = 2 * args[3] * args[3];
mp_int_t x = args[2];

View File

@@ -1432,7 +1432,7 @@ static mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
case IP_DROP_MEMBERSHIP: {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
if (bufinfo.len != sizeof(ip_addr_t) * 2) {
if (bufinfo.len != sizeof(MP_IGMP_IP_ADDR_TYPE) * 2) {
mp_raise_ValueError(NULL);
}

View File

@@ -60,6 +60,10 @@ typedef struct _network_cyw43_obj_t {
static const network_cyw43_obj_t network_cyw43_wl_sta = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_STA };
static const network_cyw43_obj_t network_cyw43_wl_ap = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_AP };
// Avoid race conditions with callbacks by tracking the last up or down request
// we have made for each interface.
static bool if_active[2];
static void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
struct netif *netif = &self->cyw->netif[self->itf];
@@ -122,6 +126,10 @@ static MP_DEFINE_CONST_FUN_OBJ_3(network_cyw43_ioctl_obj, network_cyw43_ioctl);
/*******************************************************************************/
// network API
static uint32_t get_country_code(void) {
return CYW43_COUNTRY(mod_network_country_code[0], mod_network_country_code[1], 0);
}
static mp_obj_t network_cyw43_deinit(mp_obj_t self_in) {
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
cyw43_deinit(self->cyw);
@@ -132,10 +140,11 @@ static MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_deinit_obj, network_cyw43_deinit)
static mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) {
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (n_args == 1) {
return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf));
return mp_obj_new_bool(if_active[self->itf]);
} else {
uint32_t country = CYW43_COUNTRY(mod_network_country_code[0], mod_network_country_code[1], 0);
cyw43_wifi_set_up(self->cyw, self->itf, mp_obj_is_true(args[1]), country);
bool value = mp_obj_is_true(args[1]);
cyw43_wifi_set_up(self->cyw, self->itf, value, get_country_code());
if_active[self->itf] = value;
return mp_const_none;
}
}
@@ -311,7 +320,17 @@ static MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_disconnect_obj, network_cyw43_dis
static mp_obj_t network_cyw43_isconnected(mp_obj_t self_in) {
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf) == 3);
bool result = (cyw43_tcpip_link_status(self->cyw, self->itf) == CYW43_LINK_UP);
if (result && self->itf == CYW43_ITF_AP) {
// For AP we need to not only know if the link is up, but also if any stations
// have associated.
uint8_t mac_buf[6];
int num_stas = 1;
cyw43_wifi_ap_get_stas(self->cyw, &num_stas, mac_buf);
result = num_stas > 0;
}
return mp_obj_new_bool(result);
}
static MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_isconnected_obj, network_cyw43_isconnected);
@@ -351,13 +370,15 @@ static mp_obj_t network_cyw43_status(size_t n_args, const mp_obj_t *args) {
if (self->itf != CYW43_ITF_AP) {
mp_raise_ValueError(MP_ERROR_TEXT("AP required"));
}
int num_stas;
uint8_t macs[32 * 6];
static const unsigned mac_len = 6;
static const unsigned max_stas = 32;
int num_stas = max_stas;
uint8_t macs[max_stas * mac_len];
cyw43_wifi_ap_get_stas(self->cyw, &num_stas, macs);
mp_obj_t list = mp_obj_new_list(num_stas, NULL);
for (int i = 0; i < num_stas; ++i) {
mp_obj_t tuple[1] = {
mp_obj_new_bytes(&macs[i * 6], 6),
mp_obj_new_bytes(&macs[i * mac_len], mac_len),
};
((mp_obj_list_t *)MP_OBJ_TO_PTR(list))->items[i] = mp_obj_new_tuple(1, tuple);
}
@@ -445,6 +466,10 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args"));
}
// A number of these options only update buffers in memory, and
// won't do anything until the interface is cycled down and back up
bool cycle_active = false;
for (size_t i = 0; i < kwargs->alloc; ++i) {
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
mp_map_elem_t *e = &kwargs->table[i];
@@ -457,6 +482,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
}
case MP_QSTR_channel: {
cyw43_wifi_ap_set_channel(self->cyw, mp_obj_get_int(e->value));
cycle_active = true;
break;
}
case MP_QSTR_ssid:
@@ -464,6 +490,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
size_t len;
const char *str = mp_obj_str_get_data(e->value, &len);
cyw43_wifi_ap_set_ssid(self->cyw, len, (const uint8_t *)str);
cycle_active = true;
break;
}
case MP_QSTR_monitor: {
@@ -483,6 +510,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
}
case MP_QSTR_security: {
cyw43_wifi_ap_set_auth(self->cyw, mp_obj_get_int(e->value));
cycle_active = true;
break;
}
case MP_QSTR_key:
@@ -490,6 +518,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
size_t len;
const char *str = mp_obj_str_get_data(e->value, &len);
cyw43_wifi_ap_set_password(self->cyw, len, (const uint8_t *)str);
cycle_active = true;
break;
}
case MP_QSTR_pm: {
@@ -519,6 +548,13 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
}
}
// If the interface is already active, cycle it down and up
if (cycle_active && if_active[self->itf]) {
uint32_t country = get_country_code();
cyw43_wifi_set_up(self->cyw, self->itf, false, country);
cyw43_wifi_set_up(self->cyw, self->itf, true, country);
}
return mp_const_none;
}
}

View File

@@ -58,6 +58,13 @@ static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t bloc
if (ret == mp_const_none) {
return 0;
} else {
// Some block devices return a bool indicating success, so
// convert those to an errno integer code.
if (ret == mp_const_true) {
return 0;
} else if (ret == mp_const_false) {
return -MP_EIO;
}
// Block device functions are expected to return 0 on success
// and negative integer on errors. Check for positive integer
// results as some callers (i.e. littlefs) will produce corrupt

View File

@@ -36,6 +36,10 @@
#include "esp_err.h"
#include "soc/gpio_sig_map.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
#include "esp_clk_tree.h"
#endif
#define PWM_DBG(...)
// #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n");
@@ -207,53 +211,79 @@ static void configure_channel(machine_pwm_obj_t *self) {
}
}
// Temporary workaround for ledc_find_suitable_duty_resolution function only being added in IDF V5.2
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0)
static uint32_t ledc_find_suitable_duty_resolution(uint32_t src_clk_freq, uint32_t timer_freq) {
// This implementation is based on the one used in Micropython v1.23
// Find the highest bit resolution for the requested frequency
unsigned int freq = src_clk_freq;
int divider = (freq + timer_freq / 2) / timer_freq; // rounded
if (divider == 0) {
divider = 1;
}
float f = (float)freq / divider; // actual frequency
if (f <= 1.0) {
f = 1.0;
}
freq = (unsigned int)roundf((float)freq / f);
unsigned int res = 0;
for (; freq > 1; freq >>= 1) {
++res;
}
if (res == 0) {
res = 1;
} else if (res > HIGHEST_PWM_RES) {
// Limit resolution to HIGHEST_PWM_RES to match units of our duty
res = HIGHEST_PWM_RES;
}
return res;
}
#endif
static void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) {
esp_err_t err;
if (freq != timer->freq_hz) {
// Find the highest bit resolution for the requested frequency
unsigned int i = APB_CLK_FREQ; // 80 MHz
#if SOC_LEDC_SUPPORT_REF_TICK
if (freq < EMPIRIC_FREQ) {
i = REF_CLK_FREQ; // 1 MHz
}
#endif
int divider = (i + freq / 2) / freq; // rounded
if (divider == 0) {
divider = 1;
}
float f = (float)i / divider; // actual frequency
if (f <= 1.0) {
f = 1.0;
}
i = (unsigned int)roundf((float)i / f);
unsigned int res = 0;
for (; i > 1; i >>= 1) {
++res;
}
if (res == 0) {
res = 1;
} else if (res > HIGHEST_PWM_RES) {
// Limit resolution to HIGHEST_PWM_RES to match units of our duty
res = HIGHEST_PWM_RES;
}
// Configure the new resolution and frequency
timer->duty_resolution = res;
// Configure the new frequency and resolution
timer->freq_hz = freq;
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
timer->clk_cfg = LEDC_USE_PLL_DIV_CLK;
#elif SOC_LEDC_SUPPORT_APB_CLOCK
timer->clk_cfg = LEDC_USE_APB_CLK;
#elif SOC_LEDC_SUPPORT_XTAL_CLOCK
timer->clk_cfg = LEDC_USE_XTAL_CLK;
#else
timer->clk_cfg = LEDC_USE_APB_CLK;
#error No supported PWM / LEDC clocks.
#endif
#if SOC_LEDC_SUPPORT_REF_TICK
if (freq < EMPIRIC_FREQ) {
timer->clk_cfg = LEDC_USE_REF_TICK;
}
#endif
uint32_t src_clk_freq = 0;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
err = esp_clk_tree_src_get_freq_hz(timer->clk_cfg, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_freq);
if (err != ESP_OK) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unable to query source clock frequency %d"), (int)timer->clk_cfg);
}
#else
// Simplified fallback logic for IDF V5.0.x, for targets with APB only.
src_clk_freq = APB_CLK_FREQ; // 80 MHz
#if SOC_LEDC_SUPPORT_REF_TICK
if (timer->clk_cfg == LEDC_USE_REF_TICK) {
src_clk_freq = REF_CLK_FREQ; // 1 MHz
}
#endif // SOC_LEDC_SUPPORT_REF_TICK
#endif // ESP_IDF_VERSION
timer->duty_resolution = ledc_find_suitable_duty_resolution(src_clk_freq, timer->freq_hz);
// Set frequency
esp_err_t err = ledc_timer_config(timer);
err = ledc_timer_config(timer);
if (err != ESP_OK) {
if (err == ESP_FAIL) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unreachable frequency %d"), freq);

View File

@@ -29,12 +29,14 @@
#include "modmachine.h"
#include "driver/gpio.h"
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#if SOC_TOUCH_SENSOR_SUPPORTED
#if CONFIG_IDF_TARGET_ESP32
#if SOC_TOUCH_VERSION_1 // ESP32 only
#include "driver/touch_pad.h"
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#elif SOC_TOUCH_VERSION_2 // All other SoCs with touch, to date
#include "driver/touch_sensor.h"
#else
#error "Unknown touch hardware version"
#endif
typedef struct _mtp_obj_t {
@@ -70,6 +72,8 @@ static const mtp_obj_t touchpad_obj[] = {
{{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM12},
{{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM13},
{{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM14},
#else
#error "Please add GPIO mapping for this SoC"
#endif
};
@@ -92,17 +96,18 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
if (!initialized) {
touch_pad_init();
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
touch_pad_fsm_start();
#endif
initialized = 1;
}
#if CONFIG_IDF_TARGET_ESP32
#if SOC_TOUCH_VERSION_1
esp_err_t err = touch_pad_config(self->touchpad_id, 0);
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#elif SOC_TOUCH_VERSION_2
esp_err_t err = touch_pad_config(self->touchpad_id);
#endif
if (err == ESP_OK) {
#if SOC_TOUCH_VERSION_2
touch_pad_fsm_start();
#endif
return MP_OBJ_FROM_PTR(self);
}
mp_raise_ValueError(MP_ERROR_TEXT("Touch pad error"));
@@ -110,10 +115,10 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
static mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) {
mtp_obj_t *self = self_in;
#if CONFIG_IDF_TARGET_ESP32
#if SOC_TOUCH_VERSION_1
uint16_t value = mp_obj_get_int(value_in);
esp_err_t err = touch_pad_config(self->touchpad_id, value);
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#elif SOC_TOUCH_VERSION_2
esp_err_t err = touch_pad_config(self->touchpad_id);
#endif
if (err == ESP_OK) {
@@ -125,10 +130,10 @@ MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config);
static mp_obj_t mtp_read(mp_obj_t self_in) {
mtp_obj_t *self = self_in;
#if CONFIG_IDF_TARGET_ESP32
#if SOC_TOUCH_VERSION_1
uint16_t value;
esp_err_t err = touch_pad_read(self->touchpad_id, &value);
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#elif SOC_TOUCH_VERSION_2
uint32_t value;
esp_err_t err = touch_pad_read_raw_data(self->touchpad_id, &value);
#endif
@@ -155,4 +160,4 @@ MP_DEFINE_CONST_OBJ_TYPE(
locals_dict, &mtp_locals_dict
);
#endif
#endif // SOC_TOUCH_SENSOR_SUPPORTED

View File

@@ -39,6 +39,7 @@
#include "esp_task.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_memory_utils.h"
#include "esp_psram.h"
#include "py/cstack.h"
@@ -237,6 +238,13 @@ void *esp_native_code_commit(void *buf, size_t len, void *reloc) {
len = (len + 3) & ~3;
size_t len_node = sizeof(native_code_node_t) + len;
native_code_node_t *node = heap_caps_malloc(len_node, MALLOC_CAP_EXEC);
#if CONFIG_IDF_TARGET_ESP32S2
// Workaround for ESP-IDF bug https://github.com/espressif/esp-idf/issues/14835
if (node != NULL && !esp_ptr_executable(node)) {
free(node);
node = NULL;
}
#endif // CONFIG_IDF_TARGET_ESP32S2
if (node == NULL) {
m_malloc_fail(len_node);
}

View File

@@ -213,7 +213,7 @@ static int mdns_getaddrinfo(const char *host_str, const char *port_str,
#endif // MICROPY_HW_ENABLE_MDNS_QUERIES
static void _getaddrinfo_inner(const mp_obj_t host, const mp_obj_t portx,
const struct addrinfo *hints, struct addrinfo **res) {
struct addrinfo *hints, struct addrinfo **res) {
int retval = 0;
*res = NULL;
@@ -235,6 +235,9 @@ static void _getaddrinfo_inner(const mp_obj_t host, const mp_obj_t portx,
MP_THREAD_GIL_EXIT();
// The ai_canonname field is used below, so set the hint.
hints->ai_flags |= AI_CANONNAME;
#if MICROPY_HW_ENABLE_MDNS_QUERIES
retval = mdns_getaddrinfo(host_str, port_str, hints, res);
#endif
@@ -264,7 +267,8 @@ static void _getaddrinfo_inner(const mp_obj_t host, const mp_obj_t portx,
static void _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) {
mp_obj_t *elem;
mp_obj_get_array_fixed_n(addrtuple, 2, &elem);
_getaddrinfo_inner(elem[0], elem[1], NULL, resp);
struct addrinfo hints = { 0 };
_getaddrinfo_inner(elem[0], elem[1], &hints, resp);
}
static mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {

View File

@@ -549,21 +549,38 @@ static mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
break;
}
case MP_QSTR_channel: {
uint8_t primary;
wifi_second_chan_t secondary;
// Get the current value of secondary
esp_exceptions(esp_wifi_get_channel(&primary, &secondary));
primary = mp_obj_get_int(kwargs->table[i].value);
esp_err_t err = esp_wifi_set_channel(primary, secondary);
if (err == ESP_ERR_INVALID_ARG) {
// May need to swap secondary channel above to below or below to above
secondary = (
(secondary == WIFI_SECOND_CHAN_ABOVE)
? WIFI_SECOND_CHAN_BELOW
: (secondary == WIFI_SECOND_CHAN_BELOW)
uint8_t channel = mp_obj_get_int(kwargs->table[i].value);
if (self->if_id == ESP_IF_WIFI_AP) {
cfg.ap.channel = channel;
} else {
// This setting is only used to determine the
// starting channel for a scan, so it can result in
// slightly faster connection times.
cfg.sta.channel = channel;
// This additional code to directly set the channel
// on the STA interface is only relevant for ESP-NOW
// (when there is no STA connection attempt.)
uint8_t old_primary;
wifi_second_chan_t secondary;
// Get the current value of secondary
esp_exceptions(esp_wifi_get_channel(&old_primary, &secondary));
esp_err_t err = esp_wifi_set_channel(channel, secondary);
if (err == ESP_ERR_INVALID_ARG) {
// May need to swap secondary channel above to below or below to above
secondary = (
(secondary == WIFI_SECOND_CHAN_ABOVE)
? WIFI_SECOND_CHAN_BELOW
: (secondary == WIFI_SECOND_CHAN_BELOW)
? WIFI_SECOND_CHAN_ABOVE
: WIFI_SECOND_CHAN_NONE);
esp_exceptions(esp_wifi_set_channel(primary, secondary));
err = esp_wifi_set_channel(channel, secondary);
}
esp_exceptions(err);
if (channel != old_primary) {
// Workaround the ESP-IDF Wi-Fi stack sometimes taking a moment to change channels
mp_hal_delay_ms(1);
}
}
break;
}

View File

@@ -62,6 +62,7 @@ void ticker_init0(void) {
#else
NRFX_IRQ_PRIORITY_SET(FastTicker_IRQn, 2);
#endif
m_num_of_slow_tickers = 0;
NRFX_IRQ_PRIORITY_SET(SlowTicker_IRQn, 3);

View File

@@ -7,7 +7,7 @@ QSTR_DEFS = qstrdefsport.h
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
XCVERSION ?= 1.35
XCVERSION ?= 2.10
XC16 ?= /opt/microchip/xc16/v$(XCVERSION)
CROSS_COMPILE ?= $(XC16)/bin/xc16-
@@ -31,7 +31,7 @@ CFLAGS += -O1 -DNDEBUG
endif
LDFLAGS += --heap=0 -nostdlib -T $(XC16)/support/$(PARTFAMILY)/gld/p$(PART).gld -Map=$@.map --cref -p$(PART)
LIBS += -L$(XC16)/lib -L$(XC16)/lib/$(PARTFAMILY) -lc -lm -lpic30
LIBS += -L$(XC16)/lib -L$(XC16)/lib/$(PARTFAMILY) -lc99-elf -lm-elf -lc99-pic30-elf
SRC_C = \
main.c \

View File

@@ -93,7 +93,3 @@ typedef int mp_off_t;
#define MICROPY_MPHALPORT_H "pic16bit_mphal.h"
#define MICROPY_HW_BOARD_NAME "dsPICSK"
#define MICROPY_HW_MCU_NAME "dsPIC33"
// XC16 toolchain doesn't seem to define these
typedef int intptr_t;
typedef unsigned int uintptr_t;

View File

@@ -196,6 +196,7 @@ set(MICROPY_SOURCE_QSTR
)
set(PICO_SDK_COMPONENTS
boot_bootrom_headers
hardware_adc
hardware_base
hardware_boot_lock
@@ -222,6 +223,7 @@ set(PICO_SDK_COMPONENTS
pico_base_headers
pico_binary_info
pico_bootrom
pico_flash
pico_multicore
pico_platform
pico_platform_compiler
@@ -274,7 +276,7 @@ if(PICO_RP2040)
elseif(PICO_RP2350 AND PICO_ARM)
target_sources(pico_float_micropython INTERFACE
${PICO_SDK_PATH}/src/rp2_common/pico_float/float_aeabi_dcp.S
${PICO_SDK_PATH}/src/rp2_common/pico_float/float_conv_m33.S
${PICO_SDK_PATH}/src/rp2_common/pico_float/float_common_m33.S
)
endif()
@@ -554,8 +556,8 @@ target_compile_definitions(${MICROPY_TARGET} PRIVATE
LFS1_NO_MALLOC LFS1_NO_DEBUG LFS1_NO_WARN LFS1_NO_ERROR LFS1_NO_ASSERT
LFS2_NO_MALLOC LFS2_NO_DEBUG LFS2_NO_WARN LFS2_NO_ERROR LFS2_NO_ASSERT
PICO_FLOAT_PROPAGATE_NANS=1
PICO_STACK_SIZE=0x2000
PICO_CORE1_STACK_SIZE=0
PICO_STACK_SIZE=0x1000
PICO_CORE1_STACK_SIZE=0x1000
PICO_MAX_SHARED_IRQ_HANDLERS=8 # we need more than the default
PICO_PROGRAM_NAME="MicroPython"
PICO_NO_PROGRAM_VERSION_STRING=1 # do it ourselves in main.c

View File

@@ -20,4 +20,6 @@
#define MICROPY_HW_PIN_EXT_COUNT CYW43_WL_GPIO_COUNT
#define MICROPY_HW_PIN_RESERVED(i) ((i) == CYW43_PIN_WL_HOST_WAKE || (i) == CYW43_PIN_WL_REG_ON)
// If this returns true for a pin then its irq will not be disabled on a soft reboot
int mp_hal_is_pin_reserved(int n);
#define MICROPY_HW_PIN_RESERVED(i) mp_hal_is_pin_reserved(i)

View File

@@ -53,6 +53,41 @@
#define CYW43_HOST_NAME mod_network_hostname_data
#if CYW43_PIN_WL_DYNAMIC
// Dynamic pins can be changed at runtime before initialising the CYW43
typedef enum cyw43_pin_index_t {
CYW43_PIN_INDEX_WL_REG_ON,
CYW43_PIN_INDEX_WL_DATA_OUT,
CYW43_PIN_INDEX_WL_DATA_IN,
CYW43_PIN_INDEX_WL_HOST_WAKE,
CYW43_PIN_INDEX_WL_CLOCK,
CYW43_PIN_INDEX_WL_CS,
CYW43_PIN_INDEX_WL_COUNT // last
} cyw43_pin_index_t;
// Function to retrieve a cyw43 dynamic pin
uint cyw43_get_pin_wl(cyw43_pin_index_t pin_id);
#define CYW43_PIN_WL_REG_ON cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_REG_ON)
#define CYW43_PIN_WL_DATA_OUT cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_DATA_OUT)
#define CYW43_PIN_WL_DATA_IN cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_DATA_IN)
#define CYW43_PIN_WL_HOST_WAKE cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_HOST_WAKE)
#define CYW43_PIN_WL_CLOCK cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_CLOCK)
#define CYW43_PIN_WL_CS cyw43_get_pin_wl(CYW43_PIN_INDEX_WL_CS)
#else
#define CYW43_PIN_WL_REG_ON CYW43_DEFAULT_PIN_WL_REG_ON
#define CYW43_PIN_WL_DATA_OUT CYW43_DEFAULT_PIN_WL_DATA_OUT
#define CYW43_PIN_WL_DATA_IN CYW43_DEFAULT_PIN_WL_DATA_IN
#define CYW43_PIN_WL_HOST_WAKE CYW43_DEFAULT_PIN_WL_HOST_WAKE
#define CYW43_PIN_WL_CLOCK CYW43_DEFAULT_PIN_WL_CLOCK
#define CYW43_PIN_WL_CS CYW43_DEFAULT_PIN_WL_CS
#endif
#define CYW43_SDPCM_SEND_COMMON_WAIT \
if (get_core_num() == 0) { \
cyw43_yield(); \

View File

@@ -69,7 +69,7 @@ SECTIONS
* FLASH ... we will include any thing excluded here in .data below by default */
*(.init)
/* Change for MicroPython... exclude gc.c, parse.c, vm.c from flash */
*(EXCLUDE_FILE(*libgcc.a: *libc.a: *lib_a-mem*.o *libm.a: *gc.c.obj *vm.c.obj *parse.c.obj) .text*)
*(EXCLUDE_FILE(*libgcc.a: *libc.a: *lib_a-mem*.o *libm.a: *gc.c.obj *vm.c.obj *parse.c.obj *libhelix_mp3.a:) .text*)
*(.fini)
/* Pull all c'tors into .text */
*crtbegin.o(.ctors)
@@ -89,7 +89,7 @@ SECTIONS
} > FLASH
.rodata : {
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *libhelix_mp3.a:) .rodata*)
. = ALIGN(4);
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
. = ALIGN(4);

View File

@@ -278,3 +278,11 @@ void mp_wfe_or_timeout(uint32_t timeout_ms) {
// Clean up the timer node if it's not already
soft_timer_remove(&timer);
}
int mp_hal_is_pin_reserved(int n) {
#if MICROPY_PY_NETWORK_CYW43
return n == CYW43_PIN_WL_HOST_WAKE;
#else
return false;
#endif
}

View File

@@ -210,5 +210,6 @@ enum {
void mp_hal_get_mac(int idx, uint8_t buf[6]);
void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
int mp_hal_is_pin_reserved(int n);
#endif // MICROPY_INCLUDED_RP2_MPHALPORT_H

View File

@@ -70,10 +70,20 @@ bi_decl(bi_block_device(
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
// This is a workaround to pico-sdk #2201: https://github.com/raspberrypi/pico-sdk/issues/2201
// which means the multicore_lockout_victim_is_initialized returns true even after core1 is reset.
static bool use_multicore_lockout(void) {
return multicore_lockout_victim_is_initialized(1 - get_core_num())
#if MICROPY_PY_THREAD
&& core1_entry != NULL
#endif
;
}
// Flash erase and write must run with interrupts disabled and the other core suspended,
// because the XIP bit gets disabled.
static uint32_t begin_critical_flash_section(void) {
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
if (use_multicore_lockout()) {
multicore_lockout_start_blocking();
}
return save_and_disable_interrupts();
@@ -81,7 +91,7 @@ static uint32_t begin_critical_flash_section(void) {
static void end_critical_flash_section(uint32_t state) {
restore_interrupts(state);
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
if (use_multicore_lockout()) {
multicore_lockout_end_blocking();
}
}

View File

@@ -380,6 +380,18 @@ static inline bool mp_check(bool value) {
// mp_int_t can be larger than long, i.e. Windows 64-bit, nan-box variants
static inline uint32_t mp_clz_mpi(mp_int_t x) {
#ifdef __XC16__
mp_uint_t mask = MP_OBJ_WORD_MSBIT_HIGH;
mp_uint_t zeroes = 0;
while (mask != 0) {
if (mask & (mp_uint_t)x) {
break;
}
zeroes++;
mask >>= 1;
}
return zeroes;
#else
MP_STATIC_ASSERT(sizeof(mp_int_t) == sizeof(long long)
|| sizeof(mp_int_t) == sizeof(long));
@@ -389,6 +401,7 @@ static inline uint32_t mp_clz_mpi(mp_int_t x) {
} else {
return mp_clzll((unsigned long long)x);
}
#endif
}
#endif // MICROPY_INCLUDED_PY_MISC_H

View File

@@ -31,7 +31,7 @@
// are unavailable.
#define MICROPY_VERSION_MAJOR 1
#define MICROPY_VERSION_MINOR 24
#define MICROPY_VERSION_MICRO 0
#define MICROPY_VERSION_MICRO 1
#define MICROPY_VERSION_PRERELEASE 0
// Combined version as a 32-bit number for convenience to allow version

View File

@@ -208,7 +208,7 @@ static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
size_t offset = mp_get_index(self->base.type, deque_len(self), index, false);
size_t index_val = self->i_get + offset;
if (index_val > self->alloc) {
if (index_val >= self->alloc) {
index_val -= self->alloc;
}

View File

@@ -47,6 +47,13 @@
#define M_PI (3.14159265358979323846)
#endif
// Workaround a bug in recent MSVC where NAN is no longer constant.
// (By redefining back to the previous MSVC definition of NAN)
#if defined(_MSC_VER) && _MSC_VER >= 1942
#undef NAN
#define NAN (-(float)(((float)(1e+300 * 1e+300)) * 0.0F))
#endif
typedef struct _mp_obj_float_t {
mp_obj_base_t base;
mp_float_t value;

View File

@@ -63,3 +63,18 @@ for x, y in (
fbuf.fill(0)
fbuf.ellipse(x, y, 6, 12, 0xAA, True)
printbuf()
# Draw an ellipse with both radius 0
fbuf.fill(0)
fbuf.ellipse(15, 15, 0, 0, 0xFF, True)
printbuf()
# Draw an ellipse with both radius 0 out of bounds
fbuf.fill(0)
fbuf.ellipse(45, 45, 0, 0, 0xFF, True)
printbuf()
# Draw an ellipse with radius 0 and all sectors masked out
fbuf.fill(0)
fbuf.ellipse(15, 15, 0, 0, 0xFF, True, 0)
printbuf()

View File

@@ -702,3 +702,99 @@ aaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000
aaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000
aaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000
-->8--
--8<--
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000ff0000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-->8--
--8<--
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-->8--
--8<--
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
-->8--

View File

@@ -0,0 +1,18 @@
# This is a regression test for https://github.com/micropython/micropython/issues/16619
# it runs in two parts by necessity:
#
# - This "part1" creates a non-terminating thread.
# - The test runner issues a soft reset, which will terminate that thread.
# - "part2" is the actual test, which is whether flash access works correctly
# after the thread was terminated by soft reset.
import _thread
def infinite():
while True:
pass
_thread.start_new_thread(infinite, ())
print("Part 1 complete...")

View File

@@ -0,0 +1 @@
Part 1 complete...

View File

@@ -0,0 +1,12 @@
# This is part2 of a two-part regression test, see part1
# for details of what's expected.
import os
FILENAME = "/rp2_thread_reset_test.txt"
print("Starting")
with open(FILENAME, "w") as f:
f.write("test")
print("Written")
os.unlink(FILENAME)
print("Removed")

View File

@@ -0,0 +1,3 @@
Starting
Written
Removed

View File

@@ -129,8 +129,15 @@ def _remote_path_basename(a):
def do_filesystem_cp(state, src, dest, multiple, check_hash=False):
if dest.startswith(":"):
dest_exists = state.transport.fs_exists(dest[1:])
dest_isdir = dest_exists and state.transport.fs_isdir(dest[1:])
dest_no_slash = dest.rstrip("/" + os.path.sep + (os.path.altsep or ""))
dest_exists = state.transport.fs_exists(dest_no_slash[1:])
dest_isdir = dest_exists and state.transport.fs_isdir(dest_no_slash[1:])
# A trailing / on dest forces it to be a directory.
if dest != dest_no_slash:
if not dest_isdir:
raise CommandError("cp: destination is not a directory")
dest = dest_no_slash
else:
dest_exists = os.path.exists(dest)
dest_isdir = dest_exists and os.path.isdir(dest)

View File

@@ -547,7 +547,10 @@ def main():
return 0
except CommandError as e:
# Make sure existing stdout appears before the error message on stderr.
sys.stdout.flush()
print(f"{_PROG}: {e}", file=sys.stderr)
sys.stderr.flush()
return 1
finally:
do_disconnect(state)

View File

@@ -151,9 +151,9 @@ class Transport:
while data:
chunk = data[:chunk_size]
self.exec("w(" + repr(chunk) + ")")
written += len(chunk)
data = data[len(chunk) :]
if progress_callback:
written += len(chunk)
progress_callback(written, src_size)
self.exec("f.close()")
except TransportExecError as e:

View File

@@ -16,7 +16,7 @@ for t in $TESTS; do
TMP=$(mktemp -d)
echo -n "${t}: "
# Strip CR and replace the random temp dir with a token.
if env MPREMOTE=${MPREMOTE} TMP="${TMP}" "${t}" | tr -d '\r' | sed "s,${TMP},"'${TMP},g' > "${t}.out"; then
if env MPREMOTE=${MPREMOTE} TMP="${TMP}" "${t}" 2>&1 | tr -d '\r' | sed "s,${TMP},"'${TMP},g' > "${t}.out"; then
if diff "${t}.out" "${t}.exp" > /dev/null; then
echo "OK"
else

View File

@@ -66,6 +66,16 @@ $MPREMOTE resume cp "${TMP}/a.py" :aaa
$MPREMOTE resume cp "${TMP}/a.py" :bbb/b.py
$MPREMOTE resume cat :aaa/a.py bbb/b.py
# Test cp -f (force copy).
echo -----
$MPREMOTE resume cp -f "${TMP}/a.py" :aaa
$MPREMOTE resume cat :aaa/a.py
# Test cp where the destination has a trailing /.
echo -----
$MPREMOTE resume cp "${TMP}/a.py" :aaa/
$MPREMOTE resume cp "${TMP}/a.py" :aaa/a.py/ || echo "expect error"
echo -----
$MPREMOTE resume rm :b.py c.py
$MPREMOTE resume ls

View File

@@ -38,6 +38,16 @@ print("World")
print("Hello")
print("World")
-----
cp ${TMP}/a.py :aaa
print("Hello")
print("World")
-----
cp ${TMP}/a.py :aaa/
Up to date: aaa/a.py
cp ${TMP}/a.py :aaa/a.py/
mpremote: cp: destination is not a directory
expect error
-----
rm :b.py
rm :c.py
ls :