diff options
Diffstat (limited to 'extmod')
-rw-r--r-- | extmod/btstack/modbluetooth_btstack.c | 7 | ||||
-rw-r--r-- | extmod/machine_pulse.c | 37 | ||||
-rw-r--r-- | extmod/modbluetooth.c | 7 | ||||
-rw-r--r-- | extmod/modbluetooth.h | 2 | ||||
-rw-r--r-- | extmod/modframebuf.c | 57 | ||||
-rw-r--r-- | extmod/modjson.c | 3 | ||||
-rw-r--r-- | extmod/modlwip.c | 303 | ||||
-rw-r--r-- | extmod/modmachine.c | 12 | ||||
-rw-r--r-- | extmod/modmachine.h | 2 | ||||
-rw-r--r-- | extmod/modnetwork.c | 39 | ||||
-rw-r--r-- | extmod/modnetwork.h | 5 | ||||
-rw-r--r-- | extmod/modre.c | 3 | ||||
-rw-r--r-- | extmod/modtls_axtls.c | 2 | ||||
-rw-r--r-- | extmod/modtls_mbedtls.c | 2 | ||||
-rw-r--r-- | extmod/moductypes.c | 2 | ||||
-rw-r--r-- | extmod/network_cyw43.c | 3 | ||||
-rw-r--r-- | extmod/network_esp_hosted.c | 2 | ||||
-rw-r--r-- | extmod/network_ppp_lwip.c | 9 | ||||
-rw-r--r-- | extmod/network_wiznet5k.c | 2 | ||||
-rw-r--r-- | extmod/nimble/modbluetooth_nimble.c | 21 | ||||
-rw-r--r-- | extmod/nimble/modbluetooth_nimble.h | 2 | ||||
-rw-r--r-- | extmod/vfs_lfsx.c | 2 |
22 files changed, 343 insertions, 181 deletions
diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c index b29970842c..7694a1874f 100644 --- a/extmod/btstack/modbluetooth_btstack.c +++ b/extmod/btstack/modbluetooth_btstack.c @@ -705,12 +705,12 @@ int mp_bluetooth_init(void) { return 0; } -void mp_bluetooth_deinit(void) { +int mp_bluetooth_deinit(void) { DEBUG_printf("mp_bluetooth_deinit\n"); // Nothing to do if not initialised. if (!MP_STATE_PORT(bluetooth_btstack_root_pointers)) { - return; + return 0; } mp_bluetooth_gap_advertise_stop(); @@ -737,6 +737,9 @@ void mp_bluetooth_deinit(void) { deinit_stack(); DEBUG_printf("mp_bluetooth_deinit: complete\n"); + + bool timeout = mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_TIMEOUT; + return timeout ? MP_ETIMEDOUT : 0; } bool mp_bluetooth_is_active(void) { diff --git a/extmod/machine_pulse.c b/extmod/machine_pulse.c index 85dba86d9b..b78a63f182 100644 --- a/extmod/machine_pulse.c +++ b/extmod/machine_pulse.c @@ -30,20 +30,35 @@ #if MICROPY_PY_MACHINE_PULSE -MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) { + mp_uint_t nchanges = 2; mp_uint_t start = mp_hal_ticks_us(); - while (mp_hal_pin_read(pin) != pulse_level) { - if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { - return (mp_uint_t)-2; - } - } - start = mp_hal_ticks_us(); - while (mp_hal_pin_read(pin) == pulse_level) { - if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { - return (mp_uint_t)-1; + for (;;) { + // Sample ticks and pin as close together as possible, and always in the same + // order each time around the loop. This gives the most accurate measurement. + mp_uint_t t = mp_hal_ticks_us(); + int pin_value = mp_hal_pin_read(pin); + + if (pin_value == pulse_level) { + // Pin is at desired value. Flip desired value and see if we are done. + pulse_level = 1 - pulse_level; + if (--nchanges == 0) { + return t - start; + } + start = t; + } else { + // Pin hasn't changed yet, check for timeout. + mp_uint_t dt = t - start; + if (dt >= timeout_us) { + return -nchanges; + } + + // Allow a port to perform background task processing if needed. + #ifdef MICROPY_PY_MACHINE_TIME_PULSE_US_HOOK + MICROPY_PY_MACHINE_TIME_PULSE_US_HOOK(dt); + #endif } } - return mp_hal_ticks_us() - start; } static mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index b95c42a4ee..ffa407809a 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -290,12 +290,13 @@ static mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, static mp_obj_t bluetooth_ble_active(size_t n_args, const mp_obj_t *args) { if (n_args == 2) { // Boolean enable/disable argument supplied, set current state. + int err; if (mp_obj_is_true(args[1])) { - int err = mp_bluetooth_init(); - bluetooth_handle_errno(err); + err = mp_bluetooth_init(); } else { - mp_bluetooth_deinit(); + err = mp_bluetooth_deinit(); } + bluetooth_handle_errno(err); } // Return current state. return mp_obj_new_bool(mp_bluetooth_is_active()); diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 6a087c8e25..24f063fa5d 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -295,7 +295,7 @@ extern const mp_obj_type_t mp_type_bluetooth_uuid; int mp_bluetooth_init(void); // Disables the Bluetooth stack. Is a no-op when not enabled. -void mp_bluetooth_deinit(void); +int mp_bluetooth_deinit(void); // Returns true when the Bluetooth stack is active. bool mp_bluetooth_is_active(void); diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index b718a66cc6..5c4b9abf0c 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -270,8 +270,7 @@ static void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, u formats[fb->format].fill_rect(fb, x, y, xend - x, yend - y, col); } -static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) { - mp_arg_check_num(n_args, n_kw, 4, 5, false); +static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in, unsigned int buf_flags, mp_obj_framebuf_t *o) { mp_int_t width = mp_obj_get_int(args_in[1]); mp_int_t height = mp_obj_get_int(args_in[2]); @@ -318,13 +317,15 @@ static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size } mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE); + mp_get_buffer_raise(args_in[0], &bufinfo, buf_flags); if ((strides_required * stride + (height_required - strides_required) * width_required) * bpp / 8 > bufinfo.len) { mp_raise_ValueError(NULL); } - mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, type); + if (o == NULL) { + o = mp_obj_malloc(mp_obj_framebuf_t, (const mp_obj_type_t *)&mp_type_framebuf); + } o->buf_obj = args_in[0]; o->buf = bufinfo.buf; o->width = width; @@ -335,6 +336,11 @@ static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size return MP_OBJ_FROM_PTR(o); } +static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) { + mp_arg_check_num(n_args, n_kw, 4, 5, false); + return framebuf_make_new_helper(n_args, args_in, MP_BUFFER_WRITE, NULL); +} + static void framebuf_args(const mp_obj_t *args_in, mp_int_t *args_out, int n) { for (int i = 0; i < n; ++i) { args_out[i] = mp_obj_get_int(args_in[i + 1]); @@ -707,13 +713,27 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_poly_obj, 5, 6, framebuf_pol #endif // MICROPY_PY_ARRAY +static void get_readonly_framebuffer(mp_obj_t arg, mp_obj_framebuf_t *rofb) { + mp_obj_t fb = mp_obj_cast_to_native_base(arg, MP_OBJ_FROM_PTR(&mp_type_framebuf)); + if (fb != MP_OBJ_NULL) { + *rofb = *(mp_obj_framebuf_t *)MP_OBJ_TO_PTR(fb); + } else { + // A tuple/list of the form: (buffer, width, height, format[, stride]). + size_t len; + mp_obj_t *items; + mp_obj_get_array(arg, &len, &items); + if (len < 4 || len > 5) { + mp_raise_ValueError(NULL); + } + framebuf_make_new_helper(len, items, MP_BUFFER_READ, rofb); + } +} + static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) { mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args_in[0]); - mp_obj_t source_in = mp_obj_cast_to_native_base(args_in[1], MP_OBJ_FROM_PTR(&mp_type_framebuf)); - if (source_in == MP_OBJ_NULL) { - mp_raise_TypeError(NULL); - } - mp_obj_framebuf_t *source = MP_OBJ_TO_PTR(source_in); + + mp_obj_framebuf_t source; + get_readonly_framebuffer(args_in[1], &source); mp_int_t x = mp_obj_get_int(args_in[2]); mp_int_t y = mp_obj_get_int(args_in[3]); @@ -721,16 +741,17 @@ static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) { if (n_args > 4) { key = mp_obj_get_int(args_in[4]); } - mp_obj_framebuf_t *palette = NULL; + mp_obj_framebuf_t palette; + palette.buf = NULL; if (n_args > 5 && args_in[5] != mp_const_none) { - palette = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(args_in[5], MP_OBJ_FROM_PTR(&mp_type_framebuf))); + get_readonly_framebuffer(args_in[5], &palette); } if ( (x >= self->width) || (y >= self->height) || - (-x >= source->width) || - (-y >= source->height) + (-x >= source.width) || + (-y >= source.height) ) { // Out of bounds, no-op. return mp_const_none; @@ -741,15 +762,15 @@ static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) { int y0 = MAX(0, y); int x1 = MAX(0, -x); int y1 = MAX(0, -y); - int x0end = MIN(self->width, x + source->width); - int y0end = MIN(self->height, y + source->height); + int x0end = MIN(self->width, x + source.width); + int y0end = MIN(self->height, y + source.height); for (; y0 < y0end; ++y0) { int cx1 = x1; for (int cx0 = x0; cx0 < x0end; ++cx0) { - uint32_t col = getpixel(source, cx1, y1); - if (palette) { - col = getpixel(palette, col, 0); + uint32_t col = getpixel(&source, cx1, y1); + if (palette.buf) { + col = getpixel(&palette, col, 0); } if (col != (uint32_t)key) { setpixel(self, cx0, y0, col); diff --git a/extmod/modjson.c b/extmod/modjson.c index e655a02bc0..11aedd1983 100644 --- a/extmod/modjson.c +++ b/extmod/modjson.c @@ -160,7 +160,8 @@ static mp_obj_t mod_json_load(mp_obj_t stream_obj) { for (;;) { cont: if (S_END(s)) { - break; + // Input finished abruptly in the middle of a composite entity. + goto fail; } mp_obj_t next = MP_OBJ_NULL; bool enter = false; diff --git a/extmod/modlwip.c b/extmod/modlwip.c index f109e0029b..b53559ed8c 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -70,6 +70,10 @@ #define TCP_NODELAY TF_NODELAY +// Socket flags +#define MSG_PEEK 0x01 +#define MSG_DONTWAIT 0x02 + // For compatibilily with older lwIP versions. #ifndef ip_set_option #define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt)) @@ -286,6 +290,15 @@ static const int error_lookup_table[] = { #define MOD_NETWORK_SOCK_DGRAM (2) #define MOD_NETWORK_SOCK_RAW (3) +// Total queue length for buffered UDP/raw incoming packets. +#define LWIP_INCOMING_PACKET_QUEUE_LEN (4) + +typedef struct _lwip_incoming_packet_t { + struct pbuf *pbuf; + ip_addr_t peer_addr; + uint16_t peer_port; +} lwip_incoming_packet_t; + typedef struct _lwip_socket_obj_t { mp_obj_base_t base; @@ -294,8 +307,11 @@ typedef struct _lwip_socket_obj_t { struct udp_pcb *udp; struct raw_pcb *raw; } pcb; + + // Data structure that holds incoming pbuf's. + // Each socket type has different state that it needs to keep track of. volatile union { - struct pbuf *pbuf; + // TCP listening sockets have a queue of incoming connections, implemented as a ringbuffer. struct { uint8_t alloc; uint8_t iget; @@ -305,10 +321,23 @@ typedef struct _lwip_socket_obj_t { struct tcp_pcb **array; // if alloc != 0 } tcp; } connection; + + // Connected TCP sockets have a single incoming pbuf that new data is appended to. + struct { + struct pbuf *pbuf; + } tcp; + + // UDP and raw sockets have a queue of incoming pbuf's, implemented as a ringbuffer. + struct { + uint8_t iget; // ringbuffer read index + uint8_t iput; // ringbuffer write index + lwip_incoming_packet_t *array; + } udp_raw; } incoming; + mp_obj_t callback; - ip_addr_t peer; - mp_uint_t peer_port; + ip_addr_t tcp_peer_addr; + mp_uint_t tcp_peer_port; mp_uint_t timeout; uint16_t recv_offset; @@ -347,9 +376,21 @@ static void lwip_socket_free_incoming(lwip_socket_obj_t *socket) { && socket->pcb.tcp->state == LISTEN; if (!socket_is_listener) { - if (socket->incoming.pbuf != NULL) { - pbuf_free(socket->incoming.pbuf); - socket->incoming.pbuf = NULL; + if (socket->type == MOD_NETWORK_SOCK_STREAM) { + if (socket->incoming.tcp.pbuf != NULL) { + pbuf_free(socket->incoming.tcp.pbuf); + socket->incoming.tcp.pbuf = NULL; + } + } else { + for (size_t i = 0; i < LWIP_INCOMING_PACKET_QUEUE_LEN; ++i) { + lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[i]; + if (slot->pbuf != NULL) { + pbuf_free(slot->pbuf); + slot->pbuf = NULL; + } + } + socket->incoming.udp_raw.iget = 0; + socket->incoming.udp_raw.iput = 0; } } else { uint8_t alloc = socket->incoming.connection.alloc; @@ -407,6 +448,19 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) { } } +static void udp_raw_incoming(lwip_socket_obj_t *socket, struct pbuf *p, const ip_addr_t *addr, u16_t port) { + lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iput]; + if (slot->pbuf != NULL) { + // No room in the inn, drop the packet. + pbuf_free(p); + } else { + slot->pbuf = p; + slot->peer_addr = *addr; + slot->peer_port = port; + socket->incoming.udp_raw.iput = (socket->incoming.udp_raw.iput + 1) % LWIP_INCOMING_PACKET_QUEUE_LEN; + } +} + #if MICROPY_PY_LWIP_SOCK_RAW // Callback for incoming raw packets. #if LWIP_VERSION_MAJOR < 2 @@ -416,13 +470,7 @@ static u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, c #endif { lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg; - - if (socket->incoming.pbuf != NULL) { - pbuf_free(p); - } else { - socket->incoming.pbuf = p; - memcpy(&socket->peer, addr, sizeof(socket->peer)); - } + udp_raw_incoming(socket, p, addr, 0); return 1; // we ate the packet } #endif @@ -436,15 +484,7 @@ static void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, #endif { lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg; - - if (socket->incoming.pbuf != NULL) { - // That's why they call it "unreliable". No room in the inn, drop the packet. - pbuf_free(p); - } else { - socket->incoming.pbuf = p; - socket->peer_port = (mp_uint_t)port; - memcpy(&socket->peer, addr, sizeof(socket->peer)); - } + udp_raw_incoming(socket, p, addr, port); } // Callback for general tcp errors. @@ -562,13 +602,13 @@ static err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err return ERR_OK; } - if (socket->incoming.pbuf == NULL) { - socket->incoming.pbuf = p; + if (socket->incoming.tcp.pbuf == NULL) { + socket->incoming.tcp.pbuf = p; } else { #ifdef SOCKET_SINGLE_PBUF return ERR_BUF; #else - pbuf_cat(socket->incoming.pbuf, p); + pbuf_cat(socket->incoming.tcp.pbuf, p); #endif } @@ -637,18 +677,20 @@ static mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, m } // Helper function for recv/recvfrom to handle raw/UDP packets -static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, ip_addr_t *ip, mp_uint_t *port, int *_errno) { +static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_int_t flags, ip_addr_t *ip, mp_uint_t *port, int *_errno) { - if (socket->incoming.pbuf == NULL) { - if (socket->timeout == 0) { - // Non-blocking socket. + lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iget]; + + if (slot->pbuf == NULL) { + // Non-blocking socket or flag + if (socket->timeout == 0 || (flags & MSG_DONTWAIT)) { *_errno = MP_EAGAIN; return -1; } // Wait for data to arrive on UDP socket. mp_uint_t start = mp_hal_ticks_ms(); - while (socket->incoming.pbuf == NULL) { + while (slot->pbuf == NULL) { if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { *_errno = MP_ETIMEDOUT; return -1; @@ -658,17 +700,20 @@ static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_u } if (ip != NULL) { - memcpy(ip, &socket->peer, sizeof(socket->peer)); - *port = socket->peer_port; + *ip = slot->peer_addr; + *port = slot->peer_port; } - struct pbuf *p = socket->incoming.pbuf; + struct pbuf *p = slot->pbuf; MICROPY_PY_LWIP_ENTER u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0); - pbuf_free(p); - socket->incoming.pbuf = NULL; + if ((flags & MSG_PEEK) == 0) { + pbuf_free(p); + slot->pbuf = NULL; + socket->incoming.udp_raw.iget = (socket->incoming.udp_raw.iget + 1) % LWIP_INCOMING_PACKET_QUEUE_LEN; + } MICROPY_PY_LWIP_EXIT @@ -776,14 +821,20 @@ static mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui } // Helper function for recv/recvfrom to handle TCP packets -static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { +static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_int_t flags, int *_errno) { // Check for any pending errors STREAM_ERROR_CHECK(socket); - if (socket->incoming.pbuf == NULL) { + if (socket->state == STATE_LISTENING) { + // original socket in listening state, not the accepted connection. + *_errno = MP_ENOTCONN; + return -1; + } - // Non-blocking socket - if (socket->timeout == 0) { + if (socket->incoming.tcp.pbuf == NULL) { + + // Non-blocking socket or flag + if (socket->timeout == 0 || (flags & MSG_DONTWAIT)) { if (socket->state == STATE_PEER_CLOSED) { return 0; } @@ -792,7 +843,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } mp_uint_t start = mp_hal_ticks_ms(); - while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) { + while (socket->state == STATE_CONNECTED && socket->incoming.tcp.pbuf == NULL) { if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { *_errno = MP_ETIMEDOUT; return -1; @@ -801,7 +852,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ } if (socket->state == STATE_PEER_CLOSED) { - if (socket->incoming.pbuf == NULL) { + if (socket->incoming.tcp.pbuf == NULL) { // socket closed and no data left in buffer return 0; } @@ -819,7 +870,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ assert(socket->pcb.tcp != NULL); - struct pbuf *p = socket->incoming.pbuf; + struct pbuf *p = socket->incoming.tcp.pbuf; mp_uint_t remaining = p->len - socket->recv_offset; if (len > remaining) { @@ -828,19 +879,21 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ memcpy(buf, (byte *)p->payload + socket->recv_offset, len); - remaining -= len; - if (remaining == 0) { - socket->incoming.pbuf = p->next; - // If we don't ref here, free() will free the entire chain, - // if we ref, it does what we need: frees 1st buf, and decrements - // next buf's refcount back to 1. - pbuf_ref(p->next); - pbuf_free(p); - socket->recv_offset = 0; - } else { - socket->recv_offset += len; + if ((flags & MSG_PEEK) == 0) { + remaining -= len; + if (remaining == 0) { + socket->incoming.tcp.pbuf = p->next; + // If we don't ref here, free() will free the entire chain, + // if we ref, it does what we need: frees 1st buf, and decrements + // next buf's refcount back to 1. + pbuf_ref(p->next); + pbuf_free(p); + socket->recv_offset = 0; + } else { + socket->recv_offset += len; + } + tcp_recved(socket->pcb.tcp, len); } - tcp_recved(socket->pcb.tcp, len); MICROPY_PY_LWIP_EXIT @@ -854,8 +907,18 @@ static const mp_obj_type_t lwip_socket_type; static void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { lwip_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "<socket state=%d timeout=%d incoming=%p off=%d>", self->state, self->timeout, - self->incoming.pbuf, self->recv_offset); + mp_printf(print, "<socket state=%d timeout=%d incoming=", self->state, self->timeout); + if (self->type == MOD_NETWORK_SOCK_STREAM) { + mp_printf(print, "%p off=%d>", self->incoming.tcp.pbuf, self->recv_offset); + } else { + int num_in_queue = 0; + for (size_t i = 0; i < LWIP_INCOMING_PACKET_QUEUE_LEN; ++i) { + if (self->incoming.udp_raw.array[i].pbuf != NULL) { + ++num_in_queue; + } + } + mp_printf(print, "%d>", num_in_queue); + } } // FIXME: Only supports two arguments at present @@ -884,16 +947,22 @@ static mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s socket->incoming.connection.tcp.item = NULL; break; case MOD_NETWORK_SOCK_DGRAM: - socket->pcb.udp = udp_new(); - socket->incoming.pbuf = NULL; - break; #if MICROPY_PY_LWIP_SOCK_RAW - case MOD_NETWORK_SOCK_RAW: { - mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]); - socket->pcb.raw = raw_new(proto); - break; - } + case MOD_NETWORK_SOCK_RAW: #endif + if (socket->type == MOD_NETWORK_SOCK_DGRAM) { + socket->pcb.udp = udp_new(); + } + #if MICROPY_PY_LWIP_SOCK_RAW + else { + mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]); + socket->pcb.raw = raw_new(proto); + } + #endif + socket->incoming.udp_raw.iget = 0; + socket->incoming.udp_raw.iput = 0; + socket->incoming.udp_raw.array = m_new0(lwip_incoming_packet_t, LWIP_INCOMING_PACKET_QUEUE_LEN); + break; default: mp_raise_OSError(MP_EINVAL); } @@ -1075,7 +1144,7 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) { // ...and set up the new socket for it. socket2->domain = MOD_NETWORK_AF_INET; socket2->type = MOD_NETWORK_SOCK_STREAM; - socket2->incoming.pbuf = NULL; + socket2->incoming.tcp.pbuf = NULL; socket2->timeout = socket->timeout; socket2->state = STATE_CONNECTED; socket2->recv_offset = 0; @@ -1130,8 +1199,8 @@ static mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { socket->state = STATE_NEW; mp_raise_OSError(error_lookup_table[-err]); } - socket->peer_port = (mp_uint_t)port; - memcpy(&socket->peer, &dest, sizeof(socket->peer)); + socket->tcp_peer_addr = dest; + socket->tcp_peer_port = (mp_uint_t)port; MICROPY_PY_LWIP_EXIT // And now we wait... @@ -1216,40 +1285,58 @@ static mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) { } static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_send_obj, lwip_socket_send); -static mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { - lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); +// Common implementation for recv & recvfrom +static mp_obj_t lwip_socket_recv_common(size_t n_args, const mp_obj_t *args, ip_addr_t *ip, mp_uint_t *port) { + lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(args[0]); + mp_int_t len = mp_obj_get_int(args[1]); + mp_int_t flags = n_args > 2 ? mp_obj_get_int(args[2]) : 0; int _errno; + vstr_t vstr; + mp_uint_t ret = 0; lwip_socket_check_connected(socket); - mp_int_t len = mp_obj_get_int(len_in); - vstr_t vstr; vstr_init_len(&vstr, len); - mp_uint_t ret = 0; switch (socket->type) { - case MOD_NETWORK_SOCK_STREAM: { - ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno); + case MOD_NETWORK_SOCK_STREAM: + if (ip != NULL) { + *ip = socket->tcp_peer_addr; + *port = (mp_uint_t)socket->tcp_peer_port; + } + ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, flags, &_errno); break; - } case MOD_NETWORK_SOCK_DGRAM: #if MICROPY_PY_LWIP_SOCK_RAW case MOD_NETWORK_SOCK_RAW: #endif - ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, NULL, NULL, &_errno); + ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, flags, ip, port, &_errno); break; } if (ret == -1) { mp_raise_OSError(_errno); } - if (ret == 0) { return mp_const_empty_bytes; } vstr.len = ret; return mp_obj_new_bytes_from_vstr(&vstr); } -static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recv_obj, lwip_socket_recv); + +static mp_obj_t lwip_socket_recv(size_t n_args, const mp_obj_t *args) { + return lwip_socket_recv_common(n_args, args, NULL, NULL); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_recv_obj, 2, 3, lwip_socket_recv); + +static mp_obj_t lwip_socket_recvfrom(size_t n_args, const mp_obj_t *args) { + ip_addr_t ip; + mp_uint_t port; + mp_obj_t tuple[2]; + tuple[0] = lwip_socket_recv_common(n_args, args, &ip, &port); + tuple[1] = lwip_format_inet_addr(&ip, port); + return mp_obj_new_tuple(2, tuple); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_recvfrom_obj, 2, 3, lwip_socket_recvfrom); static mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); @@ -1284,50 +1371,6 @@ static mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t } static MP_DEFINE_CONST_FUN_OBJ_3(lwip_socket_sendto_obj, lwip_socket_sendto); -static mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { - lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); - int _errno; - - lwip_socket_check_connected(socket); - - mp_int_t len = mp_obj_get_int(len_in); - vstr_t vstr; - vstr_init_len(&vstr, len); - ip_addr_t ip; - mp_uint_t port; - - mp_uint_t ret = 0; - switch (socket->type) { - case MOD_NETWORK_SOCK_STREAM: { - memcpy(&ip, &socket->peer, sizeof(socket->peer)); - port = (mp_uint_t)socket->peer_port; - ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno); - break; - } - case MOD_NETWORK_SOCK_DGRAM: - #if MICROPY_PY_LWIP_SOCK_RAW - case MOD_NETWORK_SOCK_RAW: - #endif - ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, &ip, &port, &_errno); - break; - } - if (ret == -1) { - mp_raise_OSError(_errno); - } - - mp_obj_t tuple[2]; - if (ret == 0) { - tuple[0] = mp_const_empty_bytes; - } else { - vstr.len = ret; - tuple[0] = mp_obj_new_bytes_from_vstr(&vstr); - } - tuple[1] = lwip_format_inet_addr(&ip, port); - - return mp_obj_new_tuple(2, tuple); -} -static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recvfrom_obj, lwip_socket_recvfrom); - static mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in); lwip_socket_check_connected(socket); @@ -1487,12 +1530,12 @@ static mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, i switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: - return lwip_tcp_receive(socket, buf, size, errcode); + return lwip_tcp_receive(socket, buf, size, 0, errcode); case MOD_NETWORK_SOCK_DGRAM: #if MICROPY_PY_LWIP_SOCK_RAW case MOD_NETWORK_SOCK_RAW: #endif - return lwip_raw_udp_receive(socket, buf, size, NULL, NULL, errcode); + return lwip_raw_udp_receive(socket, buf, size, 0, NULL, NULL, errcode); } // Unreachable return MP_STREAM_ERROR; @@ -1537,9 +1580,15 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_ if (lwip_socket_incoming_array(socket)[socket->incoming.connection.iget] != NULL) { ret |= MP_STREAM_POLL_RD; } + } else if (socket->type == MOD_NETWORK_SOCK_STREAM) { + // For TCP sockets there is just one slot for incoming data + if (socket->incoming.tcp.pbuf != NULL) { + ret |= MP_STREAM_POLL_RD; + } } else { - // Otherwise there is just one slot for incoming data - if (socket->incoming.pbuf != NULL) { + // Otherwise for UDP/raw there is a queue of incoming data + lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iget]; + if (slot->pbuf != NULL) { ret |= MP_STREAM_POLL_RD; } } @@ -1858,6 +1907,8 @@ static const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IP_PROTO_TCP) }, { MP_ROM_QSTR(MP_QSTR_TCP_NODELAY), MP_ROM_INT(TCP_NODELAY) }, + { MP_ROM_QSTR(MP_QSTR_MSG_PEEK), MP_ROM_INT(MSG_PEEK) }, + { MP_ROM_QSTR(MP_QSTR_MSG_DONTWAIT), MP_ROM_INT(MSG_DONTWAIT) }, }; static MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table); diff --git a/extmod/modmachine.c b/extmod/modmachine.c index 5906835949..f2570123e3 100644 --- a/extmod/modmachine.c +++ b/extmod/modmachine.c @@ -45,11 +45,11 @@ static void mp_machine_idle(void); #if MICROPY_PY_MACHINE_BOOTLOADER -NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args); +MP_NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args); #endif #if MICROPY_PY_MACHINE_RESET -NORETURN static void mp_machine_reset(void); +MP_NORETURN static void mp_machine_reset(void); static mp_int_t mp_machine_reset_cause(void); #endif @@ -58,7 +58,7 @@ static mp_obj_t mp_machine_unique_id(void); static mp_obj_t mp_machine_get_freq(void); static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args); static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args); -NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args); +MP_NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args); #endif // The port can provide additional machine-module implementation in this file. @@ -67,7 +67,7 @@ NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args); #endif #if MICROPY_PY_MACHINE_BOOTLOADER -NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) { +MP_NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) { mp_machine_bootloader(n_args, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader); @@ -81,7 +81,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); #if MICROPY_PY_MACHINE_RESET -NORETURN static mp_obj_t machine_reset(void) { +MP_NORETURN static mp_obj_t machine_reset(void) { mp_machine_reset(); } MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); @@ -116,7 +116,7 @@ static mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep); -NORETURN static mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { +MP_NORETURN static mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) { mp_machine_deepsleep(n_args, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep); diff --git a/extmod/modmachine.h b/extmod/modmachine.h index 7c16ed302e..26010be8e1 100644 --- a/extmod/modmachine.h +++ b/extmod/modmachine.h @@ -242,7 +242,7 @@ uintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align); uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align); #endif -NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args); +MP_NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args); void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len); mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us); diff --git a/extmod/modnetwork.c b/extmod/modnetwork.c index 336836b6b8..b6855fcaaa 100644 --- a/extmod/modnetwork.c +++ b/extmod/modnetwork.c @@ -40,6 +40,19 @@ #if MICROPY_PY_NETWORK_CYW43 // So that CYW43_LINK_xxx constants are available to MICROPY_PORT_NETWORK_INTERFACES. #include "lib/cyw43-driver/src/cyw43.h" +extern const struct _mp_obj_type_t mp_network_cyw43_type; +#endif + +#if MICROPY_PY_NETWORK_WIZNET5K +extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k; +#endif + +#if MICROPY_PY_NETWORK_NINAW10 +extern const struct _mp_obj_type_t mod_network_nic_type_nina; +#endif + +#if MICROPY_PY_NETWORK_ESP_HOSTED +extern const struct _mp_obj_type_t mod_network_esp_hosted_type; #endif #ifdef MICROPY_PY_NETWORK_INCLUDEFILE @@ -166,6 +179,32 @@ static const mp_rom_map_elem_t mp_module_network_globals_table[] = { MICROPY_PORT_NETWORK_INTERFACES #endif + #if MICROPY_PY_NETWORK_CYW43 + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) }, + // CYW43 status constants, currently for rp2 port only. + // TODO move these to WIFI module for all ports. + #if defined(PICO_PROGRAM_NAME) && defined(CYW43_LINK_DOWN) + { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(CYW43_LINK_DOWN) }, + { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(CYW43_LINK_JOIN) }, + { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(CYW43_LINK_BADAUTH) }, + { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(CYW43_LINK_NONET) }, + { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(CYW43_LINK_FAIL) }, + { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(CYW43_LINK_UP) }, + #endif + #endif + + #if MICROPY_PY_NETWORK_WIZNET5K + { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) }, + #endif + + #if MICROPY_PY_NETWORK_NINAW10 + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_nina) }, + #endif + + #if MICROPY_PY_NETWORK_ESP_HOSTED + { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_esp_hosted_type) }, + #endif + // Allow a port to take mostly full control of the network module. #ifdef MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE #include MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h index 7e5a283353..d16329f07d 100644 --- a/extmod/modnetwork.h +++ b/extmod/modnetwork.h @@ -60,6 +60,11 @@ extern char mod_network_country_code[2]; #define MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN (32) #endif +#if MICROPY_PY_NETWORK_NINAW10 +// This Network interface requires the extended socket state. +#define MICROPY_PY_SOCKET_EXTENDED_STATE (1) +#endif + // This is a null-terminated string. extern char mod_network_hostname_data[MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN + 1]; diff --git a/extmod/modre.c b/extmod/modre.c index 1a118009cb..d17ec68d50 100644 --- a/extmod/modre.c +++ b/extmod/modre.c @@ -427,6 +427,9 @@ static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { const char *re_str = mp_obj_str_get_str(args[0]); int size = re1_5_sizecode(re_str); if (size == -1) { + #if MICROPY_ERROR_REPORTING >= MICROPY_ERROR_REPORTING_NORMAL + mp_raise_ValueError(MP_ERROR_TEXT("regex too complex")); + #endif goto error; } mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, re.insts, char, size, (mp_obj_type_t *)&re_type); diff --git a/extmod/modtls_axtls.c b/extmod/modtls_axtls.c index 0e49fde2d8..ba28c13fce 100644 --- a/extmod/modtls_axtls.c +++ b/extmod/modtls_axtls.c @@ -105,7 +105,7 @@ static const char *const ssl_error_tab2[] = { "NOT_SUPPORTED", }; -static NORETURN void ssl_raise_error(int err) { +static MP_NORETURN void ssl_raise_error(int err) { MP_STATIC_ASSERT(SSL_NOT_OK - 3 == SSL_EAGAIN); MP_STATIC_ASSERT(SSL_ERROR_CONN_LOST - 18 == SSL_ERROR_NOT_SUPPORTED); diff --git a/extmod/modtls_mbedtls.c b/extmod/modtls_mbedtls.c index 6c34805da4..71a14adcff 100644 --- a/extmod/modtls_mbedtls.c +++ b/extmod/modtls_mbedtls.c @@ -147,7 +147,7 @@ static const unsigned char *asn1_get_data(mp_obj_t obj, size_t *out_len) { return (const unsigned char *)str; } -static NORETURN void mbedtls_raise_error(int err) { +static MP_NORETURN void mbedtls_raise_error(int err) { // Handle special cases. if (err == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_OSError(MP_ENOMEM); diff --git a/extmod/moductypes.c b/extmod/moductypes.c index 54abce79e0..eb72f441bb 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -89,7 +89,7 @@ typedef struct _mp_obj_uctypes_struct_t { uint32_t flags; } mp_obj_uctypes_struct_t; -static NORETURN void syntax_error(void) { +static MP_NORETURN void syntax_error(void) { mp_raise_TypeError(MP_ERROR_TEXT("syntax error in uctypes descriptor")); } diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index 1b1b10b407..9ebfa904db 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -143,6 +143,9 @@ static mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) { return mp_obj_new_bool(if_active[self->itf]); } else { bool value = mp_obj_is_true(args[1]); + if (!value && self->itf == CYW43_ITF_STA) { + cyw43_wifi_leave(self->cyw, self->itf); + } cyw43_wifi_set_up(self->cyw, self->itf, value, get_country_code()); if_active[self->itf] = value; return mp_const_none; diff --git a/extmod/network_esp_hosted.c b/extmod/network_esp_hosted.c index 04cfc36b32..6ed348450b 100644 --- a/extmod/network_esp_hosted.c +++ b/extmod/network_esp_hosted.c @@ -48,6 +48,8 @@ #include "esp_hosted_wifi.h" #include "esp_hosted_hal.h" +extern const mp_obj_type_t mod_network_esp_hosted_type; + typedef struct _esp_hosted_obj_t { mp_obj_base_t base; uint32_t itf; diff --git a/extmod/network_ppp_lwip.c b/extmod/network_ppp_lwip.c index 8eb90ea4a6..2c3dac9201 100644 --- a/extmod/network_ppp_lwip.c +++ b/extmod/network_ppp_lwip.c @@ -24,6 +24,10 @@ * THE SOFTWARE. */ +// This file is intended to closely match ports/esp32/network_ppp.c. Changes can +// and should probably be applied to both files. Compare them directly by using: +// git diff --no-index extmod/network_ppp_lwip.c ports/esp32/network_ppp.c + #include "py/runtime.h" #include "py/mphal.h" #include "py/stream.h" @@ -80,7 +84,6 @@ static void network_ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx) { break; case PPPERR_USER: if (self->state >= STATE_ERROR) { - network_ppp_stream_uart_irq_disable(self); // Indicate that we are no longer connected and thus // only need to free the PPP PCB, not close it. self->state = STATE_ACTIVE; @@ -121,6 +124,7 @@ static mp_obj_t network_ppp___del__(mp_obj_t self_in) { self->state = STATE_INACTIVE; ppp_close(self->pcb, 1); } + network_ppp_stream_uart_irq_disable(self); // Free PPP PCB and reset state. self->state = STATE_INACTIVE; ppp_free(self->pcb); @@ -295,7 +299,8 @@ static mp_obj_t network_ppp_connect(size_t n_args, const mp_obj_t *args, mp_map_ ppp_set_auth(self->pcb, parsed_args[ARG_security].u_int, user_str, key_str); } - netif_set_default(self->pcb->netif); + ppp_set_default(self->pcb); + ppp_set_usepeerdns(self->pcb, true); if (ppp_connect(self->pcb, 0) != ERR_OK) { diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index 533d39a187..e065c14866 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -78,6 +78,8 @@ #endif +extern const mp_obj_type_t mod_network_nic_type_wiznet5k; + #ifndef printf #define printf(...) mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__) #endif diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index 6ca0c17267..5e7030e36f 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -60,6 +60,7 @@ static uint8_t nimble_address_mode = BLE_OWN_ADDR_RANDOM; #define NIMBLE_STARTUP_TIMEOUT 2000 +#define NIMBLE_SHUTDOWN_TIMEOUT 500 // Any BLE_HS_xxx code not in this table will default to MP_EIO. static int8_t ble_hs_err_to_errno_table[] = { @@ -554,7 +555,7 @@ static void ble_hs_shutdown_stop_cb(int status, void *arg) { static struct ble_hs_stop_listener ble_hs_shutdown_stop_listener; -void mp_bluetooth_nimble_port_shutdown(void) { +int mp_bluetooth_nimble_port_shutdown(void) { DEBUG_printf("mp_bluetooth_nimble_port_shutdown (nimble default)\n"); // By default, just call ble_hs_stop directly and wait for the stack to stop. @@ -562,9 +563,17 @@ void mp_bluetooth_nimble_port_shutdown(void) { ble_hs_stop(&ble_hs_shutdown_stop_listener, ble_hs_shutdown_stop_cb, NULL); + mp_uint_t timeout_start_ticks_ms = mp_hal_ticks_ms(); while (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { - mp_event_wait_indefinite(); + mp_uint_t elapsed = mp_hal_ticks_ms() - timeout_start_ticks_ms; + if (elapsed > NIMBLE_SHUTDOWN_TIMEOUT) { + // Stack had not responded (via ble_hs_shutdown_stop_cb) + return MP_ETIMEDOUT; + } + + mp_event_wait_ms(NIMBLE_SHUTDOWN_TIMEOUT - elapsed); } + return 0; } #endif // !MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY @@ -659,10 +668,11 @@ int mp_bluetooth_init(void) { return 0; } -void mp_bluetooth_deinit(void) { +int mp_bluetooth_deinit(void) { DEBUG_printf("mp_bluetooth_deinit %d\n", mp_bluetooth_nimble_ble_state); + int ret = 0; if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { - return; + return 0; } // Must call ble_hs_stop() in a port-specific way to stop the background @@ -675,7 +685,7 @@ void mp_bluetooth_deinit(void) { DEBUG_printf("mp_bluetooth_deinit: starting port shutdown\n"); - mp_bluetooth_nimble_port_shutdown(); + ret = mp_bluetooth_nimble_port_shutdown(); assert(mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF); } else { mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF; @@ -692,6 +702,7 @@ void mp_bluetooth_deinit(void) { #endif DEBUG_printf("mp_bluetooth_deinit: shut down\n"); + return ret; } bool mp_bluetooth_is_active(void) { diff --git a/extmod/nimble/modbluetooth_nimble.h b/extmod/nimble/modbluetooth_nimble.h index d9bef64920..0dd20eb658 100644 --- a/extmod/nimble/modbluetooth_nimble.h +++ b/extmod/nimble/modbluetooth_nimble.h @@ -84,7 +84,7 @@ void mp_bluetooth_nimble_port_hci_deinit(void); void mp_bluetooth_nimble_port_start(void); // Tell the port to stop its background task. -void mp_bluetooth_nimble_port_shutdown(void); +int mp_bluetooth_nimble_port_shutdown(void); // --- Called by the HCI UART layer to let us know when packets have been sent. void mp_bluetooth_nimble_sent_hci_packet(void); diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index 4b10ca3aa5..404eab84f4 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -300,7 +300,7 @@ static mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) { struct LFSx_API (info) info; int ret = LFSx_API(stat)(&self->lfs, path, &info); if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) { - mp_raise_OSError(-MP_ENOENT); + mp_raise_OSError(MP_ENOENT); } } |