22 Commits

Author SHA1 Message Date
Damien George
ecfdd5d6f9 all: Bump version to 1.24.1.
Some checks failed
unix port / settrace (push) Has been cancelled
unix port / settrace_stackless (push) Has been cancelled
unix port / macos (push) Has been cancelled
unix port / qemu_mips (push) Has been cancelled
unix port / qemu_arm (push) Has been cancelled
unix port / qemu_riscv64 (push) Has been cancelled
webassembly port / build (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Has been cancelled
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, dev) (push) Has been cancelled
windows port / build-mingw (i686, mingw32, standard) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, dev) (push) Has been cancelled
windows port / build-mingw (x86_64, mingw64, standard) (push) Has been cancelled
windows port / cross-build-on-linux (push) Has been cancelled
zephyr port / build (push) Has been cancelled
Python code lint and formatting with ruff / ruff (push) Has been cancelled
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.
Some checks are pending
unix port / settrace (push) Waiting to run
unix port / settrace_stackless (push) Waiting to run
unix port / macos (push) Waiting to run
unix port / qemu_mips (push) Waiting to run
unix port / qemu_arm (push) Waiting to run
unix port / qemu_riscv64 (push) Waiting to run
webassembly port / build (push) Waiting to run
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-mingw (i686, mingw32, dev) (push) Waiting to run
windows port / build-mingw (i686, mingw32, standard) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, dev) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, standard) (push) Waiting to run
windows port / cross-build-on-linux (push) Waiting to run
zephyr port / build (push) Waiting to run
Python code lint and formatting with ruff / ruff (push) Waiting to run
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
24 changed files with 351 additions and 82 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

@@ -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

@@ -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 :