From 59c3618cbdb0e8627ef701727e5c2178eb321067 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 20 Jan 2023 13:19:59 +0530 Subject: [PATCH 01/29] clone espnow implementation Co-authored-by: Nick Moore Co-authored-by: shawwwn Co-authored-by: glenn20 --- ports/espressif/bindings/espnow/ESPNow.c | 908 +++++++++++++++++++++++ ports/espressif/bindings/espnow/ESPNow.h | 30 + 2 files changed, 938 insertions(+) create mode 100644 ports/espressif/bindings/espnow/ESPNow.c create mode 100644 ports/espressif/bindings/espnow/ESPNow.h diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c new file mode 100644 index 0000000000..0e9da4fc1b --- /dev/null +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -0,0 +1,908 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2020 Nick Moore + * Copyright (c) 2018 shawwwn + * Copyright (c) 2020-2021 Glenn Moloney @glenn20 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include +#include +#include + +#include "esp_log.h" +#include "esp_now.h" +#include "esp_wifi.h" +#include "esp_wifi_types.h" + +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/mperrno.h" +#include "py/obj.h" +#include "py/objstr.h" +#include "py/objarray.h" +#include "py/stream.h" +#include "py/binary.h" +#include "py/ringbuf.h" + +#include "mpconfigport.h" +#include "mphalport.h" +#include "modnetwork.h" +#include "modespnow.h" + +#ifndef MICROPY_ESPNOW_RSSI +// Include code to track rssi of peers +#define MICROPY_ESPNOW_RSSI 1 +#endif +#ifndef MICROPY_ESPNOW_EXTRA_PEER_METHODS +// Include mod_peer(),get_peer(),peer_count() +#define MICROPY_ESPNOW_EXTRA_PEER_METHODS 1 +#endif + +// Relies on gcc Variadic Macros and Statement Expressions +#define NEW_TUPLE(...) \ + ({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z); }) + +static const uint8_t ESPNOW_MAGIC = 0x99; + +// ESPNow packet format for the receive buffer. +// Use this for peeking at the header of the next packet in the buffer. +typedef struct { + uint8_t magic; // = ESPNOW_MAGIC + uint8_t msg_len; // Length of the message + #if MICROPY_ESPNOW_RSSI + uint32_t time_ms; // Timestamp (ms) when packet is received + int8_t rssi; // RSSI value (dBm) (-127 to 0) + #endif // MICROPY_ESPNOW_RSSI +} __attribute__((packed)) espnow_hdr_t; + +typedef struct { + espnow_hdr_t hdr; // The header + uint8_t peer[6]; // Peer address + uint8_t msg[0]; // Message is up to 250 bytes +} __attribute__((packed)) espnow_pkt_t; + +// The maximum length of an espnow packet (bytes) +static const size_t MAX_PACKET_LEN = ( + (sizeof(espnow_pkt_t) + ESP_NOW_MAX_DATA_LEN)); + +// Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes +// Will allocate an additional 7 bytes for buffer overhead +static const size_t DEFAULT_RECV_BUFFER_SIZE = (2 * MAX_PACKET_LEN); + +// Default timeout (millisec) to wait for incoming ESPNow messages (5 minutes). +static const size_t DEFAULT_RECV_TIMEOUT_MS = (5 * 60 * 1000); + +// Time to wait (millisec) for responses from sent packets: (2 seconds). +static const size_t DEFAULT_SEND_TIMEOUT_MS = (2 * 1000); + +// Number of milliseconds to wait for pending responses to sent packets. +// This is a fallback which should never be reached. +static const mp_uint_t PENDING_RESPONSES_TIMEOUT_MS = 100; +static const mp_uint_t PENDING_RESPONSES_BUSY_POLL_MS = 10; + +// The data structure for the espnow_singleton. +typedef struct _esp_espnow_obj_t { + mp_obj_base_t base; + + ringbuf_t *recv_buffer; // A buffer for received packets + size_t recv_buffer_size; // The size of the recv_buffer + size_t recv_timeout_ms; // Timeout for recv() + volatile size_t rx_packets; // # of received packets + size_t dropped_rx_pkts; // # of dropped packets (buffer full) + size_t tx_packets; // # of sent packets + volatile size_t tx_responses; // # of sent packet responses received + volatile size_t tx_failures; // # of sent packet responses failed + size_t peer_count; // Cache the # of peers for send(sync=True) + mp_obj_t recv_cb; // Callback when a packet is received + mp_obj_t recv_cb_arg; // Argument passed to callback + #if MICROPY_ESPNOW_RSSI + mp_obj_t peers_table; // A dictionary of discovered peers + #endif // MICROPY_ESPNOW_RSSI +} esp_espnow_obj_t; + +const mp_obj_type_t esp_espnow_type; + +// ### Initialisation and Config functions +// + +// Return a pointer to the ESPNow module singleton +// If state == INITIALISED check the device has been initialised. +// Raises OSError if not initialised and state == INITIALISED. +static esp_espnow_obj_t *_get_singleton() { + return MP_STATE_PORT(espnow_singleton); +} + +static esp_espnow_obj_t *_get_singleton_initialised() { + esp_espnow_obj_t *self = _get_singleton(); + // assert(self); + if (self->recv_buffer == NULL) { + // Throw an espnow not initialised error + check_esp_err(ESP_ERR_ESPNOW_NOT_INIT); + } + return self; +} + +// Allocate and initialise the ESPNow module as a singleton. +// Returns the initialised espnow_singleton. +STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + + // The espnow_singleton must be defined in MICROPY_PORT_ROOT_POINTERS + // (see mpconfigport.h) to prevent memory allocated here from being + // garbage collected. + // NOTE: on soft reset the espnow_singleton MUST be set to NULL and the + // ESP-NOW functions de-initialised (see main.c). + esp_espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); + if (self != NULL) { + return self; + } + self = m_new_obj(esp_espnow_obj_t); + self->base.type = &esp_espnow_type; + self->recv_buffer_size = DEFAULT_RECV_BUFFER_SIZE; + self->recv_timeout_ms = DEFAULT_RECV_TIMEOUT_MS; + self->recv_buffer = NULL; // Buffer is allocated in espnow_init() + self->recv_cb = mp_const_none; + #if MICROPY_ESPNOW_RSSI + self->peers_table = mp_obj_new_dict(0); + // Prevent user code modifying the dict + mp_obj_dict_get_map(self->peers_table)->is_fixed = 1; + #endif // MICROPY_ESPNOW_RSSI + + // Set the global singleton pointer for the espnow protocol. + MP_STATE_PORT(espnow_singleton) = self; + + return self; +} + +// Forward declare the send and recv ESPNow callbacks +STATIC void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status); + +STATIC void recv_cb(const uint8_t *mac_addr, const uint8_t *data, int len); + +// ESPNow.init(): Initialise the data buffers and ESP-NOW functions. +// Initialise the Espressif ESPNOW software stack, register callbacks and +// allocate the recv data buffers. +// Returns None. +static mp_obj_t espnow_init(mp_obj_t _) { + esp_espnow_obj_t *self = _get_singleton(); + if (self->recv_buffer == NULL) { // Already initialised + self->recv_buffer = m_new_obj(ringbuf_t); + ringbuf_alloc(self->recv_buffer, self->recv_buffer_size); + + esp_initialise_wifi(); // Call the wifi init code in network_wlan.c + check_esp_err(esp_now_init()); + check_esp_err(esp_now_register_recv_cb(recv_cb)); + check_esp_err(esp_now_register_send_cb(send_cb)); + } + return mp_const_none; +} + +// ESPNow.deinit(): De-initialise the ESPNOW software stack, disable callbacks +// and deallocate the recv data buffers. +// Note: this function is called from main.c:mp_task() to cleanup before soft +// reset, so cannot be declared STATIC and must guard against self == NULL;. +mp_obj_t espnow_deinit(mp_obj_t _) { + esp_espnow_obj_t *self = _get_singleton(); + if (self != NULL && self->recv_buffer != NULL) { + check_esp_err(esp_now_unregister_recv_cb()); + check_esp_err(esp_now_unregister_send_cb()); + check_esp_err(esp_now_deinit()); + self->recv_buffer->buf = NULL; + self->recv_buffer = NULL; + self->peer_count = 0; // esp_now_deinit() removes all peers. + self->tx_packets = self->tx_responses; + } + return mp_const_none; +} + +STATIC mp_obj_t espnow_active(size_t n_args, const mp_obj_t *args) { + esp_espnow_obj_t *self = _get_singleton(); + if (n_args > 1) { + if (mp_obj_is_true(args[1])) { + espnow_init(self); + } else { + espnow_deinit(self); + } + } + return self->recv_buffer != NULL ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_active_obj, 1, 2, espnow_active); + +// ESPNow.config(['param'|param=value, ..]) +// Get or set configuration values. Supported config params: +// buffer: size of buffer for rx packets (default=514 bytes) +// timeout: Default read timeout (default=300,000 milliseconds) +STATIC mp_obj_t espnow_config( + size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + esp_espnow_obj_t *self = _get_singleton(); + enum { ARG_get, ARG_buffer, ARG_timeout, ARG_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (args[ARG_buffer].u_int >= 0) { + self->recv_buffer_size = args[ARG_buffer].u_int; + } + if (args[ARG_timeout].u_int >= 0) { + self->recv_timeout_ms = args[ARG_timeout].u_int; + } + if (args[ARG_rate].u_int >= 0) { + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) + esp_initialise_wifi(); // Call the wifi init code in network_wlan.c + check_esp_err(esp_wifi_config_espnow_rate( + ESP_IF_WIFI_STA, args[ARG_rate].u_int)); + check_esp_err(esp_wifi_config_espnow_rate( + ESP_IF_WIFI_AP, args[ARG_rate].u_int)); + #else + mp_raise_ValueError(MP_ERROR_TEXT("rate option not supported")); + #endif + } + if (args[ARG_get].u_obj == MP_OBJ_NULL) { + return mp_const_none; + } +#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) + // Return the value of the requested parameter + uintptr_t name = (uintptr_t)args[ARG_get].u_obj; + if (name == QS(MP_QSTR_buffer)) { + return mp_obj_new_int(self->recv_buffer_size); + } else if (name == QS(MP_QSTR_timeout)) { + return mp_obj_new_int(self->recv_timeout_ms); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); + } +#undef QS + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_config_obj, 1, espnow_config); + +// ESPNow.on_recv(recv_cb) +// Set callback function to be invoked when a message is received. +STATIC mp_obj_t espnow_on_recv(size_t n_args, const mp_obj_t *args) { + esp_espnow_obj_t *self = _get_singleton(); + mp_obj_t recv_cb = args[1]; + if (recv_cb != mp_const_none && !mp_obj_is_callable(recv_cb)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid handler")); + } + self->recv_cb = recv_cb; + self->recv_cb_arg = (n_args > 2) ? args[2] : mp_const_none; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_on_recv_obj, 2, 3, espnow_on_recv); + +// ESPnow.stats(): Provide some useful stats. +// Returns a tuple of: +// (tx_pkts, tx_responses, tx_failures, rx_pkts, dropped_rx_pkts) +STATIC mp_obj_t espnow_stats(mp_obj_t _) { + const esp_espnow_obj_t *self = _get_singleton(); + return NEW_TUPLE( + mp_obj_new_int(self->tx_packets), + mp_obj_new_int(self->tx_responses), + mp_obj_new_int(self->tx_failures), + mp_obj_new_int(self->rx_packets), + mp_obj_new_int(self->dropped_rx_pkts)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_stats_obj, espnow_stats); + +#if MICROPY_ESPNOW_RSSI +// ### Maintaining the peer table and reading RSSI values +// +// We maintain a peers table for several reasons, to: +// - support monitoring the RSSI values for all peers; and +// - to return unique bytestrings for each peer which supports more efficient +// application memory usage and peer handling. + +// Get the RSSI value from the wifi packet header +static inline int8_t _get_rssi_from_wifi_pkt(const uint8_t *msg) { + // Warning: Secret magic to get the rssi from the wifi packet header + // See espnow.c:espnow_recv_cb() at https://github.com/espressif/esp-now/ + // In the wifi packet the msg comes after a wifi_promiscuous_pkt_t + // and a espnow_frame_format_t. + // Backtrack to get a pointer to the wifi_promiscuous_pkt_t. + static const size_t sizeof_espnow_frame_format = 39; + wifi_promiscuous_pkt_t *wifi_pkt = (wifi_promiscuous_pkt_t *)( + msg - sizeof_espnow_frame_format - sizeof(wifi_promiscuous_pkt_t)); + + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) + return wifi_pkt->rx_ctrl.rssi - 100; // Offset rssi for IDF 4.0.2 + #else + return wifi_pkt->rx_ctrl.rssi; + #endif +} + +// Lookup a peer in the peers table and return a reference to the item in the +// peers_table. Add peer to the table if it is not found (may alloc memory). +// Will not return NULL. +static mp_map_elem_t *_lookup_add_peer( + esp_espnow_obj_t *self, const uint8_t *peer) { + + // We do not want to allocate any new memory in the case that the peer + // already exists in the peers_table (which is almost all the time). + // So, we use a byte string on the stack and look that up in the dict. + mp_map_t *map = mp_obj_dict_get_map(self->peers_table); + mp_obj_str_t peer_obj = {{&mp_type_bytes}, 0, ESP_NOW_ETH_ALEN, peer}; + mp_map_elem_t *item = mp_map_lookup(map, &peer_obj, MP_MAP_LOOKUP); + if (item == NULL) { + // If not found, add the peer using a new bytestring + map->is_fixed = 0; // Allow to modify the dict + mp_obj_t new_peer = mp_obj_new_bytes(peer, ESP_NOW_ETH_ALEN); + item = mp_map_lookup(map, new_peer, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + item->value = mp_obj_new_list(2, NULL); + map->is_fixed = 1; // Relock the dict + } + return item; +} + +// Update the peers table with the new rssi value from a received pkt and +// return a reference to the item in the peers_table. +static mp_map_elem_t *_update_rssi( + const uint8_t *peer, int8_t rssi, uint32_t time_ms) { + + esp_espnow_obj_t *self = _get_singleton_initialised(); + // Lookup the peer in the device table + mp_map_elem_t *item = _lookup_add_peer(self, peer); + mp_obj_list_t *list = MP_OBJ_TO_PTR(item->value); + list->items[0] = MP_OBJ_NEW_SMALL_INT(rssi); + list->items[1] = mp_obj_new_int(time_ms); + return item; +} +#endif // MICROPY_ESPNOW_RSSI + +// ### Handling espnow packets in the recv buffer +// + +// ### Send and Receive ESP_Now data +// + +// Return C pointer to byte memory string/bytes/bytearray in obj. +// Raise ValueError if the length does not match expected len. +static uint8_t *_get_bytes_len_rw(mp_obj_t obj, size_t len, mp_uint_t rw) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(obj, &bufinfo, rw); + if (bufinfo.len != len) { + mp_raise_ValueError( + MP_ERROR_TEXT("ESPNow: bytes or bytearray wrong length")); + } + return (uint8_t *)bufinfo.buf; +} + +static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len) { + return _get_bytes_len_rw(obj, len, MP_BUFFER_READ); +} + +static uint8_t *_get_bytes_len_w(mp_obj_t obj, size_t len) { + return _get_bytes_len_rw(obj, len, MP_BUFFER_WRITE); +} + +// Return C pointer to the MAC address. +// Raise ValueError if mac_addr is wrong type or is not 6 bytes long. +static const uint8_t *_get_peer(mp_obj_t mac_addr) { + return mp_obj_is_true(mac_addr) + ? _get_bytes_len(mac_addr, ESP_NOW_ETH_ALEN) : NULL; +} + +// Copy data from the ring buffer - wait if buffer is empty up to timeout_ms +int ringbuf_read_wait(ringbuf_t *r, void *data, size_t len, int timeout_ms) { + int64_t end = mp_hal_ticks_ms() + timeout_ms; + int status = 0; + while ( + ((status = ringbuf_read(r, data, len)) == 0) && + (end - (int64_t)mp_hal_ticks_ms()) >= 0) { + MICROPY_EVENT_POLL_HOOK; + } + return status; +} + +// ESPNow.recvinto(buffers[, timeout_ms]): +// Waits for an espnow message and copies the peer_addr and message into +// the buffers list. +// Arguments: +// buffers: (Optional) list of bytearrays to store return values. +// timeout_ms: (Optional) timeout in milliseconds (or None). +// Buffers should be a list: [bytearray(6), bytearray(250)] +// If buffers is 4 elements long, the rssi and timestamp values will be +// loaded into the 3rd and 4th elements. +// Default timeout is set with ESPNow.config(timeout=milliseconds). +// Return (None, None) on timeout. +STATIC mp_obj_t espnow_recvinto(size_t n_args, const mp_obj_t *args) { + esp_espnow_obj_t *self = _get_singleton_initialised(); + + size_t timeout_ms = ((n_args > 2 && args[2] != mp_const_none) + ? mp_obj_get_int(args[2]) : self->recv_timeout_ms); + + mp_obj_list_t *list = MP_OBJ_TO_PTR(args[1]); + if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) { + mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recvinto(): Invalid argument")); + } + mp_obj_array_t *msg = MP_OBJ_TO_PTR(list->items[1]); + if (mp_obj_is_type(msg, &mp_type_bytearray)) { + msg->len += msg->free; // Make all the space in msg array available + msg->free = 0; + } + #if MICROPY_ESPNOW_RSSI + uint8_t peer_buf[ESP_NOW_ETH_ALEN]; + #else + uint8_t *peer_buf = _get_bytes_len_w(list->items[0], ESP_NOW_ETH_ALEN); + #endif // MICROPY_ESPNOW_RSSI + uint8_t *msg_buf = _get_bytes_len_w(msg, ESP_NOW_MAX_DATA_LEN); + + // Read the packet header from the incoming buffer + espnow_hdr_t hdr; + if (ringbuf_read_wait(self->recv_buffer, &hdr, sizeof(hdr), timeout_ms) < 1) { + return MP_OBJ_NEW_SMALL_INT(0); // Timeout waiting for packet + } + int msg_len = hdr.msg_len; + + // Check the message packet header format and read the message data + if (hdr.magic != ESPNOW_MAGIC || + msg_len > ESP_NOW_MAX_DATA_LEN || + ringbuf_read(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) < 1 || + ringbuf_read(self->recv_buffer, msg_buf, msg_len) < 1) { + mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recv(): buffer error")); + } + if (mp_obj_is_type(msg, &mp_type_bytearray)) { + // Set the length of the message bytearray. + size_t size = msg->len + msg->free; + msg->len = msg_len; + msg->free = size - msg_len; + } + + #if MICROPY_ESPNOW_RSSI + // Update rssi value in the peer device table + mp_map_elem_t *entry = _update_rssi(peer_buf, hdr.rssi, hdr.time_ms); + list->items[0] = entry->key; // Set first element of list to peer + if (list->len >= 4) { + list->items[2] = MP_OBJ_NEW_SMALL_INT(hdr.rssi); + list->items[3] = mp_obj_new_int(hdr.time_ms); + } + #endif // MICROPY_ESPNOW_RSSI + + return MP_OBJ_NEW_SMALL_INT(msg_len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_recvinto_obj, 2, 3, espnow_recvinto); + +// Test if data is available to read from the buffers +STATIC mp_obj_t espnow_any(const mp_obj_t _) { + esp_espnow_obj_t *self = _get_singleton_initialised(); + + return ringbuf_avail(self->recv_buffer) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_any_obj, espnow_any); + +// Used by espnow_send() for sends() with sync==True. +// Wait till all pending sent packet responses have been received. +// ie. self->tx_responses == self->tx_packets. +static void _wait_for_pending_responses(esp_espnow_obj_t *self) { + mp_uint_t start = mp_hal_ticks_ms(); + mp_uint_t t; + while (self->tx_responses < self->tx_packets) { + if ((t = mp_hal_ticks_ms() - start) > PENDING_RESPONSES_TIMEOUT_MS) { + mp_raise_OSError(MP_ETIMEDOUT); + } + if (t > PENDING_RESPONSES_BUSY_POLL_MS) { + // After 10ms of busy waiting give other tasks a look in. + MICROPY_EVENT_POLL_HOOK; + } + } +} + +// ESPNow.send(peer_addr, message, [sync (=true), size]) +// ESPNow.send(message) +// Send a message to the peer's mac address. Optionally wait for a response. +// If peer_addr == None or any non-true value, send to all registered peers. +// If sync == True, wait for response after sending. +// If size is provided it should be the number of bytes in message to send(). +// Returns: +// True if sync==False and message sent successfully. +// True if sync==True and message is received successfully by all recipients +// False if sync==True and message is not received by at least one recipient +// Raises: EAGAIN if the internal espnow buffers are full. +STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) { + esp_espnow_obj_t *self = _get_singleton_initialised(); + // Check the various combinations of input arguments + const uint8_t *peer = (n_args > 2) ? _get_peer(args[1]) : NULL; + mp_obj_t msg = (n_args > 2) ? args[2] : (n_args == 2) ? args[1] : MP_OBJ_NULL; + bool sync = n_args <= 3 || args[3] == mp_const_none || mp_obj_is_true(args[3]); + + // Get a pointer to the data buffer of the message + mp_buffer_info_t message; + mp_get_buffer_raise(msg, &message, MP_BUFFER_READ); + + if (sync) { + // Flush out any pending responses. + // If the last call was sync==False there may be outstanding responses + // still to be received (possible many if we just had a burst of + // unsync send()s). We need to wait for all pending responses if this + // call has sync=True. + _wait_for_pending_responses(self); + } + int saved_failures = self->tx_failures; + // Send the packet - try, try again if internal esp-now buffers are full. + esp_err_t err; + int64_t start = mp_hal_ticks_ms(); + while ((ESP_ERR_ESPNOW_NO_MEM == + (err = esp_now_send(peer, message.buf, message.len))) && + (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { + MICROPY_EVENT_POLL_HOOK; + } + check_esp_err(err); // Will raise OSError if e != ESP_OK + // Increment the sent packet count. If peer_addr==NULL msg will be + // sent to all peers EXCEPT any broadcast or multicast addresses. + self->tx_packets += ((peer == NULL) ? self->peer_count : 1); + if (sync) { + // Wait for and tally all the expected responses from peers + _wait_for_pending_responses(self); + } + // Return False if sync and any peers did not respond. + return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_send_obj, 2, 4, espnow_send); + +// ### The ESP_Now send and recv callback routines +// + +// Callback triggered when a sent packet is acknowledged by the peer (or not). +// Just count the number of responses and number of failures. +// These are used in the send() logic. +STATIC void send_cb( + const uint8_t *mac_addr, esp_now_send_status_t status) { + + esp_espnow_obj_t *self = _get_singleton(); + self->tx_responses++; + if (status != ESP_NOW_SEND_SUCCESS) { + self->tx_failures++; + } +} + +// Callback triggered when an ESP-Now packet is received. +// Write the peer MAC address and the message into the recv_buffer as an +// ESPNow packet. +// If the buffer is full, drop the message and increment the dropped count. +// Schedules the user callback if one has been registered (ESPNow.config()). +STATIC void recv_cb( + const uint8_t *mac_addr, const uint8_t *msg, int msg_len) { + + esp_espnow_obj_t *self = _get_singleton(); + ringbuf_t *buf = self->recv_buffer; + // TODO: Test this works with ">". + if (sizeof(espnow_pkt_t) + msg_len >= ringbuf_free(buf)) { + self->dropped_rx_pkts++; + return; + } + espnow_hdr_t header; + header.magic = ESPNOW_MAGIC; + header.msg_len = msg_len; + #if MICROPY_ESPNOW_RSSI + header.rssi = _get_rssi_from_wifi_pkt(msg); + header.time_ms = mp_hal_ticks_ms(); + #endif // MICROPY_ESPNOW_RSSI + + ringbuf_write(buf, &header, sizeof(header)); + ringbuf_write(buf, mac_addr, ESP_NOW_ETH_ALEN); + ringbuf_write(buf, msg, msg_len); + self->rx_packets++; + if (self->recv_cb != mp_const_none) { + mp_sched_schedule(self->recv_cb, self->recv_cb_arg); + } +} + +// ### Peer Management Functions +// + +// Set the ESP-NOW Primary Master Key (pmk) (for encrypted communications). +// Raise OSError if ESP-NOW functions are not initialised. +// Raise ValueError if key is not a bytes-like object exactly 16 bytes long. +STATIC mp_obj_t espnow_set_pmk(mp_obj_t _, mp_obj_t key) { + check_esp_err(esp_now_set_pmk(_get_bytes_len(key, ESP_NOW_KEY_LEN))); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); + +// Common code for add_peer() and mod_peer() to process the args and kw_args: +// Raise ValueError if the LMK is not a bytes-like object of exactly 16 bytes. +// Raise TypeError if invalid keyword args or too many positional args. +// Return true if all args parsed correctly. +STATIC bool _update_peer_info( + esp_now_peer_info_t *peer, size_t n_args, + const mp_obj_t *pos_args, mp_map_t *kw_args) { + + enum { ARG_lmk, ARG_channel, ARG_ifidx, ARG_encrypt }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_lmk, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_channel, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_ifidx, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_encrypt, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, args); + if (args[ARG_lmk].u_obj != mp_const_none) { + mp_obj_t obj = args[ARG_lmk].u_obj; + peer->encrypt = mp_obj_is_true(obj); + if (peer->encrypt) { + // Key must be 16 bytes in length. + memcpy(peer->lmk, + _get_bytes_len(obj, ESP_NOW_KEY_LEN), + ESP_NOW_KEY_LEN); + } + } + if (args[ARG_channel].u_obj != mp_const_none) { + peer->channel = mp_obj_get_int(args[ARG_channel].u_obj); + } + if (args[ARG_ifidx].u_obj != mp_const_none) { + peer->ifidx = mp_obj_get_int(args[ARG_ifidx].u_obj); + } + if (args[ARG_encrypt].u_obj != mp_const_none) { + peer->encrypt = mp_obj_is_true(args[ARG_encrypt].u_obj); + } + return true; +} + +// Update the cached peer count in self->peer_count; +// The peer_count ignores broadcast and multicast addresses and is used for the +// send() logic and is updated from add_peer(), mod_peer() and del_peer(). +STATIC void _update_peer_count() { + esp_espnow_obj_t *self = _get_singleton_initialised(); + + esp_now_peer_info_t peer = {0}; + bool from_head = true; + int count = 0; + // esp_now_fetch_peer() skips over any broadcast or multicast addresses + while (esp_now_fetch_peer(from_head, &peer) == ESP_OK) { + from_head = false; + if (++count >= ESP_NOW_MAX_TOTAL_PEER_NUM) { + break; // Should not happen + } + } + self->peer_count = count; +} + +// ESPNow.add_peer(peer_mac, [lmk, [channel, [ifidx, [encrypt]]]]) or +// ESPNow.add_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], +// [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) +// Positional args set to None will be left at defaults. +// Raise OSError if ESPNow.init() has not been called. +// Raise ValueError if mac or LMK are not bytes-like objects or wrong length. +// Raise TypeError if invalid keyword args or too many positional args. +// Return None. +STATIC mp_obj_t espnow_add_peer( + size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + + esp_now_peer_info_t peer = {0}; + memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN); + _update_peer_info(&peer, n_args - 2, args + 2, kw_args); + + check_esp_err(esp_now_add_peer(&peer)); + _update_peer_count(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_add_peer_obj, 2, espnow_add_peer); + +// ESPNow.del_peer(peer_mac): Unregister peer_mac. +// Raise OSError if ESPNow.init() has not been called. +// Raise ValueError if peer is not a bytes-like objects or wrong length. +// Return None. +STATIC mp_obj_t espnow_del_peer(mp_obj_t _, mp_obj_t peer) { + uint8_t peer_addr[ESP_NOW_ETH_ALEN]; + memcpy(peer_addr, _get_peer(peer), ESP_NOW_ETH_ALEN); + + check_esp_err(esp_now_del_peer(peer_addr)); + _update_peer_count(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_del_peer_obj, espnow_del_peer); + +// Convert a peer_info struct to python tuple +// Used by espnow_get_peer() and espnow_get_peers() +static mp_obj_t _peer_info_to_tuple(const esp_now_peer_info_t *peer) { + return NEW_TUPLE( + mp_obj_new_bytes(peer->peer_addr, MP_ARRAY_SIZE(peer->peer_addr)), + mp_obj_new_bytes(peer->lmk, MP_ARRAY_SIZE(peer->lmk)), + mp_obj_new_int(peer->channel), + mp_obj_new_int(peer->ifidx), + (peer->encrypt) ? mp_const_true : mp_const_false); +} + +// ESPNow.get_peers(): Fetch peer_info records for all registered ESPNow peers. +// Raise OSError if ESPNow.init() has not been called. +// Return a tuple of tuples: +// ((peer_addr, lmk, channel, ifidx, encrypt), +// (peer_addr, lmk, channel, ifidx, encrypt), ...) +STATIC mp_obj_t espnow_get_peers(mp_obj_t _) { + esp_espnow_obj_t *self = _get_singleton_initialised(); + + // Build and initialise the peer info tuple. + mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->peer_count, NULL); + esp_now_peer_info_t peer = {0}; + for (int i = 0; i < peerinfo_tuple->len; i++) { + int status = esp_now_fetch_peer((i == 0), &peer); + peerinfo_tuple->items[i] = + (status == ESP_OK ? _peer_info_to_tuple(&peer) : mp_const_none); + } + + return peerinfo_tuple; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_obj, espnow_get_peers); + +#if MICROPY_ESPNOW_EXTRA_PEER_METHODS +// ESPNow.get_peer(peer_mac): Get the peer info for peer_mac as a tuple. +// Raise OSError if ESPNow.init() has not been called. +// Raise ValueError if mac or LMK are not bytes-like objects or wrong length. +// Return a tuple of (peer_addr, lmk, channel, ifidx, encrypt). +STATIC mp_obj_t espnow_get_peer(mp_obj_t _, mp_obj_t arg1) { + esp_now_peer_info_t peer = {0}; + memcpy(peer.peer_addr, _get_peer(arg1), ESP_NOW_ETH_ALEN); + + check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); + + return _peer_info_to_tuple(&peer); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_get_peer_obj, espnow_get_peer); + +// ESPNow.mod_peer(peer_mac, [lmk, [channel, [ifidx, [encrypt]]]]) or +// ESPNow.mod_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], +// [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) +// Positional args set to None will be left at current values. +// Raise OSError if ESPNow.init() has not been called. +// Raise ValueError if mac or LMK are not bytes-like objects or wrong length. +// Raise TypeError if invalid keyword args or too many positional args. +// Return None. +STATIC mp_obj_t espnow_mod_peer( + size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + + esp_now_peer_info_t peer = {0}; + memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN); + check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); + + _update_peer_info(&peer, n_args - 2, args + 2, kw_args); + + check_esp_err(esp_now_mod_peer(&peer)); + _update_peer_count(); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_mod_peer_obj, 2, espnow_mod_peer); + +// ESPNow.espnow_peer_count(): Get the number of registered peers. +// Raise OSError if ESPNow.init() has not been called. +// Return a tuple of (num_total_peers, num_encrypted_peers). +STATIC mp_obj_t espnow_peer_count(mp_obj_t _) { + esp_now_peer_num_t peer_num = {0}; + check_esp_err(esp_now_get_peer_num(&peer_num)); + + return NEW_TUPLE( + mp_obj_new_int(peer_num.total_num), + mp_obj_new_int(peer_num.encrypt_num)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_count_obj, espnow_peer_count); +#endif + +STATIC const mp_rom_map_elem_t esp_espnow_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&espnow_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&espnow_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_on_recv), MP_ROM_PTR(&espnow_on_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_stats), MP_ROM_PTR(&espnow_stats_obj) }, + + // Send and receive messages + { MP_ROM_QSTR(MP_QSTR_recvinto), MP_ROM_PTR(&espnow_recvinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&espnow_any_obj) }, + + // Peer management functions + { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) }, + { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_del_peer), MP_ROM_PTR(&espnow_del_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_peers), MP_ROM_PTR(&espnow_get_peers_obj) }, + #if MICROPY_ESPNOW_EXTRA_PEER_METHODS + { MP_ROM_QSTR(MP_QSTR_mod_peer), MP_ROM_PTR(&espnow_mod_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_peer), MP_ROM_PTR(&espnow_get_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_peer_count), MP_ROM_PTR(&espnow_peer_count_obj) }, + #endif // MICROPY_ESPNOW_EXTRA_PEER_METHODS +}; +STATIC MP_DEFINE_CONST_DICT(esp_espnow_locals_dict, esp_espnow_locals_dict_table); + +STATIC const mp_rom_map_elem_t espnow_globals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__espnow) }, + { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&esp_espnow_type) }, + { MP_ROM_QSTR(MP_QSTR_MAX_DATA_LEN), MP_ROM_INT(ESP_NOW_MAX_DATA_LEN)}, + { MP_ROM_QSTR(MP_QSTR_ETH_ALEN), MP_ROM_INT(ESP_NOW_ETH_ALEN)}, + { MP_ROM_QSTR(MP_QSTR_KEY_LEN), MP_ROM_INT(ESP_NOW_KEY_LEN)}, + { MP_ROM_QSTR(MP_QSTR_MAX_TOTAL_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_TOTAL_PEER_NUM)}, + { MP_ROM_QSTR(MP_QSTR_MAX_ENCRYPT_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_ENCRYPT_PEER_NUM)}, +}; +STATIC MP_DEFINE_CONST_DICT(espnow_globals_dict, espnow_globals_dict_table); + +// ### Dummy Buffer Protocol support +// ...so asyncio can poll.ipoll() on this device + +// Support ioctl(MP_STREAM_POLL, ) for asyncio +STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, + uintptr_t arg, int *errcode) { + if (request != MP_STREAM_POLL) { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } + esp_espnow_obj_t *self = _get_singleton(); + return (self->recv_buffer == NULL) ? 0 : // If not initialised + arg ^ ( + // If no data in the buffer, unset the Read ready flag + ((ringbuf_avail(self->recv_buffer) == 0) ? MP_STREAM_POLL_RD : 0) | + // If still waiting for responses, unset the Write ready flag + ((self->tx_responses < self->tx_packets) ? MP_STREAM_POLL_WR : 0)); +} + +STATIC const mp_stream_p_t espnow_stream_p = { + .ioctl = espnow_stream_ioctl, +}; + +#if MICROPY_ESPNOW_RSSI +// Return reference to the dictionary of peers we have seen: +// {peer1: (rssi, time_sec), peer2: (rssi, time_msec), ...} +// where: +// peerX is a byte string containing the 6-byte mac address of the peer, +// rssi is the wifi signal strength from the last msg received +// (in dBm from -127 to 0) +// time_sec is the time in milliseconds since device last booted. +STATIC void espnow_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + esp_espnow_obj_t *self = _get_singleton(); + if (dest[0] != MP_OBJ_NULL) { // Only allow "Load" operation + return; + } + if (attr == MP_QSTR_peers_table) { + dest[0] = self->peers_table; + return; + } + dest[1] = MP_OBJ_SENTINEL; // Attribute not found +} +#endif // MICROPY_ESPNOW_RSSI + +MP_DEFINE_CONST_OBJ_TYPE( + esp_espnow_type, + MP_QSTR_ESPNow, + MP_TYPE_FLAG_NONE, + make_new, espnow_make_new, + #if MICROPY_ESPNOW_RSSI + attr, espnow_attr, + #endif // MICROPY_ESPNOW_RSSI + protocol, &espnow_stream_p, + locals_dict, &esp_espnow_locals_dict + ); + +const mp_obj_module_t mp_module_espnow = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&espnow_globals_dict, +}; + +MP_REGISTER_MODULE(MP_QSTR__espnow, mp_module_espnow); +MP_REGISTER_ROOT_POINTER(struct _esp_espnow_obj_t *espnow_singleton); diff --git a/ports/espressif/bindings/espnow/ESPNow.h b/ports/espressif/bindings/espnow/ESPNow.h new file mode 100644 index 0000000000..3c6280b1ce --- /dev/null +++ b/ports/espressif/bindings/espnow/ESPNow.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Glenn Moloney @glenn20 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +// Called from main.c:mp_task() to reset the espnow software stack +mp_obj_t espnow_deinit(mp_obj_t _); From 7330c638b9abe1e84b4b6d45f2c0c78179985aea Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 20 Jan 2023 13:27:00 +0530 Subject: [PATCH 02/29] minimal changes to make espnow work --- locale/circuitpython.pot | 33 ++++++ ports/espressif/Makefile | 5 + ports/espressif/bindings/espnow/ESPNow.c | 109 ++++++++++++------ ports/espressif/bindings/espnow/ESPNow.h | 7 +- .../common-hal/_bleio/CharacteristicBuffer.c | 9 +- .../espressif/common-hal/_bleio/Connection.c | 7 +- .../common-hal/_bleio/PacketBuffer.c | 7 +- ports/espressif/mpconfigport.h | 18 +-- ports/espressif/mpconfigport.mk | 1 + ports/espressif/supervisor/port.c | 5 + py/circuitpy_mpconfig.mk | 3 + py/ringbuf.c | 44 +++++++ py/ringbuf.h | 10 ++ 13 files changed, 203 insertions(+), 55 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index b98bddec50..33effc9612 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -663,6 +663,7 @@ msgstr "" #: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h #: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h msgid "Button A was pressed at start up.\n" msgstr "" @@ -917,6 +918,18 @@ msgstr "" msgid "ESP-IDF memory allocation failed" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "ESPNow.recv(): buffer error" +msgstr "" + +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "ESPNow.recvinto(): Invalid argument" +msgstr "" + +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "ESPNow: bytes or bytearray wrong length" +msgstr "" + #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/ps2io/Ps2.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -2429,6 +2442,10 @@ msgstr "" msgid "addresses is empty" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "an error occured" +msgstr "" + #: py/compile.c msgid "annotation must be an identifier" msgstr "" @@ -2953,6 +2970,10 @@ msgid "" "documentation for instructions." msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "espnow not inited" +msgstr "" + #: py/runtime.c msgid "exceptions must derive from BaseException" msgstr "" @@ -3314,6 +3335,10 @@ msgstr "" msgid "invalid format specifier" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "invalid handler" +msgstr "" + #: shared-bindings/wifi/Radio.c msgid "invalid hostname" msgstr "" @@ -3858,6 +3883,10 @@ msgstr "" msgid "queue overflow" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "rate option not supported" +msgstr "" + #: py/parse.c msgid "raw f-strings are not supported" msgstr "" @@ -4153,6 +4182,10 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "unknown config param" +msgstr "" + #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index ddfcaeeb6e..92e91e808a 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -259,6 +259,11 @@ CFLAGS += -isystem esp32-camera/driver/include CFLAGS += -isystem esp32-camera/conversions/include endif +ifneq ($(CIRCUITPY_ESPNOW),0) +SRC_ESPNOW := $(wildcard bindings/espnow/*.c) +SRC_C += $(SRC_ESPNOW) +endif + ifneq ($(CIRCUITPY_ESPULP),0) SRC_ULP := \ $(wildcard common-hal/espulp/*.c) \ diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 0e9da4fc1b..33cf2342b8 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -6,6 +6,7 @@ * Copyright (c) 2017-2020 Nick Moore * Copyright (c) 2018 shawwwn * Copyright (c) 2020-2021 Glenn Moloney @glenn20 + * Copyright (c) 2023 MicroDev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +27,6 @@ * THE SOFTWARE. */ - #include #include #include @@ -48,8 +48,10 @@ #include "mpconfigport.h" #include "mphalport.h" -#include "modnetwork.h" -#include "modespnow.h" + +#include "bindings/espnow/ESPNow.h" + +#include "shared-bindings/wifi/__init__.h" #ifndef MICROPY_ESPNOW_RSSI // Include code to track rssi of peers @@ -115,14 +117,22 @@ typedef struct _esp_espnow_obj_t { volatile size_t tx_responses; // # of sent packet responses received volatile size_t tx_failures; // # of sent packet responses failed size_t peer_count; // Cache the # of peers for send(sync=True) + #if MICROPY_ENABLE_SCHEDULER mp_obj_t recv_cb; // Callback when a packet is received mp_obj_t recv_cb_arg; // Argument passed to callback + #endif #if MICROPY_ESPNOW_RSSI mp_obj_t peers_table; // A dictionary of discovered peers #endif // MICROPY_ESPNOW_RSSI } esp_espnow_obj_t; -const mp_obj_type_t esp_espnow_type; +static const mp_obj_type_t esp_espnow_type; + +static void check_esp_err(esp_err_t status) { + if (status != ESP_OK) { + mp_raise_RuntimeError(translate("an error occured")); + } +} // ### Initialisation and Config functions // @@ -130,16 +140,17 @@ const mp_obj_type_t esp_espnow_type; // Return a pointer to the ESPNow module singleton // If state == INITIALISED check the device has been initialised. // Raises OSError if not initialised and state == INITIALISED. -static esp_espnow_obj_t *_get_singleton() { +static esp_espnow_obj_t *_get_singleton(void) { return MP_STATE_PORT(espnow_singleton); } -static esp_espnow_obj_t *_get_singleton_initialised() { +static esp_espnow_obj_t *_get_singleton_initialised(void) { esp_espnow_obj_t *self = _get_singleton(); // assert(self); if (self->recv_buffer == NULL) { // Throw an espnow not initialised error - check_esp_err(ESP_ERR_ESPNOW_NOT_INIT); + // check_esp_err(ESP_ERR_ESPNOW_NOT_INIT); + mp_raise_RuntimeError(translate("espnow not inited")); } return self; } @@ -163,7 +174,9 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, self->recv_buffer_size = DEFAULT_RECV_BUFFER_SIZE; self->recv_timeout_ms = DEFAULT_RECV_TIMEOUT_MS; self->recv_buffer = NULL; // Buffer is allocated in espnow_init() + #if MICROPY_ENABLE_SCHEDULER self->recv_cb = mp_const_none; + #endif #if MICROPY_ESPNOW_RSSI self->peers_table = mp_obj_new_dict(0); // Prevent user code modifying the dict @@ -181,29 +194,38 @@ STATIC void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status); STATIC void recv_cb(const uint8_t *mac_addr, const uint8_t *data, int len); +static void _wifi_init(void) { + if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + common_hal_wifi_init(false); + common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); + } +} + // ESPNow.init(): Initialise the data buffers and ESP-NOW functions. // Initialise the Espressif ESPNOW software stack, register callbacks and // allocate the recv data buffers. // Returns None. -static mp_obj_t espnow_init(mp_obj_t _) { +static void espnow_init(void) { esp_espnow_obj_t *self = _get_singleton(); if (self->recv_buffer == NULL) { // Already initialised self->recv_buffer = m_new_obj(ringbuf_t); - ringbuf_alloc(self->recv_buffer, self->recv_buffer_size); + if (!ringbuf_alloc(self->recv_buffer, self->recv_buffer_size, true)) { + m_malloc_fail(self->recv_buffer_size); + } + + _wifi_init(); // Call the wifi init code - esp_initialise_wifi(); // Call the wifi init code in network_wlan.c check_esp_err(esp_now_init()); check_esp_err(esp_now_register_recv_cb(recv_cb)); check_esp_err(esp_now_register_send_cb(send_cb)); } - return mp_const_none; } // ESPNow.deinit(): De-initialise the ESPNOW software stack, disable callbacks // and deallocate the recv data buffers. // Note: this function is called from main.c:mp_task() to cleanup before soft // reset, so cannot be declared STATIC and must guard against self == NULL;. -mp_obj_t espnow_deinit(mp_obj_t _) { +static void espnow_deinit(void) { esp_espnow_obj_t *self = _get_singleton(); if (self != NULL && self->recv_buffer != NULL) { check_esp_err(esp_now_unregister_recv_cb()); @@ -214,16 +236,20 @@ mp_obj_t espnow_deinit(mp_obj_t _) { self->peer_count = 0; // esp_now_deinit() removes all peers. self->tx_packets = self->tx_responses; } - return mp_const_none; +} + +void espnow_reset(void) { + espnow_deinit(); + MP_STATE_PORT(espnow_singleton) = NULL; } STATIC mp_obj_t espnow_active(size_t n_args, const mp_obj_t *args) { esp_espnow_obj_t *self = _get_singleton(); if (n_args > 1) { if (mp_obj_is_true(args[1])) { - espnow_init(self); + espnow_init(); } else { - espnow_deinit(self); + espnow_deinit(); } } return self->recv_buffer != NULL ? mp_const_true : mp_const_false; @@ -257,7 +283,7 @@ STATIC mp_obj_t espnow_config( } if (args[ARG_rate].u_int >= 0) { #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) - esp_initialise_wifi(); // Call the wifi init code in network_wlan.c + _wifi_init(); // Call the wifi init code check_esp_err(esp_wifi_config_espnow_rate( ESP_IF_WIFI_STA, args[ARG_rate].u_int)); check_esp_err(esp_wifi_config_espnow_rate( @@ -288,6 +314,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_config_obj, 1, espnow_config); // ESPNow.on_recv(recv_cb) // Set callback function to be invoked when a message is received. STATIC mp_obj_t espnow_on_recv(size_t n_args, const mp_obj_t *args) { + #if MICROPY_ENABLE_SCHEDULER esp_espnow_obj_t *self = _get_singleton(); mp_obj_t recv_cb = args[1]; if (recv_cb != mp_const_none && !mp_obj_is_callable(recv_cb)) { @@ -295,6 +322,9 @@ STATIC mp_obj_t espnow_on_recv(size_t n_args, const mp_obj_t *args) { } self->recv_cb = recv_cb; self->recv_cb_arg = (n_args > 2) ? args[2] : mp_const_none; + #else + mp_raise_NotImplementedError(NULL); + #endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_on_recv_obj, 2, 3, espnow_on_recv); @@ -329,9 +359,11 @@ static inline int8_t _get_rssi_from_wifi_pkt(const uint8_t *msg) { // and a espnow_frame_format_t. // Backtrack to get a pointer to the wifi_promiscuous_pkt_t. static const size_t sizeof_espnow_frame_format = 39; + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" wifi_promiscuous_pkt_t *wifi_pkt = (wifi_promiscuous_pkt_t *)( msg - sizeof_espnow_frame_format - sizeof(wifi_promiscuous_pkt_t)); - + #pragma GCC diagnostic pop #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) return wifi_pkt->rx_ctrl.rssi - 100; // Offset rssi for IDF 4.0.2 #else @@ -411,13 +443,13 @@ static const uint8_t *_get_peer(mp_obj_t mac_addr) { } // Copy data from the ring buffer - wait if buffer is empty up to timeout_ms -int ringbuf_read_wait(ringbuf_t *r, void *data, size_t len, int timeout_ms) { +static int ringbuf_read_wait(ringbuf_t *r, void *data, size_t len, int timeout_ms) { int64_t end = mp_hal_ticks_ms() + timeout_ms; int status = 0; while ( ((status = ringbuf_read(r, data, len)) == 0) && (end - (int64_t)mp_hal_ticks_ms()) >= 0) { - MICROPY_EVENT_POLL_HOOK; + RUN_BACKGROUND_TASKS; } return status; } @@ -437,7 +469,7 @@ STATIC mp_obj_t espnow_recvinto(size_t n_args, const mp_obj_t *args) { esp_espnow_obj_t *self = _get_singleton_initialised(); size_t timeout_ms = ((n_args > 2 && args[2] != mp_const_none) - ? mp_obj_get_int(args[2]) : self->recv_timeout_ms); + ? (size_t)mp_obj_get_int(args[2]) : self->recv_timeout_ms); mp_obj_list_t *list = MP_OBJ_TO_PTR(args[1]); if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) { @@ -510,7 +542,7 @@ static void _wait_for_pending_responses(esp_espnow_obj_t *self) { } if (t > PENDING_RESPONSES_BUSY_POLL_MS) { // After 10ms of busy waiting give other tasks a look in. - MICROPY_EVENT_POLL_HOOK; + RUN_BACKGROUND_TASKS; } } } @@ -545,14 +577,14 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) { // call has sync=True. _wait_for_pending_responses(self); } - int saved_failures = self->tx_failures; + size_t saved_failures = self->tx_failures; // Send the packet - try, try again if internal esp-now buffers are full. esp_err_t err; int64_t start = mp_hal_ticks_ms(); while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(peer, message.buf, message.len))) && (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { - MICROPY_EVENT_POLL_HOOK; + RUN_BACKGROUND_TASKS; } check_esp_err(err); // Will raise OSError if e != ESP_OK // Increment the sent packet count. If peer_addr==NULL msg will be @@ -610,9 +642,11 @@ STATIC void recv_cb( ringbuf_write(buf, mac_addr, ESP_NOW_ETH_ALEN); ringbuf_write(buf, msg, msg_len); self->rx_packets++; + #if MICROPY_ENABLE_SCHEDULER if (self->recv_cb != mp_const_none) { mp_sched_schedule(self->recv_cb, self->recv_cb_arg); } + #endif } // ### Peer Management Functions @@ -670,7 +704,7 @@ STATIC bool _update_peer_info( // Update the cached peer count in self->peer_count; // The peer_count ignores broadcast and multicast addresses and is used for the // send() logic and is updated from add_peer(), mod_peer() and del_peer(). -STATIC void _update_peer_count() { +STATIC void _update_peer_count(void) { esp_espnow_obj_t *self = _get_singleton_initialised(); esp_now_peer_info_t peer = {0}; @@ -745,8 +779,8 @@ STATIC mp_obj_t espnow_get_peers(mp_obj_t _) { // Build and initialise the peer info tuple. mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->peer_count, NULL); esp_now_peer_info_t peer = {0}; - for (int i = 0; i < peerinfo_tuple->len; i++) { - int status = esp_now_fetch_peer((i == 0), &peer); + for (size_t i = 0; i < peerinfo_tuple->len; i++) { + esp_err_t status = esp_now_fetch_peer((i == 0), &peer); peerinfo_tuple->items[i] = (status == ESP_OK ? _peer_info_to_tuple(&peer) : mp_const_none); } @@ -887,22 +921,23 @@ STATIC void espnow_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } #endif // MICROPY_ESPNOW_RSSI -MP_DEFINE_CONST_OBJ_TYPE( - esp_espnow_type, - MP_QSTR_ESPNow, - MP_TYPE_FLAG_NONE, - make_new, espnow_make_new, +STATIC const mp_obj_type_t esp_espnow_type = { + { &mp_type_type }, + .name = MP_QSTR_ESPNow, + .make_new = espnow_make_new, + .locals_dict = (mp_obj_t)&esp_espnow_locals_dict, #if MICROPY_ESPNOW_RSSI - attr, espnow_attr, + .attr = espnow_attr, #endif // MICROPY_ESPNOW_RSSI - protocol, &espnow_stream_p, - locals_dict, &esp_espnow_locals_dict - ); + .flags = MP_TYPE_FLAG_EXTENDED, + MP_TYPE_EXTENDED_FIELDS( + .protocol = &espnow_stream_p, + ), +}; const mp_obj_module_t mp_module_espnow = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t *)&espnow_globals_dict, }; -MP_REGISTER_MODULE(MP_QSTR__espnow, mp_module_espnow); -MP_REGISTER_ROOT_POINTER(struct _esp_espnow_obj_t *espnow_singleton); +MP_REGISTER_MODULE(MP_QSTR__espnow, mp_module_espnow, CIRCUITPY_ESPNOW); diff --git a/ports/espressif/bindings/espnow/ESPNow.h b/ports/espressif/bindings/espnow/ESPNow.h index 3c6280b1ce..9855cd4ff8 100644 --- a/ports/espressif/bindings/espnow/ESPNow.h +++ b/ports/espressif/bindings/espnow/ESPNow.h @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2021 Glenn Moloney @glenn20 + * Copyright (c) 2023 MicroDev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +25,5 @@ * THE SOFTWARE. */ -#include "py/obj.h" - -// Called from main.c:mp_task() to reset the espnow software stack -mp_obj_t espnow_deinit(mp_obj_t _); +#pragma once +void espnow_reset(void); diff --git a/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c b/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c index 48be3abd67..8edb40ca85 100644 --- a/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c +++ b/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c @@ -27,17 +27,20 @@ #include #include -#include "shared/runtime/interrupt_char.h" #include "py/ringbuf.h" #include "py/runtime.h" #include "py/stream.h" +#include "shared/runtime/interrupt_char.h" + #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" -#include "supervisor/shared/tick.h" -#include "common-hal/_bleio/CharacteristicBuffer.h" #include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "supervisor/shared/tick.h" + +#include "common-hal/_bleio/ble_events.h" + STATIC int characteristic_buffer_on_ble_evt(struct ble_gap_event *event, void *param) { bleio_characteristic_buffer_obj_t *self = (bleio_characteristic_buffer_obj_t *)param; switch (event->type) { diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 63c85099e6..75def8ad76 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -30,21 +30,24 @@ #include #include -#include "shared/runtime/interrupt_char.h" #include "py/gc.h" #include "py/objlist.h" #include "py/objstr.h" #include "py/qstr.h" #include "py/runtime.h" + +#include "shared/runtime/interrupt_char.h" + #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Adapter.h" #include "shared-bindings/_bleio/Attribute.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" + #include "supervisor/shared/tick.h" -// #include "common-hal/_bleio/bonding.h" +#include "common-hal/_bleio/ble_events.h" #include "host/ble_att.h" diff --git a/ports/espressif/common-hal/_bleio/PacketBuffer.c b/ports/espressif/common-hal/_bleio/PacketBuffer.c index 3b3e51df61..d1d8c24123 100644 --- a/ports/espressif/common-hal/_bleio/PacketBuffer.c +++ b/ports/espressif/common-hal/_bleio/PacketBuffer.c @@ -27,17 +27,20 @@ #include #include -#include "shared/runtime/interrupt_char.h" #include "py/runtime.h" #include "py/stream.h" +#include "shared/runtime/interrupt_char.h" + #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/PacketBuffer.h" -#include "supervisor/shared/tick.h" +#include "supervisor/shared/tick.h" #include "supervisor/shared/bluetooth/serial.h" +#include "common-hal/_bleio/ble_events.h" + #include "host/ble_att.h" STATIC void write_to_ringbuf(bleio_packet_buffer_obj_t *self, const struct os_mbuf *mbuf) { diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index c296be2024..8c206cf02a 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -38,18 +38,22 @@ #include "py/circuitpy_mpconfig.h" #if CIRCUITPY_BLEIO -#include "common-hal/_bleio/ble_events.h" +#define BLEIO_ROOT_POINTERS struct ble_event_handler_entry *ble_event_handler_entries; +#else +#define BLEIO_ROOT_POINTERS #endif -#if CIRCUITPY_BLEIO -#define MICROPY_PORT_ROOT_POINTERS \ - CIRCUITPY_COMMON_ROOT_POINTERS \ - ble_event_handler_entry_t *ble_event_handler_entries; +#if CIRCUITPY_ESPNOW +#define ESPNOW_ROOT_POINTERS struct _esp_espnow_obj_t *espnow_singleton; #else -#define MICROPY_PORT_ROOT_POINTERS \ - CIRCUITPY_COMMON_ROOT_POINTERS +#define ESPNOW_ROOT_POINTERS #endif +#define MICROPY_PORT_ROOT_POINTERS \ + CIRCUITPY_COMMON_ROOT_POINTERS \ + BLEIO_ROOT_POINTERS \ + ESPNOW_ROOT_POINTERS + #define MICROPY_NLR_SETJMP (1) #define CIRCUITPY_DEFAULT_STACK_SIZE 0x6000 diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index c5c73c77bd..035fa75278 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -81,6 +81,7 @@ CIRCUITPY_DUALBANK = 0 endif # Modules dependent on other modules +CIRCUITPY_ESPNOW ?= $(CIRCUITPY_WIFI) CIRCUITPY_GIFIO ?= $(CIRCUITPY_ESP32_CAMERA) CIRCUITPY_QRIO ?= $(CIRCUITPY_ESP32_CAMERA) diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 6dd09ed238..8a6dfabb5f 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -37,6 +37,7 @@ #include "freertos/task.h" #include "bindings/espidf/__init__.h" +#include "bindings/espnow/ESPNow.h" #include "bindings/espulp/__init__.h" #include "common-hal/microcontroller/Pin.h" #include "common-hal/analogio/AnalogOut.h" @@ -369,6 +370,10 @@ void reset_port(void) { dualbank_reset(); #endif + #if CIRCUITPY_ESPNOW + espnow_reset(); + #endif + #if CIRCUITPY_ESPULP espulp_reset(); #endif diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 3c1c173a51..03ff0f9d95 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -227,6 +227,9 @@ CFLAGS += -DCIRCUITPY_ERRNO=$(CIRCUITPY_ERRNO) CIRCUITPY_ESPIDF ?= 0 CFLAGS += -DCIRCUITPY_ESPIDF=$(CIRCUITPY_ESPIDF) +CIRCUITPY_ESPNOW ?= 0 +CFLAGS += -DCIRCUITPY_ESPNOW=$(CIRCUITPY_ESPNOW) + CIRCUITPY_ESPULP ?= 0 CFLAGS += -DCIRCUITPY_ESPULP=$(CIRCUITPY_ESPULP) diff --git a/py/ringbuf.c b/py/ringbuf.c index 8a4cb33cbc..f90805d6f3 100644 --- a/py/ringbuf.c +++ b/py/ringbuf.c @@ -142,3 +142,47 @@ int ringbuf_put16(ringbuf_t *r, uint16_t v) { ringbuf_put(r, v & 0xff); return 0; } + +// Returns: +// 1: Success +// 0: Not enough data available to complete read (try again later) +// -1: Requested read is larger than buffer - will never succeed +int ringbuf_read(ringbuf_t *r, void *data, size_t data_len) { + if (ringbuf_avail(r) < data_len) { + return (r->size <= data_len) ? -1 : 0; + } + uint32_t iget = r->next_read; + uint32_t iget_a = (iget + data_len) % r->size; + uint8_t *datap = data; + if (iget_a < iget) { + // Copy part of the data from the space left at the end of the buffer + memcpy(datap, r->buf + iget, r->size - iget); + datap += (r->size - iget); + iget = 0; + } + memcpy(datap, r->buf + iget, iget_a - iget); + r->next_read = iget_a; + return 1; +} + +// Returns: +// 1: Success +// 0: Not enough free space available to complete write (try again later) +// -1: Requested write is larger than buffer - will never succeed +int ringbuf_write(ringbuf_t *r, const void *data, size_t data_len) { + if (ringbuf_free(r) < data_len) { + return (r->size <= data_len) ? -1 : 0; + } + uint32_t iput = r->next_write; + uint32_t iput_a = (iput + data_len) % r->size; + const uint8_t *datap = data; + if (iput_a < iput) { + // Copy part of the data to the end of the buffer + memcpy(r->buf + iput, datap, r->size - iput); + datap += (r->size - iput); + iput = 0; + } + memcpy(r->buf + iput, datap, iput_a - iput); + r->next_write = iput_a; + return 1; +} diff --git a/py/ringbuf.h b/py/ringbuf.h index 2725bedcca..5d54abc6b5 100644 --- a/py/ringbuf.h +++ b/py/ringbuf.h @@ -61,5 +61,15 @@ size_t ringbuf_get_n(ringbuf_t *r, uint8_t *buf, size_t bufsize); // Note: big-endian. Return -1 if can't read or write two bytes. int ringbuf_get16(ringbuf_t *r); int ringbuf_put16(ringbuf_t *r, uint16_t v); +int ringbuf_read(ringbuf_t *r, void *data, size_t data_len); +int ringbuf_write(ringbuf_t *r, const void *data, size_t data_len); + +static inline size_t ringbuf_free(ringbuf_t *r) { + return (r->size + r->next_read - r->next_write - 1) % r->size; +} + +static inline size_t ringbuf_avail(ringbuf_t *r) { + return (r->size + r->next_write - r->next_read) % r->size; +} #endif // MICROPY_INCLUDED_PY_RINGBUF_H From f15e84de6c0c66867c73748649b02d081aa94120 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Mon, 23 Jan 2023 09:42:39 +0530 Subject: [PATCH 03/29] update espnow module --- locale/circuitpython.pot | 28 +- .../bindings/espnow/{ESPNow.c => Now.c} | 897 ++++++++---------- .../bindings/espnow/{ESPNow.h => Now.h} | 4 +- ports/espressif/bindings/espnow/__init__.c | 85 ++ ports/espressif/bindings/espnow/__init__.h | 29 + ports/espressif/mpconfigport.h | 2 +- ports/espressif/supervisor/port.c | 2 +- 7 files changed, 535 insertions(+), 512 deletions(-) rename ports/espressif/bindings/espnow/{ESPNow.c => Now.c} (54%) rename ports/espressif/bindings/espnow/{ESPNow.h => Now.h} (95%) create mode 100644 ports/espressif/bindings/espnow/__init__.c create mode 100644 ports/espressif/bindings/espnow/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 33effc9612..d0fb9e5da4 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -918,18 +918,6 @@ msgstr "" msgid "ESP-IDF memory allocation failed" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "ESPNow.recv(): buffer error" -msgstr "" - -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "ESPNow.recvinto(): Invalid argument" -msgstr "" - -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "ESPNow: bytes or bytearray wrong length" -msgstr "" - #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/ps2io/Ps2.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c @@ -2442,7 +2430,7 @@ msgstr "" msgid "addresses is empty" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/bindings/espnow/Now.c msgid "an error occured" msgstr "" @@ -2970,10 +2958,6 @@ msgid "" "documentation for instructions." msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "espnow not inited" -msgstr "" - #: py/runtime.c msgid "exceptions must derive from BaseException" msgstr "" @@ -3335,10 +3319,6 @@ msgstr "" msgid "invalid format specifier" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "invalid handler" -msgstr "" - #: shared-bindings/wifi/Radio.c msgid "invalid hostname" msgstr "" @@ -3883,10 +3863,6 @@ msgstr "" msgid "queue overflow" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "rate option not supported" -msgstr "" - #: py/parse.c msgid "raw f-strings are not supported" msgstr "" @@ -4182,7 +4158,7 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/bindings/espnow/Now.c msgid "unknown config param" msgstr "" diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/Now.c similarity index 54% rename from ports/espressif/bindings/espnow/ESPNow.c rename to ports/espressif/bindings/espnow/Now.c index 33cf2342b8..935a740164 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/Now.c @@ -27,56 +27,52 @@ * THE SOFTWARE. */ -#include -#include -#include - -#include "esp_log.h" #include "esp_now.h" -#include "esp_wifi.h" -#include "esp_wifi_types.h" #include "py/runtime.h" -#include "py/mphal.h" -#include "py/mperrno.h" -#include "py/obj.h" -#include "py/objstr.h" #include "py/objarray.h" +#include "py/objproperty.h" #include "py/stream.h" -#include "py/binary.h" #include "py/ringbuf.h" -#include "mpconfigport.h" #include "mphalport.h" -#include "bindings/espnow/ESPNow.h" +#include "bindings/espnow/__init__.h" +#include "bindings/espnow/Now.h" +#include "shared-bindings/util.h" #include "shared-bindings/wifi/__init__.h" -#ifndef MICROPY_ESPNOW_RSSI -// Include code to track rssi of peers -#define MICROPY_ESPNOW_RSSI 1 -#endif -#ifndef MICROPY_ESPNOW_EXTRA_PEER_METHODS -// Include mod_peer(),get_peer(),peer_count() -#define MICROPY_ESPNOW_EXTRA_PEER_METHODS 1 -#endif - // Relies on gcc Variadic Macros and Statement Expressions -#define NEW_TUPLE(...) \ - ({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z); }) +#define NEW_TUPLE(...) ({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z);}) -static const uint8_t ESPNOW_MAGIC = 0x99; +#define ESPNOW_MAGIC 0x99 + +// The maximum length of an espnow packet (bytes) +#define MAX_PACKET_LEN (sizeof(espnow_pkt_t) + ESP_NOW_MAX_DATA_LEN) + +// Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes +// Will allocate an additional 7 bytes for buffer overhead +#define DEFAULT_RECV_BUFFER_SIZE (2 * MAX_PACKET_LEN) + +// Default timeout (millisec) to wait for incoming ESPNow messages (5 minutes). +#define DEFAULT_RECV_TIMEOUT_MS (5 * 60 * 1000) + +// Time to wait (millisec) for responses from sent packets: (2 seconds). +#define DEFAULT_SEND_TIMEOUT_MS (2 * 1000) + +// Number of milliseconds to wait for pending responses to sent packets. +// This is a fallback which should never be reached. +#define PENDING_RESPONSES_TIMEOUT_MS 100 +#define PENDING_RESPONSES_BUSY_POLL_MS 10 // ESPNow packet format for the receive buffer. // Use this for peeking at the header of the next packet in the buffer. typedef struct { uint8_t magic; // = ESPNOW_MAGIC uint8_t msg_len; // Length of the message - #if MICROPY_ESPNOW_RSSI uint32_t time_ms; // Timestamp (ms) when packet is received int8_t rssi; // RSSI value (dBm) (-127 to 0) - #endif // MICROPY_ESPNOW_RSSI } __attribute__((packed)) espnow_hdr_t; typedef struct { @@ -85,48 +81,20 @@ typedef struct { uint8_t msg[0]; // Message is up to 250 bytes } __attribute__((packed)) espnow_pkt_t; -// The maximum length of an espnow packet (bytes) -static const size_t MAX_PACKET_LEN = ( - (sizeof(espnow_pkt_t) + ESP_NOW_MAX_DATA_LEN)); - -// Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes -// Will allocate an additional 7 bytes for buffer overhead -static const size_t DEFAULT_RECV_BUFFER_SIZE = (2 * MAX_PACKET_LEN); - -// Default timeout (millisec) to wait for incoming ESPNow messages (5 minutes). -static const size_t DEFAULT_RECV_TIMEOUT_MS = (5 * 60 * 1000); - -// Time to wait (millisec) for responses from sent packets: (2 seconds). -static const size_t DEFAULT_SEND_TIMEOUT_MS = (2 * 1000); - -// Number of milliseconds to wait for pending responses to sent packets. -// This is a fallback which should never be reached. -static const mp_uint_t PENDING_RESPONSES_TIMEOUT_MS = 100; -static const mp_uint_t PENDING_RESPONSES_BUSY_POLL_MS = 10; - // The data structure for the espnow_singleton. -typedef struct _esp_espnow_obj_t { +typedef struct _espnow_obj_t { mp_obj_base_t base; - ringbuf_t *recv_buffer; // A buffer for received packets size_t recv_buffer_size; // The size of the recv_buffer size_t recv_timeout_ms; // Timeout for recv() volatile size_t rx_packets; // # of received packets - size_t dropped_rx_pkts; // # of dropped packets (buffer full) + volatile size_t rx_failures; // # of dropped packets (buffer full) size_t tx_packets; // # of sent packets volatile size_t tx_responses; // # of sent packet responses received volatile size_t tx_failures; // # of sent packet responses failed - size_t peer_count; // Cache the # of peers for send(sync=True) - #if MICROPY_ENABLE_SCHEDULER - mp_obj_t recv_cb; // Callback when a packet is received - mp_obj_t recv_cb_arg; // Argument passed to callback - #endif - #if MICROPY_ESPNOW_RSSI + size_t num_peers; // Cache the # of peers for send(sync=True) mp_obj_t peers_table; // A dictionary of discovered peers - #endif // MICROPY_ESPNOW_RSSI -} esp_espnow_obj_t; - -static const mp_obj_type_t esp_espnow_type; +} espnow_obj_t; static void check_esp_err(esp_err_t status) { if (status != ESP_OK) { @@ -134,54 +102,52 @@ static void check_esp_err(esp_err_t status) { } } -// ### Initialisation and Config functions -// +// --- Initialisation and Config functions --- // Return a pointer to the ESPNow module singleton // If state == INITIALISED check the device has been initialised. // Raises OSError if not initialised and state == INITIALISED. -static esp_espnow_obj_t *_get_singleton(void) { +static espnow_obj_t *_get_singleton(void) { return MP_STATE_PORT(espnow_singleton); } -static esp_espnow_obj_t *_get_singleton_initialised(void) { - esp_espnow_obj_t *self = _get_singleton(); - // assert(self); - if (self->recv_buffer == NULL) { - // Throw an espnow not initialised error - // check_esp_err(ESP_ERR_ESPNOW_NOT_INIT); - mp_raise_RuntimeError(translate("espnow not inited")); - } - return self; +static bool espnow_deinited(espnow_obj_t *self) { + return self->recv_buffer == NULL; } -// Allocate and initialise the ESPNow module as a singleton. -// Returns the initialised espnow_singleton. -STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *all_args) { +// Return a pointer to the ESPNow module singleton +// If state == INITIALISED check the device has been initialised. +// Raises OSError if not initialised and state == INITIALISED. +static void check_for_deinit(espnow_obj_t *self) { + if (espnow_deinited(self)) { + raise_deinited_error(); + } +} + +//| class Now: +//| def __init__(self) -> Now: +//| """ +//| Allocate and initialise the ESPNow module as a singleton. +//| Returns the initialised espnow_singleton. +//| """ +//| ... +//| +STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + espnow_obj_t *self = _get_singleton(); - // The espnow_singleton must be defined in MICROPY_PORT_ROOT_POINTERS - // (see mpconfigport.h) to prevent memory allocated here from being - // garbage collected. - // NOTE: on soft reset the espnow_singleton MUST be set to NULL and the - // ESP-NOW functions de-initialised (see main.c). - esp_espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); if (self != NULL) { return self; } - self = m_new_obj(esp_espnow_obj_t); - self->base.type = &esp_espnow_type; + + self = m_new_obj(espnow_obj_t); + self->base.type = &espnow_type; self->recv_buffer_size = DEFAULT_RECV_BUFFER_SIZE; self->recv_timeout_ms = DEFAULT_RECV_TIMEOUT_MS; - self->recv_buffer = NULL; // Buffer is allocated in espnow_init() - #if MICROPY_ENABLE_SCHEDULER - self->recv_cb = mp_const_none; - #endif - #if MICROPY_ESPNOW_RSSI + self->recv_buffer = NULL; self->peers_table = mp_obj_new_dict(0); + // Prevent user code modifying the dict mp_obj_dict_get_map(self->peers_table)->is_fixed = 1; - #endif // MICROPY_ESPNOW_RSSI // Set the global singleton pointer for the espnow protocol. MP_STATE_PORT(espnow_singleton) = self; @@ -189,10 +155,47 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, return self; } -// Forward declare the send and recv ESPNow callbacks -STATIC void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status); +// --- The ESP-NOW send and recv callback routines --- -STATIC void recv_cb(const uint8_t *mac_addr, const uint8_t *data, int len); +// Callback triggered when a sent packet is acknowledged by the peer (or not). +// Just count the number of responses and number of failures. +// These are used in the send() logic. +static void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) { + espnow_obj_t *self = _get_singleton(); + self->tx_responses++; + if (status != ESP_NOW_SEND_SUCCESS) { + self->tx_failures++; + } +} + +static inline int8_t _get_rssi_from_wifi_pkt(const uint8_t *msg); + +// Callback triggered when an ESP-Now packet is received. +// Write the peer MAC address and the message into the recv_buffer as an ESPNow packet. +// If the buffer is full, drop the message and increment the dropped count. +// Schedules the user callback if one has been registered (ESPNow.config()). +static void recv_cb(const uint8_t *mac_addr, const uint8_t *msg, int msg_len) { + espnow_obj_t *self = _get_singleton(); + ringbuf_t *buf = self->recv_buffer; + + // TODO: Test this works with ">". + if (sizeof(espnow_pkt_t) + msg_len >= ringbuf_free(buf)) { + self->rx_failures++; + return; + } + + espnow_hdr_t header; + header.magic = ESPNOW_MAGIC; + header.msg_len = msg_len; + header.rssi = _get_rssi_from_wifi_pkt(msg); + header.time_ms = mp_hal_ticks_ms(); + + ringbuf_write(buf, &header, sizeof(header)); + ringbuf_write(buf, mac_addr, ESP_NOW_ETH_ALEN); + ringbuf_write(buf, msg, msg_len); + + self->rx_packets++; +} static void _wifi_init(void) { if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { @@ -201,13 +204,16 @@ static void _wifi_init(void) { } } -// ESPNow.init(): Initialise the data buffers and ESP-NOW functions. -// Initialise the Espressif ESPNOW software stack, register callbacks and -// allocate the recv data buffers. -// Returns None. -static void espnow_init(void) { - esp_espnow_obj_t *self = _get_singleton(); - if (self->recv_buffer == NULL) { // Already initialised +//| def init() -> None: +//| """ +//| Initialise the data buffers and ESP-NOW functions. +//| Initialise the Espressif ESP-NOW software stack, register callbacks +//| and allocate the recv data buffers. +//| """ +//| ... +//| +static void espnow_init(espnow_obj_t *self) { + if (espnow_deinited(self)) { // Already initialised self->recv_buffer = m_new_obj(ringbuf_t); if (!ringbuf_alloc(self->recv_buffer, self->recv_buffer_size, true)) { m_malloc_fail(self->recv_buffer_size); @@ -216,54 +222,65 @@ static void espnow_init(void) { _wifi_init(); // Call the wifi init code check_esp_err(esp_now_init()); - check_esp_err(esp_now_register_recv_cb(recv_cb)); check_esp_err(esp_now_register_send_cb(send_cb)); + check_esp_err(esp_now_register_recv_cb(recv_cb)); } } -// ESPNow.deinit(): De-initialise the ESPNOW software stack, disable callbacks -// and deallocate the recv data buffers. -// Note: this function is called from main.c:mp_task() to cleanup before soft -// reset, so cannot be declared STATIC and must guard against self == NULL;. -static void espnow_deinit(void) { - esp_espnow_obj_t *self = _get_singleton(); - if (self != NULL && self->recv_buffer != NULL) { - check_esp_err(esp_now_unregister_recv_cb()); +//| def deinit() -> None: +//| """ +//| De-initialise the ESP-NOW software stack, disable callbacks +//| and deallocate the recv data buffers. +//| """ +//| ... +//| +static void espnow_deinit(espnow_obj_t *self) { + if (self != NULL && !espnow_deinited(self)) { check_esp_err(esp_now_unregister_send_cb()); + check_esp_err(esp_now_unregister_recv_cb()); check_esp_err(esp_now_deinit()); self->recv_buffer->buf = NULL; self->recv_buffer = NULL; - self->peer_count = 0; // esp_now_deinit() removes all peers. + self->num_peers = 0; // esp_now_deinit() removes all peers. self->tx_packets = self->tx_responses; } } void espnow_reset(void) { - espnow_deinit(); + espnow_deinit(_get_singleton()); MP_STATE_PORT(espnow_singleton) = NULL; } +//| def active(state: bool) -> bool: +//| """ +//| Initialise or de-initialise the ESPNow communication protocol +//| depending on the value of the flag optional argument. +//| """ +//| ... +//| STATIC mp_obj_t espnow_active(size_t n_args, const mp_obj_t *args) { - esp_espnow_obj_t *self = _get_singleton(); + espnow_obj_t *self = args[0]; if (n_args > 1) { if (mp_obj_is_true(args[1])) { - espnow_init(); + espnow_init(self); } else { - espnow_deinit(); + espnow_deinit(self); } } - return self->recv_buffer != NULL ? mp_const_true : mp_const_false; + return mp_obj_new_bool(!espnow_deinited(self)); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_active_obj, 1, 2, espnow_active); -// ESPNow.config(['param'|param=value, ..]) -// Get or set configuration values. Supported config params: -// buffer: size of buffer for rx packets (default=514 bytes) -// timeout: Default read timeout (default=300,000 milliseconds) -STATIC mp_obj_t espnow_config( - size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - - esp_espnow_obj_t *self = _get_singleton(); +//| def config(['param'|param=value, ..]) -> int: +//| """ +//| Get or set configuration values. Supported config params: +//| buffer: size of buffer for rx packets (default=514 bytes) +//| timeout: Default read timeout (default=300,000 milliseconds) +//| """ +//| ... +//| +STATIC mp_obj_t espnow_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + espnow_obj_t *self = pos_args[0]; enum { ARG_get, ARG_buffer, ARG_timeout, ARG_rate }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -271,30 +288,28 @@ STATIC mp_obj_t espnow_config( { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); if (args[ARG_buffer].u_int >= 0) { self->recv_buffer_size = args[ARG_buffer].u_int; } + if (args[ARG_timeout].u_int >= 0) { self->recv_timeout_ms = args[ARG_timeout].u_int; } + if (args[ARG_rate].u_int >= 0) { - #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) _wifi_init(); // Call the wifi init code - check_esp_err(esp_wifi_config_espnow_rate( - ESP_IF_WIFI_STA, args[ARG_rate].u_int)); - check_esp_err(esp_wifi_config_espnow_rate( - ESP_IF_WIFI_AP, args[ARG_rate].u_int)); - #else - mp_raise_ValueError(MP_ERROR_TEXT("rate option not supported")); - #endif + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, args[ARG_rate].u_int)); + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, args[ARG_rate].u_int)); } + if (args[ARG_get].u_obj == MP_OBJ_NULL) { return mp_const_none; } + #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) // Return the value of the requested parameter uintptr_t name = (uintptr_t)args[ARG_get].u_obj; @@ -311,40 +326,26 @@ STATIC mp_obj_t espnow_config( } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_config_obj, 1, espnow_config); -// ESPNow.on_recv(recv_cb) -// Set callback function to be invoked when a message is received. -STATIC mp_obj_t espnow_on_recv(size_t n_args, const mp_obj_t *args) { - #if MICROPY_ENABLE_SCHEDULER - esp_espnow_obj_t *self = _get_singleton(); - mp_obj_t recv_cb = args[1]; - if (recv_cb != mp_const_none && !mp_obj_is_callable(recv_cb)) { - mp_raise_ValueError(MP_ERROR_TEXT("invalid handler")); - } - self->recv_cb = recv_cb; - self->recv_cb_arg = (n_args > 2) ? args[2] : mp_const_none; - #else - mp_raise_NotImplementedError(NULL); - #endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_on_recv_obj, 2, 3, espnow_on_recv); - -// ESPnow.stats(): Provide some useful stats. -// Returns a tuple of: -// (tx_pkts, tx_responses, tx_failures, rx_pkts, dropped_rx_pkts) -STATIC mp_obj_t espnow_stats(mp_obj_t _) { - const esp_espnow_obj_t *self = _get_singleton(); +//| stats: Tuple[int, int, int, int, int] +//| """Provide some useful stats. +//| Returns a tuple of (tx_packets, tx_responses, tx_failures, rx_packets, rx_failures). +//| """ +//| +STATIC mp_obj_t espnow_get_stats(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); return NEW_TUPLE( mp_obj_new_int(self->tx_packets), mp_obj_new_int(self->tx_responses), mp_obj_new_int(self->tx_failures), mp_obj_new_int(self->rx_packets), - mp_obj_new_int(self->dropped_rx_pkts)); + mp_obj_new_int(self->rx_failures)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_stats_obj, espnow_stats); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_stats_obj, espnow_get_stats); -#if MICROPY_ESPNOW_RSSI -// ### Maintaining the peer table and reading RSSI values +MP_PROPERTY_GETTER(espnow_stats_obj, + (mp_obj_t)&espnow_get_stats_obj); + +// --- Maintaining the peer table and reading RSSI values --- // // We maintain a peers table for several reasons, to: // - support monitoring the RSSI values for all peers; and @@ -364,19 +365,12 @@ static inline int8_t _get_rssi_from_wifi_pkt(const uint8_t *msg) { wifi_promiscuous_pkt_t *wifi_pkt = (wifi_promiscuous_pkt_t *)( msg - sizeof_espnow_frame_format - sizeof(wifi_promiscuous_pkt_t)); #pragma GCC diagnostic pop - #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) - return wifi_pkt->rx_ctrl.rssi - 100; // Offset rssi for IDF 4.0.2 - #else return wifi_pkt->rx_ctrl.rssi; - #endif } -// Lookup a peer in the peers table and return a reference to the item in the -// peers_table. Add peer to the table if it is not found (may alloc memory). -// Will not return NULL. -static mp_map_elem_t *_lookup_add_peer( - esp_espnow_obj_t *self, const uint8_t *peer) { - +// Lookup a peer in the peers table and return a reference to the item in the peers_table. +// Add peer to the table if it is not found (may alloc memory). Will not return NULL. +static mp_map_elem_t *_lookup_add_peer(espnow_obj_t *self, const uint8_t *peer) { // We do not want to allocate any new memory in the case that the peer // already exists in the peers_table (which is almost all the time). // So, we use a byte string on the stack and look that up in the dict. @@ -396,10 +390,7 @@ static mp_map_elem_t *_lookup_add_peer( // Update the peers table with the new rssi value from a received pkt and // return a reference to the item in the peers_table. -static mp_map_elem_t *_update_rssi( - const uint8_t *peer, int8_t rssi, uint32_t time_ms) { - - esp_espnow_obj_t *self = _get_singleton_initialised(); +static mp_map_elem_t *_update_rssi(espnow_obj_t *self, const uint8_t *peer, int8_t rssi, uint32_t time_ms) { // Lookup the peer in the device table mp_map_elem_t *item = _lookup_add_peer(self, peer); mp_obj_list_t *list = MP_OBJ_TO_PTR(item->value); @@ -407,23 +398,17 @@ static mp_map_elem_t *_update_rssi( list->items[1] = mp_obj_new_int(time_ms); return item; } -#endif // MICROPY_ESPNOW_RSSI -// ### Handling espnow packets in the recv buffer -// +// --- Handling espnow packets in the recv buffer --- -// ### Send and Receive ESP_Now data -// +// --- Send and Receive ESP_Now data --- // Return C pointer to byte memory string/bytes/bytearray in obj. // Raise ValueError if the length does not match expected len. static uint8_t *_get_bytes_len_rw(mp_obj_t obj, size_t len, mp_uint_t rw) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(obj, &bufinfo, rw); - if (bufinfo.len != len) { - mp_raise_ValueError( - MP_ERROR_TEXT("ESPNow: bytes or bytearray wrong length")); - } + mp_arg_validate_length(bufinfo.len, len, MP_QSTR_bytes); return (uint8_t *)bufinfo.buf; } @@ -438,8 +423,7 @@ static uint8_t *_get_bytes_len_w(mp_obj_t obj, size_t len) { // Return C pointer to the MAC address. // Raise ValueError if mac_addr is wrong type or is not 6 bytes long. static const uint8_t *_get_peer(mp_obj_t mac_addr) { - return mp_obj_is_true(mac_addr) - ? _get_bytes_len(mac_addr, ESP_NOW_ETH_ALEN) : NULL; + return mp_obj_is_true(mac_addr) ? _get_bytes_len(mac_addr, ESP_NOW_ETH_ALEN) : NULL; } // Copy data from the ring buffer - wait if buffer is empty up to timeout_ms @@ -454,88 +438,11 @@ static int ringbuf_read_wait(ringbuf_t *r, void *data, size_t len, int timeout_m return status; } -// ESPNow.recvinto(buffers[, timeout_ms]): -// Waits for an espnow message and copies the peer_addr and message into -// the buffers list. -// Arguments: -// buffers: (Optional) list of bytearrays to store return values. -// timeout_ms: (Optional) timeout in milliseconds (or None). -// Buffers should be a list: [bytearray(6), bytearray(250)] -// If buffers is 4 elements long, the rssi and timestamp values will be -// loaded into the 3rd and 4th elements. -// Default timeout is set with ESPNow.config(timeout=milliseconds). -// Return (None, None) on timeout. -STATIC mp_obj_t espnow_recvinto(size_t n_args, const mp_obj_t *args) { - esp_espnow_obj_t *self = _get_singleton_initialised(); - - size_t timeout_ms = ((n_args > 2 && args[2] != mp_const_none) - ? (size_t)mp_obj_get_int(args[2]) : self->recv_timeout_ms); - - mp_obj_list_t *list = MP_OBJ_TO_PTR(args[1]); - if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) { - mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recvinto(): Invalid argument")); - } - mp_obj_array_t *msg = MP_OBJ_TO_PTR(list->items[1]); - if (mp_obj_is_type(msg, &mp_type_bytearray)) { - msg->len += msg->free; // Make all the space in msg array available - msg->free = 0; - } - #if MICROPY_ESPNOW_RSSI - uint8_t peer_buf[ESP_NOW_ETH_ALEN]; - #else - uint8_t *peer_buf = _get_bytes_len_w(list->items[0], ESP_NOW_ETH_ALEN); - #endif // MICROPY_ESPNOW_RSSI - uint8_t *msg_buf = _get_bytes_len_w(msg, ESP_NOW_MAX_DATA_LEN); - - // Read the packet header from the incoming buffer - espnow_hdr_t hdr; - if (ringbuf_read_wait(self->recv_buffer, &hdr, sizeof(hdr), timeout_ms) < 1) { - return MP_OBJ_NEW_SMALL_INT(0); // Timeout waiting for packet - } - int msg_len = hdr.msg_len; - - // Check the message packet header format and read the message data - if (hdr.magic != ESPNOW_MAGIC || - msg_len > ESP_NOW_MAX_DATA_LEN || - ringbuf_read(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) < 1 || - ringbuf_read(self->recv_buffer, msg_buf, msg_len) < 1) { - mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recv(): buffer error")); - } - if (mp_obj_is_type(msg, &mp_type_bytearray)) { - // Set the length of the message bytearray. - size_t size = msg->len + msg->free; - msg->len = msg_len; - msg->free = size - msg_len; - } - - #if MICROPY_ESPNOW_RSSI - // Update rssi value in the peer device table - mp_map_elem_t *entry = _update_rssi(peer_buf, hdr.rssi, hdr.time_ms); - list->items[0] = entry->key; // Set first element of list to peer - if (list->len >= 4) { - list->items[2] = MP_OBJ_NEW_SMALL_INT(hdr.rssi); - list->items[3] = mp_obj_new_int(hdr.time_ms); - } - #endif // MICROPY_ESPNOW_RSSI - - return MP_OBJ_NEW_SMALL_INT(msg_len); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_recvinto_obj, 2, 3, espnow_recvinto); - -// Test if data is available to read from the buffers -STATIC mp_obj_t espnow_any(const mp_obj_t _) { - esp_espnow_obj_t *self = _get_singleton_initialised(); - - return ringbuf_avail(self->recv_buffer) ? mp_const_true : mp_const_false; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_any_obj, espnow_any); - // Used by espnow_send() for sends() with sync==True. // Wait till all pending sent packet responses have been received. // ie. self->tx_responses == self->tx_packets. -static void _wait_for_pending_responses(esp_espnow_obj_t *self) { - mp_uint_t start = mp_hal_ticks_ms(); - mp_uint_t t; +static void _wait_for_pending_responses(espnow_obj_t *self) { + mp_uint_t t, start = mp_hal_ticks_ms(); while (self->tx_responses < self->tx_packets) { if ((t = mp_hal_ticks_ms() - start) > PENDING_RESPONSES_TIMEOUT_MS) { mp_raise_OSError(MP_ETIMEDOUT); @@ -547,19 +454,26 @@ static void _wait_for_pending_responses(esp_espnow_obj_t *self) { } } -// ESPNow.send(peer_addr, message, [sync (=true), size]) -// ESPNow.send(message) -// Send a message to the peer's mac address. Optionally wait for a response. -// If peer_addr == None or any non-true value, send to all registered peers. -// If sync == True, wait for response after sending. -// If size is provided it should be the number of bytes in message to send(). -// Returns: -// True if sync==False and message sent successfully. -// True if sync==True and message is received successfully by all recipients -// False if sync==True and message is not received by at least one recipient -// Raises: EAGAIN if the internal espnow buffers are full. +//| def send(peer_addr: bytes = None, message: Union[bytes, str], sync: bool = True) -> bool: +//| """ +//| Send a message to the peer's mac address. Optionally wait for a response. +//| If peer_addr == None or any non-true value, send to all registered peers. +//| If sync == True, wait for response after sending. +//| If size is provided it should be the number of bytes in message to send(). +//| +//| Returns: +//| True if sync == False and message sent successfully. +//| True if sync == True and message is received successfully by all recipients +//| False if sync == True and message is not received by at least one recipient +//| +//| Raises: EAGAIN if the internal espnow buffers are full. +//| """ +//| ... +//| STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) { - esp_espnow_obj_t *self = _get_singleton_initialised(); + espnow_obj_t *self = args[0]; + check_for_deinit(self); + // Check the various combinations of input arguments const uint8_t *peer = (n_args > 2) ? _get_peer(args[1]) : NULL; mp_obj_t msg = (n_args > 2) ? args[2] : (n_args == 2) ? args[1] : MP_OBJ_NULL; @@ -577,139 +491,166 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) { // call has sync=True. _wait_for_pending_responses(self); } + size_t saved_failures = self->tx_failures; // Send the packet - try, try again if internal esp-now buffers are full. esp_err_t err; int64_t start = mp_hal_ticks_ms(); - while ((ESP_ERR_ESPNOW_NO_MEM == - (err = esp_now_send(peer, message.buf, message.len))) && + while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(peer, message.buf, message.len))) && (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { RUN_BACKGROUND_TASKS; } check_esp_err(err); // Will raise OSError if e != ESP_OK + // Increment the sent packet count. If peer_addr==NULL msg will be // sent to all peers EXCEPT any broadcast or multicast addresses. - self->tx_packets += ((peer == NULL) ? self->peer_count : 1); + self->tx_packets += ((peer == NULL) ? self->num_peers : 1); if (sync) { // Wait for and tally all the expected responses from peers _wait_for_pending_responses(self); } + // Return False if sync and any peers did not respond. return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures)); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_send_obj, 2, 4, espnow_send); -// ### The ESP_Now send and recv callback routines -// +//| def recv(buffers: List[bytearray(6), bytearray(250), ...], timeout: int) -> Optional[int]: +//| """ +//| Waits for an espnow message and copies the peer_addr and message into the buffers list. +//| +//| If buffers is 2 elements long, the peer_mac and message will be +//| loaded into the 1st and 2nd elements. +//| If buffers is 4 elements long, the rssi and timestamp values will be +//| loaded into the 3rd and 4th elements. +//| +//| Default timeout is set with ESPNow.config(timeout=milliseconds). +//| Returns None on timeout otherwise length of the message. +//| """ +//| ... +//| +STATIC mp_obj_t espnow_recv(size_t n_args, const mp_obj_t *args) { + espnow_obj_t *self = args[0]; + check_for_deinit(self); -// Callback triggered when a sent packet is acknowledged by the peer (or not). -// Just count the number of responses and number of failures. -// These are used in the send() logic. -STATIC void send_cb( - const uint8_t *mac_addr, esp_now_send_status_t status) { + size_t timeout_ms = ((n_args > 2 && args[2] != mp_const_none) + ? (size_t)mp_obj_get_int(args[2]) : self->recv_timeout_ms); - esp_espnow_obj_t *self = _get_singleton(); - self->tx_responses++; - if (status != ESP_NOW_SEND_SUCCESS) { - self->tx_failures++; + mp_obj_list_t *list = MP_OBJ_TO_PTR(args[1]); + if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) { + mp_arg_error_invalid(MP_QSTR_buffers); } + + mp_obj_array_t *msg = MP_OBJ_TO_PTR(list->items[1]); + if (mp_obj_is_type(msg, &mp_type_bytearray)) { + msg->len += msg->free; // Make all the space in msg array available + msg->free = 0; + } + + uint8_t peer_buf[ESP_NOW_ETH_ALEN]; + uint8_t *msg_buf = _get_bytes_len_w(msg, ESP_NOW_MAX_DATA_LEN); + + // Read the packet header from the incoming buffer + espnow_hdr_t hdr; + if (ringbuf_read_wait(self->recv_buffer, &hdr, sizeof(hdr), timeout_ms) < 1) { + return MP_OBJ_NEW_SMALL_INT(0); // Timeout waiting for packet + } + int msg_len = hdr.msg_len; + + // Check the message packet header format and read the message data + if (hdr.magic != ESPNOW_MAGIC || + msg_len > ESP_NOW_MAX_DATA_LEN || + ringbuf_read(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) < 1 || + ringbuf_read(self->recv_buffer, msg_buf, msg_len) < 1) { + mp_arg_error_invalid(MP_QSTR_buffer); + } + if (mp_obj_is_type(msg, &mp_type_bytearray)) { + // Set the length of the message bytearray. + size_t size = msg->len + msg->free; + msg->len = msg_len; + msg->free = size - msg_len; + } + + // Update rssi value in the peer device table + mp_map_elem_t *entry = _update_rssi(self, peer_buf, hdr.rssi, hdr.time_ms); + list->items[0] = entry->key; // Set first element of list to peer + if (list->len >= 4) { + list->items[2] = MP_OBJ_NEW_SMALL_INT(hdr.rssi); + list->items[3] = mp_obj_new_int(hdr.time_ms); + } + + return MP_OBJ_NEW_SMALL_INT(msg_len); } +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_recv_obj, 2, 3, espnow_recv); -// Callback triggered when an ESP-Now packet is received. -// Write the peer MAC address and the message into the recv_buffer as an -// ESPNow packet. -// If the buffer is full, drop the message and increment the dropped count. -// Schedules the user callback if one has been registered (ESPNow.config()). -STATIC void recv_cb( - const uint8_t *mac_addr, const uint8_t *msg, int msg_len) { - - esp_espnow_obj_t *self = _get_singleton(); - ringbuf_t *buf = self->recv_buffer; - // TODO: Test this works with ">". - if (sizeof(espnow_pkt_t) + msg_len >= ringbuf_free(buf)) { - self->dropped_rx_pkts++; - return; - } - espnow_hdr_t header; - header.magic = ESPNOW_MAGIC; - header.msg_len = msg_len; - #if MICROPY_ESPNOW_RSSI - header.rssi = _get_rssi_from_wifi_pkt(msg); - header.time_ms = mp_hal_ticks_ms(); - #endif // MICROPY_ESPNOW_RSSI - - ringbuf_write(buf, &header, sizeof(header)); - ringbuf_write(buf, mac_addr, ESP_NOW_ETH_ALEN); - ringbuf_write(buf, msg, msg_len); - self->rx_packets++; - #if MICROPY_ENABLE_SCHEDULER - if (self->recv_cb != mp_const_none) { - mp_sched_schedule(self->recv_cb, self->recv_cb_arg); - } - #endif +//| def any(self) -> bool: +//| """Test if data is available to read from the buffers. +//| """ +//| ... +//| +STATIC mp_obj_t espnow_any(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return ringbuf_avail(self->recv_buffer) ? mp_const_true : mp_const_false; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_any_obj, espnow_any); -// ### Peer Management Functions -// +// --- Peer Management Functions --- -// Set the ESP-NOW Primary Master Key (pmk) (for encrypted communications). -// Raise OSError if ESP-NOW functions are not initialised. -// Raise ValueError if key is not a bytes-like object exactly 16 bytes long. -STATIC mp_obj_t espnow_set_pmk(mp_obj_t _, mp_obj_t key) { +//| def set_pmk(pmk: bytes(16)) -> None: +//| """Set the ESP-NOW Primary Master Key (pmk) (for encrypted communications). +//| """ +//| ... +//| +STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { check_esp_err(esp_now_set_pmk(_get_bytes_len(key, ESP_NOW_KEY_LEN))); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); -// Common code for add_peer() and mod_peer() to process the args and kw_args: -// Raise ValueError if the LMK is not a bytes-like object of exactly 16 bytes. -// Raise TypeError if invalid keyword args or too many positional args. -// Return true if all args parsed correctly. -STATIC bool _update_peer_info( - esp_now_peer_info_t *peer, size_t n_args, - const mp_obj_t *pos_args, mp_map_t *kw_args) { - +// Common code for add_peer() and mod_peer() to process the args and kw_args. +static void _update_peer_info(esp_now_peer_info_t *peer, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_lmk, ARG_channel, ARG_ifidx, ARG_encrypt }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_lmk, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_channel, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_ifidx, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_encrypt, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_lmk, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_channel, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_ifidx, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_encrypt, MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, - MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + if (args[ARG_lmk].u_obj != mp_const_none) { mp_obj_t obj = args[ARG_lmk].u_obj; peer->encrypt = mp_obj_is_true(obj); if (peer->encrypt) { // Key must be 16 bytes in length. - memcpy(peer->lmk, - _get_bytes_len(obj, ESP_NOW_KEY_LEN), - ESP_NOW_KEY_LEN); + memcpy(peer->lmk, _get_bytes_len(obj, ESP_NOW_KEY_LEN), ESP_NOW_KEY_LEN); } } + if (args[ARG_channel].u_obj != mp_const_none) { peer->channel = mp_obj_get_int(args[ARG_channel].u_obj); } + if (args[ARG_ifidx].u_obj != mp_const_none) { peer->ifidx = mp_obj_get_int(args[ARG_ifidx].u_obj); } + if (args[ARG_encrypt].u_obj != mp_const_none) { peer->encrypt = mp_obj_is_true(args[ARG_encrypt].u_obj); } - return true; } -// Update the cached peer count in self->peer_count; -// The peer_count ignores broadcast and multicast addresses and is used for the +// Update the cached peer count in self->num_peers; +// The num_peers ignores broadcast and multicast addresses and is used for the // send() logic and is updated from add_peer(), mod_peer() and del_peer(). -STATIC void _update_peer_count(void) { - esp_espnow_obj_t *self = _get_singleton_initialised(); - +static void _update_peer_count(espnow_obj_t *self) { esp_now_peer_info_t peer = {0}; bool from_head = true; int count = 0; + // esp_now_fetch_peer() skips over any broadcast or multicast addresses while (esp_now_fetch_peer(from_head, &peer) == ESP_OK) { from_head = false; @@ -717,41 +658,75 @@ STATIC void _update_peer_count(void) { break; // Should not happen } } - self->peer_count = count; + + self->num_peers = count; } -// ESPNow.add_peer(peer_mac, [lmk, [channel, [ifidx, [encrypt]]]]) or -// ESPNow.add_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], -// [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) -// Positional args set to None will be left at defaults. -// Raise OSError if ESPNow.init() has not been called. -// Raise ValueError if mac or LMK are not bytes-like objects or wrong length. -// Raise TypeError if invalid keyword args or too many positional args. -// Return None. -STATIC mp_obj_t espnow_add_peer( - size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { +// ESPNow.add_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) + +//| def add_peer(self, peer_mac: bytes(6), lmk: bytes, channel: int, ifidx: int, encrypt: bool) -> None: +//| """ +//| Positional args set to None will be left at defaults. +//| Raise ValueError if mac or LMK are not bytes-like objects or wrong length. +//| Raise TypeError if invalid keyword args or too many positional args. +//| """ +//| ... +//| +STATIC mp_obj_t espnow_add_peer(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + espnow_obj_t *self = args[0]; + check_for_deinit(self); esp_now_peer_info_t peer = {0}; memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN); - _update_peer_info(&peer, n_args - 2, args + 2, kw_args); + _update_peer_info(&peer, n_args - 2, args + 2, kw_args); check_esp_err(esp_now_add_peer(&peer)); - _update_peer_count(); + _update_peer_count(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_add_peer_obj, 2, espnow_add_peer); -// ESPNow.del_peer(peer_mac): Unregister peer_mac. -// Raise OSError if ESPNow.init() has not been called. -// Raise ValueError if peer is not a bytes-like objects or wrong length. -// Return None. -STATIC mp_obj_t espnow_del_peer(mp_obj_t _, mp_obj_t peer) { +// ESPNow.mod_peer(self, peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) + +//| def mod_peer(self, peer_mac: bytes(6), lmk: bytes, channel: int, ifidx: int, encrypt: bool) -> None: +//| """ +//| Positional args set to None will be left at current values. +//| Raise ValueError if mac or LMK are not bytes-like objects or wrong length. +//| Raise TypeError if invalid keyword args or too many positional args. +//| """ +//| ... +//| +STATIC mp_obj_t espnow_mod_peer(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + espnow_obj_t *self = args[0]; + check_for_deinit(self); + + esp_now_peer_info_t peer = {0}; + memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN); + check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); + + _update_peer_info(&peer, n_args - 2, args + 2, kw_args); + check_esp_err(esp_now_mod_peer(&peer)); + _update_peer_count(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_mod_peer_obj, 2, espnow_mod_peer); + +//| def del_peer(peer_mac: bytes(6)) -> None: +//| """Un-register peer_mac. +//| """ +//| ... +//| +STATIC mp_obj_t espnow_del_peer(mp_obj_t self_in, mp_obj_t peer) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + uint8_t peer_addr[ESP_NOW_ETH_ALEN]; memcpy(peer_addr, _get_peer(peer), ESP_NOW_ETH_ALEN); check_esp_err(esp_now_del_peer(peer_addr)); - _update_peer_count(); + _update_peer_count(self); return mp_const_none; } @@ -768,127 +743,95 @@ static mp_obj_t _peer_info_to_tuple(const esp_now_peer_info_t *peer) { (peer->encrypt) ? mp_const_true : mp_const_false); } -// ESPNow.get_peers(): Fetch peer_info records for all registered ESPNow peers. -// Raise OSError if ESPNow.init() has not been called. -// Return a tuple of tuples: -// ((peer_addr, lmk, channel, ifidx, encrypt), -// (peer_addr, lmk, channel, ifidx, encrypt), ...) -STATIC mp_obj_t espnow_get_peers(mp_obj_t _) { - esp_espnow_obj_t *self = _get_singleton_initialised(); +//| def get_peer(self, peer_mac: bytes(6)) -> Tuple[bytes, int, int, bool]: +//| """ +//| Get the peer info for peer_mac as a tuple. +//| Raise ValueError if mac or LMK are not bytes-like objects or wrong length. +//| Returns a tuple of (peer_addr, lmk, channel, ifidx, encrypt). +//| """ +//| ... +//| +STATIC mp_obj_t espnow_get_peer(mp_obj_t self_in, mp_obj_t peer_mac) { + esp_now_peer_info_t peer = {0}; + memcpy(peer.peer_addr, _get_peer(peer_mac), ESP_NOW_ETH_ALEN); + check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); + return _peer_info_to_tuple(&peer); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_get_peer_obj, espnow_get_peer); + +//| def get_peers(self) -> Tuple[Tuple[bytes, bytes, int, int, bool], ...]: +//| """ +//| Fetch peer_info records for all registered ESPNow peers. +//| Returns a tuple of tuples: ((peer_addr, lmk, channel, ifidx, encrypt), ...) +//| """ +//| ... +//| +STATIC mp_obj_t espnow_get_peers(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); // Build and initialise the peer info tuple. - mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->peer_count, NULL); + mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->num_peers, NULL); esp_now_peer_info_t peer = {0}; + for (size_t i = 0; i < peerinfo_tuple->len; i++) { esp_err_t status = esp_now_fetch_peer((i == 0), &peer); - peerinfo_tuple->items[i] = - (status == ESP_OK ? _peer_info_to_tuple(&peer) : mp_const_none); + peerinfo_tuple->items[i] = (status == ESP_OK ? _peer_info_to_tuple(&peer) : mp_const_none); } return peerinfo_tuple; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_obj, espnow_get_peers); -#if MICROPY_ESPNOW_EXTRA_PEER_METHODS -// ESPNow.get_peer(peer_mac): Get the peer info for peer_mac as a tuple. -// Raise OSError if ESPNow.init() has not been called. -// Raise ValueError if mac or LMK are not bytes-like objects or wrong length. -// Return a tuple of (peer_addr, lmk, channel, ifidx, encrypt). -STATIC mp_obj_t espnow_get_peer(mp_obj_t _, mp_obj_t arg1) { - esp_now_peer_info_t peer = {0}; - memcpy(peer.peer_addr, _get_peer(arg1), ESP_NOW_ETH_ALEN); - - check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); - - return _peer_info_to_tuple(&peer); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_get_peer_obj, espnow_get_peer); - -// ESPNow.mod_peer(peer_mac, [lmk, [channel, [ifidx, [encrypt]]]]) or -// ESPNow.mod_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], -// [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) -// Positional args set to None will be left at current values. -// Raise OSError if ESPNow.init() has not been called. -// Raise ValueError if mac or LMK are not bytes-like objects or wrong length. -// Raise TypeError if invalid keyword args or too many positional args. -// Return None. -STATIC mp_obj_t espnow_mod_peer( - size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - - esp_now_peer_info_t peer = {0}; - memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN); - check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); - - _update_peer_info(&peer, n_args - 2, args + 2, kw_args); - - check_esp_err(esp_now_mod_peer(&peer)); - _update_peer_count(); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_mod_peer_obj, 2, espnow_mod_peer); - -// ESPNow.espnow_peer_count(): Get the number of registered peers. -// Raise OSError if ESPNow.init() has not been called. -// Return a tuple of (num_total_peers, num_encrypted_peers). -STATIC mp_obj_t espnow_peer_count(mp_obj_t _) { +//| num_peers: Tuple[int, int] +//| """The number of registered peers in a tuple of (num_total_peers, num_encrypted_peers). (read-only) +//| """ +//| +STATIC mp_obj_t espnow_get_num_peers(mp_obj_t self_in) { esp_now_peer_num_t peer_num = {0}; check_esp_err(esp_now_get_peer_num(&peer_num)); - return NEW_TUPLE( mp_obj_new_int(peer_num.total_num), mp_obj_new_int(peer_num.encrypt_num)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_count_obj, espnow_peer_count); -#endif +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_num_peers_obj, espnow_get_num_peers); -STATIC const mp_rom_map_elem_t esp_espnow_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&espnow_active_obj) }, - { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&espnow_config_obj) }, - { MP_ROM_QSTR(MP_QSTR_on_recv), MP_ROM_PTR(&espnow_on_recv_obj) }, - { MP_ROM_QSTR(MP_QSTR_stats), MP_ROM_PTR(&espnow_stats_obj) }, +MP_PROPERTY_GETTER(espnow_num_peers_obj, + (mp_obj_t)&espnow_get_num_peers_obj); + +STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&espnow_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&espnow_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_stats), MP_ROM_PTR(&espnow_stats_obj) }, // Send and receive messages - { MP_ROM_QSTR(MP_QSTR_recvinto), MP_ROM_PTR(&espnow_recvinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, - { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&espnow_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&espnow_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&espnow_any_obj) }, // Peer management functions - { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) }, - { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_del_peer), MP_ROM_PTR(&espnow_del_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_peers), MP_ROM_PTR(&espnow_get_peers_obj) }, - #if MICROPY_ESPNOW_EXTRA_PEER_METHODS - { MP_ROM_QSTR(MP_QSTR_mod_peer), MP_ROM_PTR(&espnow_mod_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_peer), MP_ROM_PTR(&espnow_get_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_peer_count), MP_ROM_PTR(&espnow_peer_count_obj) }, - #endif // MICROPY_ESPNOW_EXTRA_PEER_METHODS + { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) }, + { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_mod_peer), MP_ROM_PTR(&espnow_mod_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_del_peer), MP_ROM_PTR(&espnow_del_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_peer), MP_ROM_PTR(&espnow_get_peer_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_peers), MP_ROM_PTR(&espnow_get_peers_obj) }, + { MP_ROM_QSTR(MP_QSTR_num_peers), MP_ROM_PTR(&espnow_num_peers_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(esp_espnow_locals_dict, esp_espnow_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(espnow_locals_dict, espnow_locals_dict_table); -STATIC const mp_rom_map_elem_t espnow_globals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__espnow) }, - { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&esp_espnow_type) }, - { MP_ROM_QSTR(MP_QSTR_MAX_DATA_LEN), MP_ROM_INT(ESP_NOW_MAX_DATA_LEN)}, - { MP_ROM_QSTR(MP_QSTR_ETH_ALEN), MP_ROM_INT(ESP_NOW_ETH_ALEN)}, - { MP_ROM_QSTR(MP_QSTR_KEY_LEN), MP_ROM_INT(ESP_NOW_KEY_LEN)}, - { MP_ROM_QSTR(MP_QSTR_MAX_TOTAL_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_TOTAL_PEER_NUM)}, - { MP_ROM_QSTR(MP_QSTR_MAX_ENCRYPT_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_ENCRYPT_PEER_NUM)}, -}; -STATIC MP_DEFINE_CONST_DICT(espnow_globals_dict, espnow_globals_dict_table); - -// ### Dummy Buffer Protocol support +// --- Dummy Buffer Protocol support --- // ...so asyncio can poll.ipoll() on this device // Support ioctl(MP_STREAM_POLL, ) for asyncio -STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, - uintptr_t arg, int *errcode) { +STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { if (request != MP_STREAM_POLL) { *errcode = MP_EINVAL; return MP_STREAM_ERROR; } - esp_espnow_obj_t *self = _get_singleton(); - return (self->recv_buffer == NULL) ? 0 : // If not initialised + + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return (espnow_deinited(self)) ? 0 : // If not initialised arg ^ ( // If no data in the buffer, unset the Read ready flag ((ringbuf_avail(self->recv_buffer) == 0) ? MP_STREAM_POLL_RD : 0) | @@ -900,16 +843,14 @@ STATIC const mp_stream_p_t espnow_stream_p = { .ioctl = espnow_stream_ioctl, }; -#if MICROPY_ESPNOW_RSSI -// Return reference to the dictionary of peers we have seen: -// {peer1: (rssi, time_sec), peer2: (rssi, time_msec), ...} -// where: -// peerX is a byte string containing the 6-byte mac address of the peer, -// rssi is the wifi signal strength from the last msg received -// (in dBm from -127 to 0) -// time_sec is the time in milliseconds since device last booted. +// Return reference to the dictionary of peers we have seen: +// {peer1: (rssi, time), peer2: (rssi, time), ...} +// where: +// peerX is a byte string containing the 6-byte mac address of the peer, +// rssi is the wifi signal strength from the last msg received (in dBm from -127 to 0) +// time is the time in milliseconds since device last booted. STATIC void espnow_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - esp_espnow_obj_t *self = _get_singleton(); + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] != MP_OBJ_NULL) { // Only allow "Load" operation return; } @@ -917,27 +858,17 @@ STATIC void espnow_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { dest[0] = self->peers_table; return; } - dest[1] = MP_OBJ_SENTINEL; // Attribute not found + dest[1] = MP_OBJ_SENTINEL; // Attribute not found } -#endif // MICROPY_ESPNOW_RSSI -STATIC const mp_obj_type_t esp_espnow_type = { +const mp_obj_type_t espnow_type = { { &mp_type_type }, - .name = MP_QSTR_ESPNow, + .name = MP_QSTR_NOW, .make_new = espnow_make_new, - .locals_dict = (mp_obj_t)&esp_espnow_locals_dict, - #if MICROPY_ESPNOW_RSSI + .locals_dict = (mp_obj_t)&espnow_locals_dict, .attr = espnow_attr, - #endif // MICROPY_ESPNOW_RSSI .flags = MP_TYPE_FLAG_EXTENDED, MP_TYPE_EXTENDED_FIELDS( .protocol = &espnow_stream_p, ), }; - -const mp_obj_module_t mp_module_espnow = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&espnow_globals_dict, -}; - -MP_REGISTER_MODULE(MP_QSTR__espnow, mp_module_espnow, CIRCUITPY_ESPNOW); diff --git a/ports/espressif/bindings/espnow/ESPNow.h b/ports/espressif/bindings/espnow/Now.h similarity index 95% rename from ports/espressif/bindings/espnow/ESPNow.h rename to ports/espressif/bindings/espnow/Now.h index 9855cd4ff8..6aa011c501 100644 --- a/ports/espressif/bindings/espnow/ESPNow.h +++ b/ports/espressif/bindings/espnow/Now.h @@ -26,4 +26,6 @@ */ #pragma once -void espnow_reset(void); + +#include "py/obj.h" +extern const mp_obj_type_t espnow_type; diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c new file mode 100644 index 0000000000..52325dad58 --- /dev/null +++ b/ports/espressif/bindings/espnow/__init__.c @@ -0,0 +1,85 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/util.h" + +#include "bindings/espnow/__init__.h" +#include "bindings/espnow/Now.h" + +//| """ESP-NOW Module +//| +//| The `espnow` module provides an interface to the +//| `ESP-NOW `_ +//| protocol provided by Espressif on its SoCs +//| (`API docs `_). +//| +//| **Sender:** :: +//| +//| import espnow +//| +//| e = espnow.ESPNow() +//| e.active(True) +//| peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' # MAC address of peer's wifi interface +//| e.add_peer(peer) +//| +//| e.send("Starting...") # Send to all peers +//| for i in range(100): +//| e.send(peer, str(i)*20, True) +//| e.send(b'end') +//| +//| **Receiver:** :: +//| +//| import espnow +//| +//| e = espnow.ESPNow() +//| e.active(True) +//| peer = b'\xaa\xaa\xaa\xaa\xaa\xaa' # MAC address of peer's wifi interface +//| e.add_peer(peer) +//| +//| while True: +//| host, msg = e.recv() +//| if msg: # msg == None if timeout in recv() +//| print(host, msg) +//| if msg == b'end': +//| break +//| """ +//| ... +//| + +STATIC const mp_rom_map_elem_t espnow_module_globals_table[] = { + // module name + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espnow) }, + // module classes + { MP_ROM_QSTR(MP_QSTR_Now), MP_ROM_PTR(&espnow_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(espnow_module_globals, espnow_module_globals_table); + +const mp_obj_module_t espnow_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&espnow_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_espnow, espnow_module, CIRCUITPY_ESPNOW); diff --git a/ports/espressif/bindings/espnow/__init__.h b/ports/espressif/bindings/espnow/__init__.h new file mode 100644 index 0000000000..fb814a434f --- /dev/null +++ b/ports/espressif/bindings/espnow/__init__.h @@ -0,0 +1,29 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +void espnow_reset(void); diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 8c206cf02a..e4733356bb 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -44,7 +44,7 @@ #endif #if CIRCUITPY_ESPNOW -#define ESPNOW_ROOT_POINTERS struct _esp_espnow_obj_t *espnow_singleton; +#define ESPNOW_ROOT_POINTERS struct _espnow_obj_t *espnow_singleton; #else #define ESPNOW_ROOT_POINTERS #endif diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 8a6dfabb5f..be33b87cca 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -37,7 +37,7 @@ #include "freertos/task.h" #include "bindings/espidf/__init__.h" -#include "bindings/espnow/ESPNow.h" +#include "bindings/espnow/__init__.h" #include "bindings/espulp/__init__.h" #include "common-hal/microcontroller/Pin.h" #include "common-hal/analogio/AnalogOut.h" From 3c10dd8b5f033e8822f845359c4ef1812c331d6b Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Mon, 23 Jan 2023 23:10:00 +0530 Subject: [PATCH 04/29] update espnow api --- locale/circuitpython.pot | 12 +- .../bindings/espnow/{Now.c => ESPNow.c} | 776 +++++++++--------- .../bindings/espnow/{Now.h => ESPNow.h} | 0 ports/espressif/bindings/espnow/__init__.c | 12 +- py/objtuple.h | 3 + py/ringbuf.c | 64 +- py/ringbuf.h | 10 - 7 files changed, 415 insertions(+), 462 deletions(-) rename ports/espressif/bindings/espnow/{Now.c => ESPNow.c} (50%) rename ports/espressif/bindings/espnow/{Now.h => ESPNow.h} (100%) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index d0fb9e5da4..cca9e1b067 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -124,7 +124,7 @@ msgstr "" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/ESPNow.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -2430,7 +2430,7 @@ msgstr "" msgid "addresses is empty" msgstr "" -#: ports/espressif/bindings/espnow/Now.c +#: ports/espressif/bindings/espnow/ESPNow.c msgid "an error occured" msgstr "" @@ -3814,6 +3814,10 @@ msgstr "" msgid "parameters must be registers in sequence r0 to r3" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "peer already exists" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c msgid "pixel coordinates out of bounds" msgstr "" @@ -4158,10 +4162,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: ports/espressif/bindings/espnow/Now.c -msgid "unknown config param" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" diff --git a/ports/espressif/bindings/espnow/Now.c b/ports/espressif/bindings/espnow/ESPNow.c similarity index 50% rename from ports/espressif/bindings/espnow/Now.c rename to ports/espressif/bindings/espnow/ESPNow.c index 935a740164..0bcd7d39ed 100644 --- a/ports/espressif/bindings/espnow/Now.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -38,18 +38,15 @@ #include "mphalport.h" #include "bindings/espnow/__init__.h" -#include "bindings/espnow/Now.h" +#include "bindings/espnow/ESPNow.h" #include "shared-bindings/util.h" #include "shared-bindings/wifi/__init__.h" -// Relies on gcc Variadic Macros and Statement Expressions -#define NEW_TUPLE(...) ({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z);}) - #define ESPNOW_MAGIC 0x99 // The maximum length of an espnow packet (bytes) -#define MAX_PACKET_LEN (sizeof(espnow_pkt_t) + ESP_NOW_MAX_DATA_LEN) +#define MAX_PACKET_LEN (sizeof(espnow_packet_t) + ESP_NOW_MAX_DATA_LEN) // Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes // Will allocate an additional 7 bytes for buffer overhead @@ -73,26 +70,26 @@ typedef struct { uint8_t msg_len; // Length of the message uint32_t time_ms; // Timestamp (ms) when packet is received int8_t rssi; // RSSI value (dBm) (-127 to 0) -} __attribute__((packed)) espnow_hdr_t; +} __attribute__((packed)) espnow_header_t; typedef struct { - espnow_hdr_t hdr; // The header + espnow_header_t header; // The header uint8_t peer[6]; // Peer address uint8_t msg[0]; // Message is up to 250 bytes -} __attribute__((packed)) espnow_pkt_t; +} __attribute__((packed)) espnow_packet_t; // The data structure for the espnow_singleton. typedef struct _espnow_obj_t { mp_obj_base_t base; ringbuf_t *recv_buffer; // A buffer for received packets size_t recv_buffer_size; // The size of the recv_buffer - size_t recv_timeout_ms; // Timeout for recv() + wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. volatile size_t rx_packets; // # of received packets volatile size_t rx_failures; // # of dropped packets (buffer full) size_t tx_packets; // # of sent packets volatile size_t tx_responses; // # of sent packet responses received volatile size_t tx_failures; // # of sent packet responses failed - size_t num_peers; // Cache the # of peers for send(sync=True) + size_t peers_count; // Cache the # of peers for send(sync=True) mp_obj_t peers_table; // A dictionary of discovered peers } espnow_obj_t; @@ -105,8 +102,6 @@ static void check_esp_err(esp_err_t status) { // --- Initialisation and Config functions --- // Return a pointer to the ESPNow module singleton -// If state == INITIALISED check the device has been initialised. -// Raises OSError if not initialised and state == INITIALISED. static espnow_obj_t *_get_singleton(void) { return MP_STATE_PORT(espnow_singleton); } @@ -115,43 +110,57 @@ static bool espnow_deinited(espnow_obj_t *self) { return self->recv_buffer == NULL; } -// Return a pointer to the ESPNow module singleton -// If state == INITIALISED check the device has been initialised. -// Raises OSError if not initialised and state == INITIALISED. static void check_for_deinit(espnow_obj_t *self) { if (espnow_deinited(self)) { raise_deinited_error(); } } -//| class Now: -//| def __init__(self) -> Now: -//| """ -//| Allocate and initialise the ESPNow module as a singleton. -//| Returns the initialised espnow_singleton. -//| """ -//| ... +static void _set_buffer_size(espnow_obj_t *self, mp_int_t value) { + self->recv_buffer_size = mp_arg_validate_int_min(value, MAX_PACKET_LEN, MP_QSTR_buffer_size); +}; + +static void _set_phy_rate(espnow_obj_t *self, mp_int_t value) { + self->phy_rate = mp_arg_validate_int_range(value, 0, WIFI_PHY_RATE_MAX - 1, MP_QSTR_phy_rate); +}; + +//| class ESPNow: +//| """Provides access to the ESP-NOW protocol.""" //| +//| def __init__(self, buffer_size: Optional[int], phy_rate: Optional[int]) -> None: +//| """Allocate and initialize `ESPNow` instance as a singleton. +//| +//| :param int buffer_size: The size of the internal ring buffer (length > 263 bytes). Default: 526 bytes. +//| :param int phy_rate: The ESP-NOW physical layer rate. Default 1 Mbps.""" +//| ... STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_buffer_size, ARG_phy_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer_size, MP_ARG_INT, { .u_int = DEFAULT_RECV_BUFFER_SIZE } }, + { MP_QSTR_phy_rate, MP_ARG_INT, { .u_int = WIFI_PHY_RATE_1M_L } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + espnow_obj_t *self = _get_singleton(); - if (self != NULL) { - return self; + if (self == NULL) { + self = m_new_obj(espnow_obj_t); + self->base.type = &espnow_type; + + _set_buffer_size(self, args[ARG_buffer_size].u_int); + _set_phy_rate(self, args[ARG_phy_rate].u_int); + + self->peers_table = mp_obj_new_dict(0); + + // Prevent user code modifying the dict + mp_obj_dict_get_map(self->peers_table)->is_fixed = 1; + + // Set the global singleton pointer for the espnow protocol. + MP_STATE_PORT(espnow_singleton) = self; } - self = m_new_obj(espnow_obj_t); - self->base.type = &espnow_type; - self->recv_buffer_size = DEFAULT_RECV_BUFFER_SIZE; - self->recv_timeout_ms = DEFAULT_RECV_TIMEOUT_MS; - self->recv_buffer = NULL; - self->peers_table = mp_obj_new_dict(0); - - // Prevent user code modifying the dict - mp_obj_dict_get_map(self->peers_table)->is_fixed = 1; - - // Set the global singleton pointer for the espnow protocol. - MP_STATE_PORT(espnow_singleton) = self; - return self; } @@ -160,7 +169,7 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t // Callback triggered when a sent packet is acknowledged by the peer (or not). // Just count the number of responses and number of failures. // These are used in the send() logic. -static void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) { +static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { espnow_obj_t *self = _get_singleton(); self->tx_responses++; if (status != ESP_NOW_SEND_SUCCESS) { @@ -168,58 +177,49 @@ static void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) { } } -static inline int8_t _get_rssi_from_wifi_pkt(const uint8_t *msg); +static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg); -// Callback triggered when an ESP-Now packet is received. +// Callback triggered when an ESP-NOW packet is received. // Write the peer MAC address and the message into the recv_buffer as an ESPNow packet. // If the buffer is full, drop the message and increment the dropped count. -// Schedules the user callback if one has been registered (ESPNow.config()). -static void recv_cb(const uint8_t *mac_addr, const uint8_t *msg, int msg_len) { +static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { espnow_obj_t *self = _get_singleton(); ringbuf_t *buf = self->recv_buffer; - // TODO: Test this works with ">". - if (sizeof(espnow_pkt_t) + msg_len >= ringbuf_free(buf)) { + if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { self->rx_failures++; return; } - espnow_hdr_t header; + espnow_header_t header; header.magic = ESPNOW_MAGIC; header.msg_len = msg_len; - header.rssi = _get_rssi_from_wifi_pkt(msg); + header.rssi = _get_rssi_from_wifi_packet(msg); header.time_ms = mp_hal_ticks_ms(); - ringbuf_write(buf, &header, sizeof(header)); - ringbuf_write(buf, mac_addr, ESP_NOW_ETH_ALEN); - ringbuf_write(buf, msg, msg_len); + ringbuf_put_n(buf, (uint8_t *)&header, sizeof(header)); + ringbuf_put_n(buf, mac, ESP_NOW_ETH_ALEN); + ringbuf_put_n(buf, msg, msg_len); self->rx_packets++; } -static void _wifi_init(void) { - if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { - common_hal_wifi_init(false); - common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); - } -} - -//| def init() -> None: -//| """ -//| Initialise the data buffers and ESP-NOW functions. -//| Initialise the Espressif ESP-NOW software stack, register callbacks -//| and allocate the recv data buffers. -//| """ -//| ... -//| +// Initialize the ESP-NOW software stack, +// register callbacks and allocate the recv data buffers. static void espnow_init(espnow_obj_t *self) { - if (espnow_deinited(self)) { // Already initialised + if (espnow_deinited(self)) { self->recv_buffer = m_new_obj(ringbuf_t); if (!ringbuf_alloc(self->recv_buffer, self->recv_buffer_size, true)) { m_malloc_fail(self->recv_buffer_size); } - _wifi_init(); // Call the wifi init code + if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + common_hal_wifi_init(false); + common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); + } + + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, self->phy_rate)); + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, self->phy_rate)); check_esp_err(esp_now_init()); check_esp_err(esp_now_register_send_cb(send_cb)); @@ -227,13 +227,8 @@ static void espnow_init(espnow_obj_t *self) { } } -//| def deinit() -> None: -//| """ -//| De-initialise the ESP-NOW software stack, disable callbacks -//| and deallocate the recv data buffers. -//| """ -//| ... -//| +// De-initialize the ESP-NOW software stack, +// disable callbacks and deallocate the recv data buffers. static void espnow_deinit(espnow_obj_t *self) { if (self != NULL && !espnow_deinited(self)) { check_esp_err(esp_now_unregister_send_cb()); @@ -241,7 +236,7 @@ static void espnow_deinit(espnow_obj_t *self) { check_esp_err(esp_now_deinit()); self->recv_buffer->buf = NULL; self->recv_buffer = NULL; - self->num_peers = 0; // esp_now_deinit() removes all peers. + self->peers_count = 0; // esp_now_deinit() removes all peers. self->tx_packets = self->tx_responses; } } @@ -251,89 +246,94 @@ void espnow_reset(void) { MP_STATE_PORT(espnow_singleton) = NULL; } -//| def active(state: bool) -> bool: -//| """ -//| Initialise or de-initialise the ESPNow communication protocol -//| depending on the value of the flag optional argument. -//| """ -//| ... -//| -STATIC mp_obj_t espnow_active(size_t n_args, const mp_obj_t *args) { - espnow_obj_t *self = args[0]; - if (n_args > 1) { - if (mp_obj_is_true(args[1])) { - espnow_init(self); - } else { - espnow_deinit(self); - } - } - return mp_obj_new_bool(!espnow_deinited(self)); +// Return C pointer to byte memory string/bytes/bytearray in obj. +// Raise ValueError if the length does not match expected len. +static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(obj, &bufinfo, rw); + mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); + return (uint8_t *)bufinfo.buf; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_active_obj, 1, 2, espnow_active); -//| def config(['param'|param=value, ..]) -> int: -//| """ -//| Get or set configuration values. Supported config params: -//| buffer: size of buffer for rx packets (default=514 bytes) -//| timeout: Default read timeout (default=300,000 milliseconds) -//| """ -//| ... +//| def set_pmk(self, pmk: bytes) -> None: +//| """Set the ESP-NOW Primary Master Key (pmk) for encrypted communications. //| -STATIC mp_obj_t espnow_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - espnow_obj_t *self = pos_args[0]; - enum { ARG_get, ARG_buffer, ARG_timeout, ARG_rate }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_buffer, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (args[ARG_buffer].u_int >= 0) { - self->recv_buffer_size = args[ARG_buffer].u_int; - } - - if (args[ARG_timeout].u_int >= 0) { - self->recv_timeout_ms = args[ARG_timeout].u_int; - } - - if (args[ARG_rate].u_int >= 0) { - _wifi_init(); // Call the wifi init code - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, args[ARG_rate].u_int)); - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, args[ARG_rate].u_int)); - } - - if (args[ARG_get].u_obj == MP_OBJ_NULL) { - return mp_const_none; - } - -#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x) - // Return the value of the requested parameter - uintptr_t name = (uintptr_t)args[ARG_get].u_obj; - if (name == QS(MP_QSTR_buffer)) { - return mp_obj_new_int(self->recv_buffer_size); - } else if (name == QS(MP_QSTR_timeout)) { - return mp_obj_new_int(self->recv_timeout_ms); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); - } -#undef QS - +//| :param bytes pmk: The ESP-NOW Primary Master Key (length = 16 bytes).""" +//| ... +STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { + check_esp_err(esp_now_set_pmk(_get_bytes_len(key, ESP_NOW_KEY_LEN, MP_BUFFER_READ))); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_config_obj, 1, espnow_config); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); + +//| active: bool +//| """Initialize or de-initialize the `ESPNow` communication protocol.""" +//| +STATIC mp_obj_t espnow_get_active(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(!espnow_deinited(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_active_obj, espnow_get_active); + +STATIC mp_obj_t espnow_set_active(const mp_obj_t self_in, const mp_obj_t value) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_is_true(value) ? espnow_init(self) : espnow_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_active_obj, espnow_set_active); + +MP_PROPERTY_GETSET(espnow_active_obj, + (mp_obj_t)&espnow_get_active_obj, + (mp_obj_t)&espnow_set_active_obj); + + +//| buffer_size: int +//| """The size of the internal ring buffer.""" +//| +STATIC mp_obj_t espnow_get_buffer_size(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->recv_buffer_size); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_buffer_size_obj, espnow_get_buffer_size); + +STATIC mp_obj_t espnow_set_buffer_size(const mp_obj_t self_in, const mp_obj_t value) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + _set_buffer_size(self, mp_obj_get_int(value)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_buffer_size_obj, espnow_set_buffer_size); + +MP_PROPERTY_GETSET(espnow_buffer_size_obj, + (mp_obj_t)&espnow_get_buffer_size_obj, + (mp_obj_t)&espnow_set_buffer_size_obj); + +//| phy_rate: int +//| """The ESP-NOW physical layer rate.""" +//| +STATIC mp_obj_t espnow_get_phy_rate(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->phy_rate); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_phy_rate_obj, espnow_get_phy_rate); + +STATIC mp_obj_t espnow_set_phy_rate(const mp_obj_t self_in, const mp_obj_t value) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + _set_phy_rate(self, mp_obj_get_int(value)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_phy_rate_obj, espnow_set_phy_rate); + +MP_PROPERTY_GETSET(espnow_phy_rate_obj, + (mp_obj_t)&espnow_get_phy_rate_obj, + (mp_obj_t)&espnow_set_phy_rate_obj); //| stats: Tuple[int, int, int, int, int] -//| """Provide some useful stats. -//| Returns a tuple of (tx_packets, tx_responses, tx_failures, rx_packets, rx_failures). -//| """ +//| """Provide some useful stats in a `tuple` of +//| (tx_packets, tx_responses, tx_failures, rx_packets, rx_failures). (read-only)""" //| STATIC mp_obj_t espnow_get_stats(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return NEW_TUPLE( + return MP_OBJ_NEW_TUPLE( mp_obj_new_int(self->tx_packets), mp_obj_new_int(self->tx_responses), mp_obj_new_int(self->tx_failures), @@ -346,26 +346,26 @@ MP_PROPERTY_GETTER(espnow_stats_obj, (mp_obj_t)&espnow_get_stats_obj); // --- Maintaining the peer table and reading RSSI values --- -// + // We maintain a peers table for several reasons, to: // - support monitoring the RSSI values for all peers; and // - to return unique bytestrings for each peer which supports more efficient // application memory usage and peer handling. // Get the RSSI value from the wifi packet header -static inline int8_t _get_rssi_from_wifi_pkt(const uint8_t *msg) { +static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { // Warning: Secret magic to get the rssi from the wifi packet header // See espnow.c:espnow_recv_cb() at https://github.com/espressif/esp-now/ // In the wifi packet the msg comes after a wifi_promiscuous_pkt_t // and a espnow_frame_format_t. // Backtrack to get a pointer to the wifi_promiscuous_pkt_t. - static const size_t sizeof_espnow_frame_format = 39; + #define SIZEOF_ESPNOW_FRAME_FORMAT 39 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" - wifi_promiscuous_pkt_t *wifi_pkt = (wifi_promiscuous_pkt_t *)( - msg - sizeof_espnow_frame_format - sizeof(wifi_promiscuous_pkt_t)); + wifi_promiscuous_pkt_t *wifi_packet = (wifi_promiscuous_pkt_t *)( + msg - SIZEOF_ESPNOW_FRAME_FORMAT - sizeof(wifi_promiscuous_pkt_t)); #pragma GCC diagnostic pop - return wifi_pkt->rx_ctrl.rssi; + return wifi_packet->rx_ctrl.rssi; } // Lookup a peer in the peers table and return a reference to the item in the peers_table. @@ -388,54 +388,24 @@ static mp_map_elem_t *_lookup_add_peer(espnow_obj_t *self, const uint8_t *peer) return item; } -// Update the peers table with the new rssi value from a received pkt and +// Update the peers table with the new rssi value from a received packet and // return a reference to the item in the peers_table. -static mp_map_elem_t *_update_rssi(espnow_obj_t *self, const uint8_t *peer, int8_t rssi, uint32_t time_ms) { +static void _update_rssi(espnow_obj_t *self, const uint8_t *peer, int8_t rssi, uint32_t time_ms) { // Lookup the peer in the device table mp_map_elem_t *item = _lookup_add_peer(self, peer); mp_obj_list_t *list = MP_OBJ_TO_PTR(item->value); list->items[0] = MP_OBJ_NEW_SMALL_INT(rssi); list->items[1] = mp_obj_new_int(time_ms); - return item; } // --- Handling espnow packets in the recv buffer --- -// --- Send and Receive ESP_Now data --- - -// Return C pointer to byte memory string/bytes/bytearray in obj. -// Raise ValueError if the length does not match expected len. -static uint8_t *_get_bytes_len_rw(mp_obj_t obj, size_t len, mp_uint_t rw) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(obj, &bufinfo, rw); - mp_arg_validate_length(bufinfo.len, len, MP_QSTR_bytes); - return (uint8_t *)bufinfo.buf; -} - -static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len) { - return _get_bytes_len_rw(obj, len, MP_BUFFER_READ); -} - -static uint8_t *_get_bytes_len_w(mp_obj_t obj, size_t len) { - return _get_bytes_len_rw(obj, len, MP_BUFFER_WRITE); -} +// --- Send and Receive ESP-NOW data --- // Return C pointer to the MAC address. -// Raise ValueError if mac_addr is wrong type or is not 6 bytes long. -static const uint8_t *_get_peer(mp_obj_t mac_addr) { - return mp_obj_is_true(mac_addr) ? _get_bytes_len(mac_addr, ESP_NOW_ETH_ALEN) : NULL; -} - -// Copy data from the ring buffer - wait if buffer is empty up to timeout_ms -static int ringbuf_read_wait(ringbuf_t *r, void *data, size_t len, int timeout_ms) { - int64_t end = mp_hal_ticks_ms() + timeout_ms; - int status = 0; - while ( - ((status = ringbuf_read(r, data, len)) == 0) && - (end - (int64_t)mp_hal_ticks_ms()) >= 0) { - RUN_BACKGROUND_TASKS; - } - return status; +// Raise ValueError if mac is wrong type or is not 6 bytes long. +static const uint8_t *_get_peer_addr(mp_obj_t mac) { + return mp_obj_is_true(mac) ? _get_bytes_len(mac, ESP_NOW_ETH_ALEN, MP_BUFFER_READ) : NULL; } // Used by espnow_send() for sends() with sync==True. @@ -454,57 +424,70 @@ static void _wait_for_pending_responses(espnow_obj_t *self) { } } -//| def send(peer_addr: bytes = None, message: Union[bytes, str], sync: bool = True) -> bool: -//| """ -//| Send a message to the peer's mac address. Optionally wait for a response. -//| If peer_addr == None or any non-true value, send to all registered peers. -//| If sync == True, wait for response after sending. -//| If size is provided it should be the number of bytes in message to send(). +//| def send( +//| self, +//| message: Union[bytearray, bytes, str], +//| mac: Optional[bytes], +//| sync: bool = True, +//| ) -> bool: +//| """Send a message to the peer's mac address. Optionally wait for a response. //| -//| Returns: -//| True if sync == False and message sent successfully. -//| True if sync == True and message is received successfully by all recipients -//| False if sync == True and message is not received by at least one recipient +//| :param Union[bytearray, bytes, str] message: The message to send (length < 250 bytes). +//| :param bytes mac: The peer's address (length = 6 bytes). If `None` or any non-true value, send to all registered peers. +//| :param bool sync: If `True`, wait for response from peer(s) after sending. //| -//| Raises: EAGAIN if the internal espnow buffers are full. -//| """ -//| ... +//| :returns: +//| `True` if sync == `False` and message sent successfully. +//| `True` if sync == `True` and message is received successfully by all recipients +//| `False` if sync == `True` and message is not received by at least one recipient //| -STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) { - espnow_obj_t *self = args[0]; +//| :raises EAGAIN: if the internal espnow buffers are full.""" +//| ... +STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_message, ARG_mac, ARG_sync }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_message, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_mac, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_sync, MP_ARG_BOOL, { .u_bool = mp_const_true } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + espnow_obj_t *self = pos_args[0]; check_for_deinit(self); - // Check the various combinations of input arguments - const uint8_t *peer = (n_args > 2) ? _get_peer(args[1]) : NULL; - mp_obj_t msg = (n_args > 2) ? args[2] : (n_args == 2) ? args[1] : MP_OBJ_NULL; - bool sync = n_args <= 3 || args[3] == mp_const_none || mp_obj_is_true(args[3]); - - // Get a pointer to the data buffer of the message - mp_buffer_info_t message; - mp_get_buffer_raise(msg, &message, MP_BUFFER_READ); + const bool sync = mp_obj_is_true(args[ARG_sync].u_obj); if (sync) { // Flush out any pending responses. - // If the last call was sync==False there may be outstanding responses - // still to be received (possible many if we just had a burst of - // unsync send()s). We need to wait for all pending responses if this - // call has sync=True. + // If the last call was sync == False there may be outstanding responses + // still to be received (possible many if we just had a burst of unsync send()s). + // We need to wait for all pending responses if this call has sync = True. _wait_for_pending_responses(self); } - size_t saved_failures = self->tx_failures; + const uint8_t *peer_addr = _get_peer_addr(args[ARG_mac].u_obj); + + // Get a pointer to the data buffer of the message + mp_buffer_info_t message; + mp_get_buffer_raise(args[ARG_message].u_obj, &message, MP_BUFFER_READ); + // Send the packet - try, try again if internal esp-now buffers are full. esp_err_t err; - int64_t start = mp_hal_ticks_ms(); - while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(peer, message.buf, message.len))) && + size_t saved_failures = self->tx_failures; + mp_uint_t start = mp_hal_ticks_ms(); + + while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(peer_addr, message.buf, message.len))) && (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { RUN_BACKGROUND_TASKS; } - check_esp_err(err); // Will raise OSError if e != ESP_OK + check_esp_err(err); + + // Increment the sent packet count. + // If peer_addr == NULL msg will be sent to all peers EXCEPT any broadcast or multicast addresses. + self->tx_packets += ((peer_addr == NULL) ? self->peers_count : 1); - // Increment the sent packet count. If peer_addr==NULL msg will be - // sent to all peers EXCEPT any broadcast or multicast addresses. - self->tx_packets += ((peer == NULL) ? self->num_peers : 1); if (sync) { // Wait for and tally all the expected responses from peers _wait_for_pending_responses(self); @@ -513,30 +496,25 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) { // Return False if sync and any peers did not respond. return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_send_obj, 2, 4, espnow_send); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); -//| def recv(buffers: List[bytearray(6), bytearray(250), ...], timeout: int) -> Optional[int]: -//| """ -//| Waits for an espnow message and copies the peer_addr and message into the buffers list. +//| def recv(self, buffers: List[bytearray]) -> int: +//| """Loads mac, message, rssi and timestamp into the provided buffers. //| -//| If buffers is 2 elements long, the peer_mac and message will be +//| If buffers is 2 elements long, the mac and message will be //| loaded into the 1st and 2nd elements. //| If buffers is 4 elements long, the rssi and timestamp values will be //| loaded into the 3rd and 4th elements. //| -//| Default timeout is set with ESPNow.config(timeout=milliseconds). -//| Returns None on timeout otherwise length of the message. -//| """ -//| ... +//| :param List[bytearray] buffers: List of buffers to be loaded. //| -STATIC mp_obj_t espnow_recv(size_t n_args, const mp_obj_t *args) { - espnow_obj_t *self = args[0]; +//| :returns: Length of the message.""" +//| ... +STATIC mp_obj_t espnow_recv(mp_obj_t self_in, mp_obj_t buffers) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - size_t timeout_ms = ((n_args > 2 && args[2] != mp_const_none) - ? (size_t)mp_obj_get_int(args[2]) : self->recv_timeout_ms); - - mp_obj_list_t *list = MP_OBJ_TO_PTR(args[1]); + mp_obj_list_t *list = MP_OBJ_TO_PTR(buffers); if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) { mp_arg_error_invalid(MP_QSTR_buffers); } @@ -547,21 +525,22 @@ STATIC mp_obj_t espnow_recv(size_t n_args, const mp_obj_t *args) { msg->free = 0; } - uint8_t peer_buf[ESP_NOW_ETH_ALEN]; - uint8_t *msg_buf = _get_bytes_len_w(msg, ESP_NOW_MAX_DATA_LEN); + uint8_t *peer_buf = _get_bytes_len(list->items[0], ESP_NOW_ETH_ALEN, MP_BUFFER_WRITE); + uint8_t *msg_buf = _get_bytes_len(msg, ESP_NOW_MAX_DATA_LEN, MP_BUFFER_WRITE); // Read the packet header from the incoming buffer - espnow_hdr_t hdr; - if (ringbuf_read_wait(self->recv_buffer, &hdr, sizeof(hdr), timeout_ms) < 1) { - return MP_OBJ_NEW_SMALL_INT(0); // Timeout waiting for packet + espnow_header_t header; + if (!ringbuf_get_n(self->recv_buffer, (uint8_t *)&header, sizeof(header))) { + return MP_OBJ_NEW_SMALL_INT(0); } - int msg_len = hdr.msg_len; + + uint8_t msg_len = header.msg_len; // Check the message packet header format and read the message data - if (hdr.magic != ESPNOW_MAGIC || + if (header.magic != ESPNOW_MAGIC || msg_len > ESP_NOW_MAX_DATA_LEN || - ringbuf_read(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) < 1 || - ringbuf_read(self->recv_buffer, msg_buf, msg_len) < 1) { + !ringbuf_get_n(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) || + !ringbuf_get_n(self->recv_buffer, msg_buf, msg_len)) { mp_arg_error_invalid(MP_QSTR_buffer); } if (mp_obj_is_type(msg, &mp_type_bytearray)) { @@ -572,79 +551,87 @@ STATIC mp_obj_t espnow_recv(size_t n_args, const mp_obj_t *args) { } // Update rssi value in the peer device table - mp_map_elem_t *entry = _update_rssi(self, peer_buf, hdr.rssi, hdr.time_ms); - list->items[0] = entry->key; // Set first element of list to peer - if (list->len >= 4) { - list->items[2] = MP_OBJ_NEW_SMALL_INT(hdr.rssi); - list->items[3] = mp_obj_new_int(hdr.time_ms); + _update_rssi(self, peer_buf, header.rssi, header.time_ms); + if (list->len == 4) { + list->items[2] = MP_OBJ_NEW_SMALL_INT(header.rssi); + list->items[3] = mp_obj_new_int(header.time_ms); } return MP_OBJ_NEW_SMALL_INT(msg_len); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_recv_obj, 2, 3, espnow_recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_recv_obj, espnow_recv); -//| def any(self) -> bool: -//| """Test if data is available to read from the buffers. -//| """ -//| ... +//| any: bool +//| """`True` if data is available to read from the buffers.""" //| -STATIC mp_obj_t espnow_any(const mp_obj_t self_in) { +STATIC mp_obj_t espnow_get_any(const mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - return ringbuf_avail(self->recv_buffer) ? mp_const_true : mp_const_false; + + return ringbuf_num_filled(self->recv_buffer) ? mp_const_true : mp_const_false; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_any_obj, espnow_any); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_any_obj, espnow_get_any); + +MP_PROPERTY_GETTER(espnow_any_obj, + (mp_obj_t)&espnow_get_any_obj); // --- Peer Management Functions --- -//| def set_pmk(pmk: bytes(16)) -> None: -//| """Set the ESP-NOW Primary Master Key (pmk) (for encrypted communications). -//| """ -//| ... -//| -STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { - check_esp_err(esp_now_set_pmk(_get_bytes_len(key, ESP_NOW_KEY_LEN))); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); - -// Common code for add_peer() and mod_peer() to process the args and kw_args. -static void _update_peer_info(esp_now_peer_info_t *peer, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_lmk, ARG_channel, ARG_ifidx, ARG_encrypt }; +// Common code for add_peer() and mod_peer() to process the args. +static void _update_peer_info(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool modify) { + enum { ARG_mac, ARG_lmk, ARG_channel, ARG_interface, ARG_encrypt }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_lmk, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_channel, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_ifidx, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_encrypt, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mac, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_lmk, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_channel, MP_ARG_INT, { .u_obj = mp_const_none } }, + { MP_QSTR_interface,MP_ARG_INT, { .u_obj = mp_const_none } }, + { MP_QSTR_encrypt, MP_ARG_BOOL,{ .u_obj = mp_const_none } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if (args[ARG_lmk].u_obj != mp_const_none) { - mp_obj_t obj = args[ARG_lmk].u_obj; - peer->encrypt = mp_obj_is_true(obj); - if (peer->encrypt) { - // Key must be 16 bytes in length. - memcpy(peer->lmk, _get_bytes_len(obj, ESP_NOW_KEY_LEN), ESP_NOW_KEY_LEN); + esp_now_peer_info_t peer = {0}; + memcpy(peer.peer_addr, _get_peer_addr(args[ARG_mac].u_obj), ESP_NOW_ETH_ALEN); + + if (modify) { + check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); + } else { + if (esp_now_is_peer_exist(peer.peer_addr)) { + mp_raise_RuntimeError(translate("peer already exists")); } + peer.channel = 0; + peer.ifidx = WIFI_IF_STA; + peer.encrypt = false; } - if (args[ARG_channel].u_obj != mp_const_none) { - peer->channel = mp_obj_get_int(args[ARG_channel].u_obj); + const mp_obj_t channel = args[ARG_channel].u_obj; + if (channel != mp_const_none) { + peer.channel = mp_arg_validate_int_range(mp_obj_get_int(channel), 1, 14, MP_QSTR_channel); } - if (args[ARG_ifidx].u_obj != mp_const_none) { - peer->ifidx = mp_obj_get_int(args[ARG_ifidx].u_obj); + const mp_obj_t interface = args[ARG_interface].u_obj; + if (interface != mp_const_none) { + peer.ifidx = (wifi_interface_t)mp_arg_validate_int_range(mp_obj_get_int(interface), 0, 1, MP_QSTR_interface); } - if (args[ARG_encrypt].u_obj != mp_const_none) { - peer->encrypt = mp_obj_is_true(args[ARG_encrypt].u_obj); + const mp_obj_t encrypt = args[ARG_encrypt].u_obj; + if (encrypt != mp_const_none) { + peer.encrypt = mp_obj_is_true(encrypt); } + + const mp_obj_t lmk = args[ARG_lmk].u_obj; + if (lmk != mp_const_none) { + memcpy(peer.lmk, _get_bytes_len(lmk, ESP_NOW_KEY_LEN, MP_BUFFER_READ), ESP_NOW_KEY_LEN); + } else if (peer.encrypt) { + mp_raise_ValueError_varg(translate("%q is %q"), MP_QSTR_lmk, MP_QSTR_None); + } + + check_esp_err((modify) ? esp_now_mod_peer(&peer) : esp_now_add_peer(&peer)); } -// Update the cached peer count in self->num_peers; -// The num_peers ignores broadcast and multicast addresses and is used for the +// Update the cached peer count in self->peers_count; +// The peers_count ignores broadcast and multicast addresses and is used for the // send() logic and is updated from add_peer(), mod_peer() and del_peer(). static void _update_peer_count(espnow_obj_t *self) { esp_now_peer_info_t peer = {0}; @@ -659,71 +646,73 @@ static void _update_peer_count(espnow_obj_t *self) { } } - self->num_peers = count; + self->peers_count = count; } -// ESPNow.add_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) - -//| def add_peer(self, peer_mac: bytes(6), lmk: bytes, channel: int, ifidx: int, encrypt: bool) -> None: -//| """ -//| Positional args set to None will be left at defaults. -//| Raise ValueError if mac or LMK are not bytes-like objects or wrong length. -//| Raise TypeError if invalid keyword args or too many positional args. -//| """ -//| ... +//| def add_peer( +//| self, +//| mac: bytes, +//| lmk: Optional[bytes], +//| channel: int = 0, +//| interface: int = 0, +//| encrypt: bool = False, +//| ) -> None: +//| """Add peer. //| -STATIC mp_obj_t espnow_add_peer(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - espnow_obj_t *self = args[0]; +//| :param bytes mac: The mac address of the peer. +//| :param bytes lmk: The Local Master Key (lmk) of the peer. +//| :param int channel: The peer's channel. Default: 0 ie. use the current channel. +//| :param int interface: The WiFi interface to use. Default: 0 ie. STA. +//| :param bool encrypt: Whether or not to use encryption.""" +//| ... +STATIC mp_obj_t espnow_add_peer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + espnow_obj_t *self = pos_args[0]; check_for_deinit(self); - esp_now_peer_info_t peer = {0}; - memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN); - - _update_peer_info(&peer, n_args - 2, args + 2, kw_args); - check_esp_err(esp_now_add_peer(&peer)); + _update_peer_info(n_args, pos_args, kw_args, false); _update_peer_count(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_add_peer_obj, 2, espnow_add_peer); -// ESPNow.mod_peer(self, peer_mac, [lmk=b'0123456789abcdef'|b''|None|False], [channel=1..11|0], [ifidx=0|1], [encrypt=True|False]) - -//| def mod_peer(self, peer_mac: bytes(6), lmk: bytes, channel: int, ifidx: int, encrypt: bool) -> None: -//| """ -//| Positional args set to None will be left at current values. -//| Raise ValueError if mac or LMK are not bytes-like objects or wrong length. -//| Raise TypeError if invalid keyword args or too many positional args. -//| """ -//| ... +//| def mod_peer( +//| self, +//| mac: bytes, +//| lmk: Optional[bytes], +//| channel: int = 0, +//| interface: int = 0, +//| encrypt: bool = False, +//| ) -> None: +//| """Modify peer. //| -STATIC mp_obj_t espnow_mod_peer(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - espnow_obj_t *self = args[0]; +//| :param bytes mac: The mac address of the peer. +//| :param bytes lmk: The Local Master Key (lmk) of the peer. +//| :param int channel: The peer's channel. Default: 0 ie. use the current channel. +//| :param int interface: The WiFi interface to use. Default: 0 ie. STA. +//| :param bool encrypt: Whether or not to use encryption.""" +//| ... +STATIC mp_obj_t espnow_mod_peer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + espnow_obj_t *self = pos_args[0]; check_for_deinit(self); - esp_now_peer_info_t peer = {0}; - memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN); - check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); - - _update_peer_info(&peer, n_args - 2, args + 2, kw_args); - check_esp_err(esp_now_mod_peer(&peer)); - _update_peer_count(self); + _update_peer_info(n_args, pos_args, kw_args, true); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_mod_peer_obj, 2, espnow_mod_peer); -//| def del_peer(peer_mac: bytes(6)) -> None: -//| """Un-register peer_mac. -//| """ -//| ... +//| def del_peer(self, mac: bytes) -> None: +//| """Delete peer. //| -STATIC mp_obj_t espnow_del_peer(mp_obj_t self_in, mp_obj_t peer) { +//| :param bytes mac: The mac address of the peer.""" +//| ... +STATIC mp_obj_t espnow_del_peer(mp_obj_t self_in, mp_obj_t mac) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); uint8_t peer_addr[ESP_NOW_ETH_ALEN]; - memcpy(peer_addr, _get_peer(peer), ESP_NOW_ETH_ALEN); + memcpy(peer_addr, _get_peer_addr(mac), ESP_NOW_ETH_ALEN); check_esp_err(esp_now_del_peer(peer_addr)); _update_peer_count(self); @@ -735,43 +724,46 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_del_peer_obj, espnow_del_peer); // Convert a peer_info struct to python tuple // Used by espnow_get_peer() and espnow_get_peers() static mp_obj_t _peer_info_to_tuple(const esp_now_peer_info_t *peer) { - return NEW_TUPLE( + return MP_OBJ_NEW_TUPLE( mp_obj_new_bytes(peer->peer_addr, MP_ARRAY_SIZE(peer->peer_addr)), mp_obj_new_bytes(peer->lmk, MP_ARRAY_SIZE(peer->lmk)), mp_obj_new_int(peer->channel), mp_obj_new_int(peer->ifidx), - (peer->encrypt) ? mp_const_true : mp_const_false); + mp_obj_new_bool(peer->encrypt)); } -//| def get_peer(self, peer_mac: bytes(6)) -> Tuple[bytes, int, int, bool]: -//| """ -//| Get the peer info for peer_mac as a tuple. -//| Raise ValueError if mac or LMK are not bytes-like objects or wrong length. -//| Returns a tuple of (peer_addr, lmk, channel, ifidx, encrypt). -//| """ -//| ... +//| def get_peer(self, mac: bytes) -> Tuple[bytes, int, int, bool]: +//| """Get the peer info for mac as a `tuple`. //| -STATIC mp_obj_t espnow_get_peer(mp_obj_t self_in, mp_obj_t peer_mac) { +//| :param bytes mac: The mac address of the peer. +//| +//| :returns: A `tuple` of (mac, lmk, channel, interface, encrypt).""" +//| ... +STATIC mp_obj_t espnow_get_peer(mp_obj_t self_in, mp_obj_t mac) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + esp_now_peer_info_t peer = {0}; - memcpy(peer.peer_addr, _get_peer(peer_mac), ESP_NOW_ETH_ALEN); + memcpy(peer.peer_addr, _get_peer_addr(mac), ESP_NOW_ETH_ALEN); check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); + return _peer_info_to_tuple(&peer); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_get_peer_obj, espnow_get_peer); -//| def get_peers(self) -> Tuple[Tuple[bytes, bytes, int, int, bool], ...]: -//| """ -//| Fetch peer_info records for all registered ESPNow peers. -//| Returns a tuple of tuples: ((peer_addr, lmk, channel, ifidx, encrypt), ...) -//| """ -//| ... +// --- Peer Related Properties --- + +//| peers: Tuple[Tuple[bytes, bytes, int, int, bool], ...] +//| """The peer info records for all registered `ESPNow` peers. (read-only) +//| +//| A `tuple` of tuples: ((mac, lmk, channel, interface, encrypt), ...).""" //| STATIC mp_obj_t espnow_get_peers(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - // Build and initialise the peer info tuple. - mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->num_peers, NULL); + // Build and initialize the peer info tuple. + mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->peers_count, NULL); esp_now_peer_info_t peer = {0}; for (size_t i = 0; i < peerinfo_tuple->len; i++) { @@ -783,25 +775,52 @@ STATIC mp_obj_t espnow_get_peers(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_obj, espnow_get_peers); -//| num_peers: Tuple[int, int] -//| """The number of registered peers in a tuple of (num_total_peers, num_encrypted_peers). (read-only) -//| """ +MP_PROPERTY_GETTER(espnow_peers_obj, + (mp_obj_t)&espnow_get_peers_obj); + +//| peers_count: Tuple[int, int] +//| """The number of registered peers in a `tuple` of (num_total_peers, num_encrypted_peers). (read-only)""" //| -STATIC mp_obj_t espnow_get_num_peers(mp_obj_t self_in) { +STATIC mp_obj_t espnow_get_peers_count(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + esp_now_peer_num_t peer_num = {0}; check_esp_err(esp_now_get_peer_num(&peer_num)); - return NEW_TUPLE( + return MP_OBJ_NEW_TUPLE( mp_obj_new_int(peer_num.total_num), mp_obj_new_int(peer_num.encrypt_num)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_num_peers_obj, espnow_get_num_peers); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_count_obj, espnow_get_peers_count); -MP_PROPERTY_GETTER(espnow_num_peers_obj, - (mp_obj_t)&espnow_get_num_peers_obj); +MP_PROPERTY_GETTER(espnow_peers_count_obj, + (mp_obj_t)&espnow_get_peers_count_obj); + +//| peers_table: Dict[bytes, List[int]] +//| """The dictionary of peers we have seen. (read-only) +//| +//| A `dict` of {peer: [rssi, time], ...} +//| +//| where: +//| peer is a byte string containing the 6-byte mac address of the peer. +//| rssi is the wifi signal strength from the last msg received (in dBm from -127 to 0). +//| time is the time in milliseconds since device last booted.""" +//| +STATIC mp_obj_t espnow_get_peers_table(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->peers_table; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_table_obj, espnow_get_peers_table); + +MP_PROPERTY_GETTER(espnow_peers_table_obj, + (mp_obj_t)&espnow_get_peers_table_obj); STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { + // Config parameters + { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) }, { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&espnow_active_obj) }, - { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&espnow_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_buffer_size), MP_ROM_PTR(&espnow_buffer_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_phy_rate), MP_ROM_PTR(&espnow_phy_rate_obj) }, { MP_ROM_QSTR(MP_QSTR_stats), MP_ROM_PTR(&espnow_stats_obj) }, // Send and receive messages @@ -810,13 +829,15 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&espnow_any_obj) }, // Peer management functions - { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) }, { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) }, { MP_ROM_QSTR(MP_QSTR_mod_peer), MP_ROM_PTR(&espnow_mod_peer_obj) }, { MP_ROM_QSTR(MP_QSTR_del_peer), MP_ROM_PTR(&espnow_del_peer_obj) }, { MP_ROM_QSTR(MP_QSTR_get_peer), MP_ROM_PTR(&espnow_get_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_peers), MP_ROM_PTR(&espnow_get_peers_obj) }, - { MP_ROM_QSTR(MP_QSTR_num_peers), MP_ROM_PTR(&espnow_num_peers_obj) }, + + // Peer related properties + { MP_ROM_QSTR(MP_QSTR_peers), MP_ROM_PTR(&espnow_peers_obj) }, + { MP_ROM_QSTR(MP_QSTR_peers_count), MP_ROM_PTR(&espnow_peers_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_peers_table), MP_ROM_PTR(&espnow_peers_table_obj) }, }; STATIC MP_DEFINE_CONST_DICT(espnow_locals_dict, espnow_locals_dict_table); @@ -831,10 +852,10 @@ STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt } espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return (espnow_deinited(self)) ? 0 : // If not initialised + return (espnow_deinited(self)) ? 0 : // If not initialized arg ^ ( // If no data in the buffer, unset the Read ready flag - ((ringbuf_avail(self->recv_buffer) == 0) ? MP_STREAM_POLL_RD : 0) | + ((!ringbuf_num_filled(self->recv_buffer)) ? MP_STREAM_POLL_RD : 0) | // If still waiting for responses, unset the Write ready flag ((self->tx_responses < self->tx_packets) ? MP_STREAM_POLL_WR : 0)); } @@ -843,30 +864,11 @@ STATIC const mp_stream_p_t espnow_stream_p = { .ioctl = espnow_stream_ioctl, }; -// Return reference to the dictionary of peers we have seen: -// {peer1: (rssi, time), peer2: (rssi, time), ...} -// where: -// peerX is a byte string containing the 6-byte mac address of the peer, -// rssi is the wifi signal strength from the last msg received (in dBm from -127 to 0) -// time is the time in milliseconds since device last booted. -STATIC void espnow_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (dest[0] != MP_OBJ_NULL) { // Only allow "Load" operation - return; - } - if (attr == MP_QSTR_peers_table) { - dest[0] = self->peers_table; - return; - } - dest[1] = MP_OBJ_SENTINEL; // Attribute not found -} - const mp_obj_type_t espnow_type = { { &mp_type_type }, - .name = MP_QSTR_NOW, + .name = MP_QSTR_ESPNow, .make_new = espnow_make_new, .locals_dict = (mp_obj_t)&espnow_locals_dict, - .attr = espnow_attr, .flags = MP_TYPE_FLAG_EXTENDED, MP_TYPE_EXTENDED_FIELDS( .protocol = &espnow_stream_p, diff --git a/ports/espressif/bindings/espnow/Now.h b/ports/espressif/bindings/espnow/ESPNow.h similarity index 100% rename from ports/espressif/bindings/espnow/Now.h rename to ports/espressif/bindings/espnow/ESPNow.h diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c index 52325dad58..5661885911 100644 --- a/ports/espressif/bindings/espnow/__init__.c +++ b/ports/espressif/bindings/espnow/__init__.c @@ -27,7 +27,7 @@ #include "shared-bindings/util.h" #include "bindings/espnow/__init__.h" -#include "bindings/espnow/Now.h" +#include "bindings/espnow/ESPNow.h" //| """ESP-NOW Module //| @@ -36,7 +36,9 @@ //| protocol provided by Espressif on its SoCs //| (`API docs `_). //| -//| **Sender:** :: +//| **Sender** +//| +//| .. code-block:: python //| //| import espnow //| @@ -50,7 +52,9 @@ //| e.send(peer, str(i)*20, True) //| e.send(b'end') //| -//| **Receiver:** :: +//| **Receiver** +//| +//| .. code-block:: python //| //| import espnow //| @@ -73,7 +77,7 @@ STATIC const mp_rom_map_elem_t espnow_module_globals_table[] = { // module name { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espnow) }, // module classes - { MP_ROM_QSTR(MP_QSTR_Now), MP_ROM_PTR(&espnow_type) }, + { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&espnow_type) }, }; STATIC MP_DEFINE_CONST_DICT(espnow_module_globals, espnow_module_globals_table); diff --git a/py/objtuple.h b/py/objtuple.h index 7bfb447fa4..ded265b47e 100644 --- a/py/objtuple.h +++ b/py/objtuple.h @@ -50,6 +50,9 @@ mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf); extern const mp_obj_type_t mp_type_attrtuple; +// Relies on gcc Variadic Macros and Statement Expressions +#define MP_OBJ_NEW_TUPLE(...) ({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z);}) + #define MP_DEFINE_ATTRTUPLE(tuple_obj_name, fields, nitems, ...) \ const mp_rom_obj_tuple_t tuple_obj_name = { \ .base = {&mp_type_attrtuple}, \ diff --git a/py/ringbuf.c b/py/ringbuf.c index f90805d6f3..5936b64230 100644 --- a/py/ringbuf.c +++ b/py/ringbuf.c @@ -72,7 +72,6 @@ int ringbuf_get16(ringbuf_t *r) { if (r->used < 2) { return -1; } - int high_byte = ringbuf_get(r); int low_byte = ringbuf_get(r); return (high_byte << 8) | low_byte; @@ -92,6 +91,15 @@ int ringbuf_put(ringbuf_t *r, uint8_t v) { return 0; } +int ringbuf_put16(ringbuf_t *r, uint16_t v) { + if (r->size - r->used < 2) { + return -1; + } + ringbuf_put(r, (v >> 8) & 0xff); + ringbuf_put(r, v & 0xff); + return 0; +} + void ringbuf_clear(ringbuf_t *r) { r->next_write = 0; r->next_read = 0; @@ -132,57 +140,3 @@ size_t ringbuf_get_n(ringbuf_t *r, uint8_t *buf, size_t bufsize) { } return bufsize; } - -int ringbuf_put16(ringbuf_t *r, uint16_t v) { - if (r->size - r->used < 2) { - return -1; - } - - ringbuf_put(r, (v >> 8) & 0xff); - ringbuf_put(r, v & 0xff); - return 0; -} - -// Returns: -// 1: Success -// 0: Not enough data available to complete read (try again later) -// -1: Requested read is larger than buffer - will never succeed -int ringbuf_read(ringbuf_t *r, void *data, size_t data_len) { - if (ringbuf_avail(r) < data_len) { - return (r->size <= data_len) ? -1 : 0; - } - uint32_t iget = r->next_read; - uint32_t iget_a = (iget + data_len) % r->size; - uint8_t *datap = data; - if (iget_a < iget) { - // Copy part of the data from the space left at the end of the buffer - memcpy(datap, r->buf + iget, r->size - iget); - datap += (r->size - iget); - iget = 0; - } - memcpy(datap, r->buf + iget, iget_a - iget); - r->next_read = iget_a; - return 1; -} - -// Returns: -// 1: Success -// 0: Not enough free space available to complete write (try again later) -// -1: Requested write is larger than buffer - will never succeed -int ringbuf_write(ringbuf_t *r, const void *data, size_t data_len) { - if (ringbuf_free(r) < data_len) { - return (r->size <= data_len) ? -1 : 0; - } - uint32_t iput = r->next_write; - uint32_t iput_a = (iput + data_len) % r->size; - const uint8_t *datap = data; - if (iput_a < iput) { - // Copy part of the data to the end of the buffer - memcpy(r->buf + iput, datap, r->size - iput); - datap += (r->size - iput); - iput = 0; - } - memcpy(r->buf + iput, datap, iput_a - iput); - r->next_write = iput_a; - return 1; -} diff --git a/py/ringbuf.h b/py/ringbuf.h index 5d54abc6b5..2725bedcca 100644 --- a/py/ringbuf.h +++ b/py/ringbuf.h @@ -61,15 +61,5 @@ size_t ringbuf_get_n(ringbuf_t *r, uint8_t *buf, size_t bufsize); // Note: big-endian. Return -1 if can't read or write two bytes. int ringbuf_get16(ringbuf_t *r); int ringbuf_put16(ringbuf_t *r, uint16_t v); -int ringbuf_read(ringbuf_t *r, void *data, size_t data_len); -int ringbuf_write(ringbuf_t *r, const void *data, size_t data_len); - -static inline size_t ringbuf_free(ringbuf_t *r) { - return (r->size + r->next_read - r->next_write - 1) % r->size; -} - -static inline size_t ringbuf_avail(ringbuf_t *r) { - return (r->size + r->next_write - r->next_read) % r->size; -} #endif // MICROPY_INCLUDED_PY_RINGBUF_H From 9b98d485bb40fb316987427ab4c89b06e68d320b Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Thu, 26 Jan 2023 14:13:38 +0530 Subject: [PATCH 05/29] switch to `ReadableBuffer` and `WriteableBuffer` --- ports/espressif/bindings/espnow/ESPNow.c | 40 ++++++++++++------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 0bcd7d39ed..b67574360c 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -255,10 +255,10 @@ static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { return (uint8_t *)bufinfo.buf; } -//| def set_pmk(self, pmk: bytes) -> None: +//| def set_pmk(self, pmk: ReadableBuffer) -> None: //| """Set the ESP-NOW Primary Master Key (pmk) for encrypted communications. //| -//| :param bytes pmk: The ESP-NOW Primary Master Key (length = 16 bytes).""" +//| :param ReadableBuffer pmk: The ESP-NOW Primary Master Key (length = 16 bytes).""" //| ... STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { check_esp_err(esp_now_set_pmk(_get_bytes_len(key, ESP_NOW_KEY_LEN, MP_BUFFER_READ))); @@ -426,14 +426,14 @@ static void _wait_for_pending_responses(espnow_obj_t *self) { //| def send( //| self, -//| message: Union[bytearray, bytes, str], -//| mac: Optional[bytes], +//| message: ReadableBuffer, +//| mac: Optional[ReadableBuffer], //| sync: bool = True, //| ) -> bool: //| """Send a message to the peer's mac address. Optionally wait for a response. //| -//| :param Union[bytearray, bytes, str] message: The message to send (length < 250 bytes). -//| :param bytes mac: The peer's address (length = 6 bytes). If `None` or any non-true value, send to all registered peers. +//| :param ReadableBuffer message: The message to send (length <= 250 bytes). +//| :param ReadableBuffer mac: The peer's address (length = 6 bytes). If `None` or any non-true value, send to all registered peers. //| :param bool sync: If `True`, wait for response from peer(s) after sending. //| //| :returns: @@ -498,7 +498,7 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); -//| def recv(self, buffers: List[bytearray]) -> int: +//| def recv(self, buffers: List[WriteableBuffer]) -> int: //| """Loads mac, message, rssi and timestamp into the provided buffers. //| //| If buffers is 2 elements long, the mac and message will be @@ -506,7 +506,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); //| If buffers is 4 elements long, the rssi and timestamp values will be //| loaded into the 3rd and 4th elements. //| -//| :param List[bytearray] buffers: List of buffers to be loaded. +//| :param List[WriteableBuffer] buffers: List of buffers to be loaded. //| //| :returns: Length of the message.""" //| ... @@ -651,16 +651,16 @@ static void _update_peer_count(espnow_obj_t *self) { //| def add_peer( //| self, -//| mac: bytes, -//| lmk: Optional[bytes], +//| mac: ReadableBuffer, +//| lmk: Optional[ReadableBuffer], //| channel: int = 0, //| interface: int = 0, //| encrypt: bool = False, //| ) -> None: //| """Add peer. //| -//| :param bytes mac: The mac address of the peer. -//| :param bytes lmk: The Local Master Key (lmk) of the peer. +//| :param ReadableBuffer mac: The mac address of the peer. +//| :param ReadableBuffer lmk: The Local Master Key (lmk) of the peer. //| :param int channel: The peer's channel. Default: 0 ie. use the current channel. //| :param int interface: The WiFi interface to use. Default: 0 ie. STA. //| :param bool encrypt: Whether or not to use encryption.""" @@ -678,16 +678,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_add_peer_obj, 2, espnow_add_peer); //| def mod_peer( //| self, -//| mac: bytes, -//| lmk: Optional[bytes], +//| mac: ReadableBuffer, +//| lmk: Optional[ReadableBuffer], //| channel: int = 0, //| interface: int = 0, //| encrypt: bool = False, //| ) -> None: //| """Modify peer. //| -//| :param bytes mac: The mac address of the peer. -//| :param bytes lmk: The Local Master Key (lmk) of the peer. +//| :param ReadableBuffer mac: The mac address of the peer. +//| :param ReadableBuffer lmk: The Local Master Key (lmk) of the peer. //| :param int channel: The peer's channel. Default: 0 ie. use the current channel. //| :param int interface: The WiFi interface to use. Default: 0 ie. STA. //| :param bool encrypt: Whether or not to use encryption.""" @@ -702,10 +702,10 @@ STATIC mp_obj_t espnow_mod_peer(size_t n_args, const mp_obj_t *pos_args, mp_map_ } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_mod_peer_obj, 2, espnow_mod_peer); -//| def del_peer(self, mac: bytes) -> None: +//| def del_peer(self, mac: ReadableBuffer) -> None: //| """Delete peer. //| -//| :param bytes mac: The mac address of the peer.""" +//| :param ReadableBuffer mac: The mac address of the peer.""" //| ... STATIC mp_obj_t espnow_del_peer(mp_obj_t self_in, mp_obj_t mac) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -732,10 +732,10 @@ static mp_obj_t _peer_info_to_tuple(const esp_now_peer_info_t *peer) { mp_obj_new_bool(peer->encrypt)); } -//| def get_peer(self, mac: bytes) -> Tuple[bytes, int, int, bool]: +//| def get_peer(self, mac: ReadableBuffer) -> Tuple[bytes, int, int, bool]: //| """Get the peer info for mac as a `tuple`. //| -//| :param bytes mac: The mac address of the peer. +//| :param ReadableBuffer mac: The mac address of the peer. //| //| :returns: A `tuple` of (mac, lmk, channel, interface, encrypt).""" //| ... From 9c430d45d15ef2f3a63459d12831343e0e45677a Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Wed, 1 Feb 2023 15:27:55 +0530 Subject: [PATCH 06/29] use truthiness of the object itself instead of `any` --- ports/espressif/bindings/espnow/ESPNow.c | 37 ++++++++++++++---------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index b67574360c..d50c41c7c7 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -561,20 +561,6 @@ STATIC mp_obj_t espnow_recv(mp_obj_t self_in, mp_obj_t buffers) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_recv_obj, espnow_recv); -//| any: bool -//| """`True` if data is available to read from the buffers.""" -//| -STATIC mp_obj_t espnow_get_any(const mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - return ringbuf_num_filled(self->recv_buffer) ? mp_const_true : mp_const_false; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_any_obj, espnow_get_any); - -MP_PROPERTY_GETTER(espnow_any_obj, - (mp_obj_t)&espnow_get_any_obj); - // --- Peer Management Functions --- // Common code for add_peer() and mod_peer() to process the args. @@ -826,7 +812,6 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { // Send and receive messages { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&espnow_recv_obj) }, - { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&espnow_any_obj) }, // Peer management functions { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) }, @@ -864,6 +849,27 @@ STATIC const mp_stream_p_t espnow_stream_p = { .ioctl = espnow_stream_ioctl, }; +//| def __bool__(self) -> bool: +//| """``True`` if `len()` is greater than zero. +//| This is an easy way to check if the buffer is empty. +//| """ +//| ... +//| def __len__(self) -> int: +//| """Return the number of `bytes` available to read. Used to implement ``len()``.""" +//| ... +STATIC mp_obj_t espnow_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t len = ringbuf_num_filled(self->recv_buffer); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(len != 0); + case MP_UNARY_OP_LEN: + return mp_obj_new_int_from_uint(len); + default: + return MP_OBJ_NULL; // op not supported + } +} + const mp_obj_type_t espnow_type = { { &mp_type_type }, .name = MP_QSTR_ESPNow, @@ -872,5 +878,6 @@ const mp_obj_type_t espnow_type = { .flags = MP_TYPE_FLAG_EXTENDED, MP_TYPE_EXTENDED_FIELDS( .protocol = &espnow_stream_p, + .unary_op = &espnow_unary_op ), }; From ae4bb75e295ac6f598ccc7802d446f67691cddfe Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Wed, 1 Feb 2023 17:54:51 +0530 Subject: [PATCH 07/29] split espnow between bindings and common-hal --- locale/circuitpython.pot | 6 + ports/espressif/Makefile | 4 +- ports/espressif/bindings/espnow/ESPNow.c | 349 ++---------------- .../espressif/bindings/espnow/ESPNowPacket.c | 70 ++++ .../espressif/bindings/espnow/ESPNowPacket.h | 30 ++ ports/espressif/bindings/espnow/__init__.c | 7 +- ports/espressif/common-hal/espnow/ESPNow.c | 327 ++++++++++++++++ ports/espressif/common-hal/espnow/ESPNow.h | 57 +++ 8 files changed, 539 insertions(+), 311 deletions(-) create mode 100644 ports/espressif/bindings/espnow/ESPNowPacket.c create mode 100644 ports/espressif/bindings/espnow/ESPNowPacket.h create mode 100644 ports/espressif/common-hal/espnow/ESPNow.c create mode 100644 ports/espressif/common-hal/espnow/ESPNow.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index cca9e1b067..1b44383086 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -491,6 +491,7 @@ msgstr "" msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -2431,6 +2432,7 @@ msgid "addresses is empty" msgstr "" #: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espnow/ESPNow.c msgid "an error occured" msgstr "" @@ -3818,6 +3820,10 @@ msgstr "" msgid "peer already exists" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +msgid "peer not found" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c msgid "pixel coordinates out of bounds" msgstr "" diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 92e91e808a..76d443dd68 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -260,7 +260,9 @@ CFLAGS += -isystem esp32-camera/conversions/include endif ifneq ($(CIRCUITPY_ESPNOW),0) -SRC_ESPNOW := $(wildcard bindings/espnow/*.c) +SRC_ESPNOW := \ + $(wildcard common-hal/espnow/*.c) \ + $(wildcard bindings/espnow/*.c) SRC_C += $(SRC_ESPNOW) endif diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index d50c41c7c7..b120b2cdff 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -41,57 +41,8 @@ #include "bindings/espnow/ESPNow.h" #include "shared-bindings/util.h" -#include "shared-bindings/wifi/__init__.h" -#define ESPNOW_MAGIC 0x99 - -// The maximum length of an espnow packet (bytes) -#define MAX_PACKET_LEN (sizeof(espnow_packet_t) + ESP_NOW_MAX_DATA_LEN) - -// Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes -// Will allocate an additional 7 bytes for buffer overhead -#define DEFAULT_RECV_BUFFER_SIZE (2 * MAX_PACKET_LEN) - -// Default timeout (millisec) to wait for incoming ESPNow messages (5 minutes). -#define DEFAULT_RECV_TIMEOUT_MS (5 * 60 * 1000) - -// Time to wait (millisec) for responses from sent packets: (2 seconds). -#define DEFAULT_SEND_TIMEOUT_MS (2 * 1000) - -// Number of milliseconds to wait for pending responses to sent packets. -// This is a fallback which should never be reached. -#define PENDING_RESPONSES_TIMEOUT_MS 100 -#define PENDING_RESPONSES_BUSY_POLL_MS 10 - -// ESPNow packet format for the receive buffer. -// Use this for peeking at the header of the next packet in the buffer. -typedef struct { - uint8_t magic; // = ESPNOW_MAGIC - uint8_t msg_len; // Length of the message - uint32_t time_ms; // Timestamp (ms) when packet is received - int8_t rssi; // RSSI value (dBm) (-127 to 0) -} __attribute__((packed)) espnow_header_t; - -typedef struct { - espnow_header_t header; // The header - uint8_t peer[6]; // Peer address - uint8_t msg[0]; // Message is up to 250 bytes -} __attribute__((packed)) espnow_packet_t; - -// The data structure for the espnow_singleton. -typedef struct _espnow_obj_t { - mp_obj_base_t base; - ringbuf_t *recv_buffer; // A buffer for received packets - size_t recv_buffer_size; // The size of the recv_buffer - wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. - volatile size_t rx_packets; // # of received packets - volatile size_t rx_failures; // # of dropped packets (buffer full) - size_t tx_packets; // # of sent packets - volatile size_t tx_responses; // # of sent packet responses received - volatile size_t tx_failures; // # of sent packet responses failed - size_t peers_count; // Cache the # of peers for send(sync=True) - mp_obj_t peers_table; // A dictionary of discovered peers -} espnow_obj_t; +#include "common-hal/espnow/ESPNow.h" static void check_esp_err(esp_err_t status) { if (status != ESP_OK) { @@ -101,154 +52,59 @@ static void check_esp_err(esp_err_t status) { // --- Initialisation and Config functions --- -// Return a pointer to the ESPNow module singleton -static espnow_obj_t *_get_singleton(void) { - return MP_STATE_PORT(espnow_singleton); -} - -static bool espnow_deinited(espnow_obj_t *self) { - return self->recv_buffer == NULL; -} - static void check_for_deinit(espnow_obj_t *self) { - if (espnow_deinited(self)) { + if (common_hal_espnow_deinited(self)) { raise_deinited_error(); } } -static void _set_buffer_size(espnow_obj_t *self, mp_int_t value) { - self->recv_buffer_size = mp_arg_validate_int_min(value, MAX_PACKET_LEN, MP_QSTR_buffer_size); -}; - -static void _set_phy_rate(espnow_obj_t *self, mp_int_t value) { - self->phy_rate = mp_arg_validate_int_range(value, 0, WIFI_PHY_RATE_MAX - 1, MP_QSTR_phy_rate); -}; - //| class ESPNow: //| """Provides access to the ESP-NOW protocol.""" //| //| def __init__(self, buffer_size: Optional[int], phy_rate: Optional[int]) -> None: //| """Allocate and initialize `ESPNow` instance as a singleton. //| -//| :param int buffer_size: The size of the internal ring buffer (length > 263 bytes). Default: 526 bytes. -//| :param int phy_rate: The ESP-NOW physical layer rate. Default 1 Mbps.""" +//| :param int buffer_size: The size of the internal ring buffer. Default: 526 bytes. +//| :param int phy_rate: The ESP-NOW physical layer rate. Default: 1 Mbps.""" //| ... STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_buffer_size, ARG_phy_rate }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer_size, MP_ARG_INT, { .u_int = DEFAULT_RECV_BUFFER_SIZE } }, + { MP_QSTR_buffer_size, MP_ARG_INT, { .u_int = 526 } }, { MP_QSTR_phy_rate, MP_ARG_INT, { .u_int = WIFI_PHY_RATE_1M_L } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - espnow_obj_t *self = _get_singleton(); + espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); - if (self == NULL) { - self = m_new_obj(espnow_obj_t); - self->base.type = &espnow_type; - - _set_buffer_size(self, args[ARG_buffer_size].u_int); - _set_phy_rate(self, args[ARG_phy_rate].u_int); - - self->peers_table = mp_obj_new_dict(0); - - // Prevent user code modifying the dict - mp_obj_dict_get_map(self->peers_table)->is_fixed = 1; - - // Set the global singleton pointer for the espnow protocol. - MP_STATE_PORT(espnow_singleton) = self; + if (self != NULL) { + mp_raise_RuntimeError(translate("Already running")); } + self = m_new_obj(espnow_obj_t); + self->base.type = &espnow_type; + + common_hal_espnow_set_buffer_size(self, args[ARG_buffer_size].u_int); + common_hal_espnow_set_phy_rate(self, args[ARG_phy_rate].u_int); + + self->peers_table = mp_obj_new_dict(0); + + // Prevent user code modifying the dict + mp_obj_dict_get_map(self->peers_table)->is_fixed = 1; + + // Set the global singleton pointer for the espnow protocol. + MP_STATE_PORT(espnow_singleton) = self; + + common_hal_espnow_init(self); + return self; } -// --- The ESP-NOW send and recv callback routines --- - -// Callback triggered when a sent packet is acknowledged by the peer (or not). -// Just count the number of responses and number of failures. -// These are used in the send() logic. -static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { - espnow_obj_t *self = _get_singleton(); - self->tx_responses++; - if (status != ESP_NOW_SEND_SUCCESS) { - self->tx_failures++; - } -} - -static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg); - -// Callback triggered when an ESP-NOW packet is received. -// Write the peer MAC address and the message into the recv_buffer as an ESPNow packet. -// If the buffer is full, drop the message and increment the dropped count. -static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { - espnow_obj_t *self = _get_singleton(); - ringbuf_t *buf = self->recv_buffer; - - if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { - self->rx_failures++; - return; - } - - espnow_header_t header; - header.magic = ESPNOW_MAGIC; - header.msg_len = msg_len; - header.rssi = _get_rssi_from_wifi_packet(msg); - header.time_ms = mp_hal_ticks_ms(); - - ringbuf_put_n(buf, (uint8_t *)&header, sizeof(header)); - ringbuf_put_n(buf, mac, ESP_NOW_ETH_ALEN); - ringbuf_put_n(buf, msg, msg_len); - - self->rx_packets++; -} - -// Initialize the ESP-NOW software stack, -// register callbacks and allocate the recv data buffers. -static void espnow_init(espnow_obj_t *self) { - if (espnow_deinited(self)) { - self->recv_buffer = m_new_obj(ringbuf_t); - if (!ringbuf_alloc(self->recv_buffer, self->recv_buffer_size, true)) { - m_malloc_fail(self->recv_buffer_size); - } - - if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { - common_hal_wifi_init(false); - common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); - } - - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, self->phy_rate)); - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, self->phy_rate)); - - check_esp_err(esp_now_init()); - check_esp_err(esp_now_register_send_cb(send_cb)); - check_esp_err(esp_now_register_recv_cb(recv_cb)); - } -} - -// De-initialize the ESP-NOW software stack, -// disable callbacks and deallocate the recv data buffers. -static void espnow_deinit(espnow_obj_t *self) { - if (self != NULL && !espnow_deinited(self)) { - check_esp_err(esp_now_unregister_send_cb()); - check_esp_err(esp_now_unregister_recv_cb()); - check_esp_err(esp_now_deinit()); - self->recv_buffer->buf = NULL; - self->recv_buffer = NULL; - self->peers_count = 0; // esp_now_deinit() removes all peers. - self->tx_packets = self->tx_responses; - } -} - -void espnow_reset(void) { - espnow_deinit(_get_singleton()); - MP_STATE_PORT(espnow_singleton) = NULL; -} - // Return C pointer to byte memory string/bytes/bytearray in obj. // Raise ValueError if the length does not match expected len. -static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { +static const uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(obj, &bufinfo, rw); mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); @@ -261,7 +117,8 @@ static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { //| :param ReadableBuffer pmk: The ESP-NOW Primary Master Key (length = 16 bytes).""" //| ... STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { - check_esp_err(esp_now_set_pmk(_get_bytes_len(key, ESP_NOW_KEY_LEN, MP_BUFFER_READ))); + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_set_pmk(self, _get_bytes_len(key, ESP_NOW_KEY_LEN, MP_BUFFER_READ)); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); @@ -271,13 +128,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); //| STATIC mp_obj_t espnow_get_active(const mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(!espnow_deinited(self)); + return mp_obj_new_bool(!common_hal_espnow_deinited(self)); } MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_active_obj, espnow_get_active); STATIC mp_obj_t espnow_set_active(const mp_obj_t self_in, const mp_obj_t value) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_is_true(value) ? espnow_init(self) : espnow_deinit(self); + mp_obj_is_true(value) ? common_hal_espnow_init(self) : common_hal_espnow_deinit(self); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_active_obj, espnow_set_active); @@ -298,7 +155,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_buffer_size_obj, espnow_get_buffer_size); STATIC mp_obj_t espnow_set_buffer_size(const mp_obj_t self_in, const mp_obj_t value) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - _set_buffer_size(self, mp_obj_get_int(value)); + common_hal_espnow_set_buffer_size(self, mp_obj_get_int(value)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_buffer_size_obj, espnow_set_buffer_size); @@ -318,7 +175,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_phy_rate_obj, espnow_get_phy_rate); STATIC mp_obj_t espnow_set_phy_rate(const mp_obj_t self_in, const mp_obj_t value) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - _set_phy_rate(self, mp_obj_get_int(value)); + common_hal_espnow_set_phy_rate(self, mp_obj_get_int(value)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_phy_rate_obj, espnow_set_phy_rate); @@ -368,36 +225,6 @@ static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { return wifi_packet->rx_ctrl.rssi; } -// Lookup a peer in the peers table and return a reference to the item in the peers_table. -// Add peer to the table if it is not found (may alloc memory). Will not return NULL. -static mp_map_elem_t *_lookup_add_peer(espnow_obj_t *self, const uint8_t *peer) { - // We do not want to allocate any new memory in the case that the peer - // already exists in the peers_table (which is almost all the time). - // So, we use a byte string on the stack and look that up in the dict. - mp_map_t *map = mp_obj_dict_get_map(self->peers_table); - mp_obj_str_t peer_obj = {{&mp_type_bytes}, 0, ESP_NOW_ETH_ALEN, peer}; - mp_map_elem_t *item = mp_map_lookup(map, &peer_obj, MP_MAP_LOOKUP); - if (item == NULL) { - // If not found, add the peer using a new bytestring - map->is_fixed = 0; // Allow to modify the dict - mp_obj_t new_peer = mp_obj_new_bytes(peer, ESP_NOW_ETH_ALEN); - item = mp_map_lookup(map, new_peer, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - item->value = mp_obj_new_list(2, NULL); - map->is_fixed = 1; // Relock the dict - } - return item; -} - -// Update the peers table with the new rssi value from a received packet and -// return a reference to the item in the peers_table. -static void _update_rssi(espnow_obj_t *self, const uint8_t *peer, int8_t rssi, uint32_t time_ms) { - // Lookup the peer in the device table - mp_map_elem_t *item = _lookup_add_peer(self, peer); - mp_obj_list_t *list = MP_OBJ_TO_PTR(item->value); - list->items[0] = MP_OBJ_NEW_SMALL_INT(rssi); - list->items[1] = mp_obj_new_int(time_ms); -} - // --- Handling espnow packets in the recv buffer --- // --- Send and Receive ESP-NOW data --- @@ -408,22 +235,6 @@ static const uint8_t *_get_peer_addr(mp_obj_t mac) { return mp_obj_is_true(mac) ? _get_bytes_len(mac, ESP_NOW_ETH_ALEN, MP_BUFFER_READ) : NULL; } -// Used by espnow_send() for sends() with sync==True. -// Wait till all pending sent packet responses have been received. -// ie. self->tx_responses == self->tx_packets. -static void _wait_for_pending_responses(espnow_obj_t *self) { - mp_uint_t t, start = mp_hal_ticks_ms(); - while (self->tx_responses < self->tx_packets) { - if ((t = mp_hal_ticks_ms() - start) > PENDING_RESPONSES_TIMEOUT_MS) { - mp_raise_OSError(MP_ETIMEDOUT); - } - if (t > PENDING_RESPONSES_BUSY_POLL_MS) { - // After 10ms of busy waiting give other tasks a look in. - RUN_BACKGROUND_TASKS; - } - } -} - //| def send( //| self, //| message: ReadableBuffer, @@ -458,106 +269,26 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k check_for_deinit(self); const bool sync = mp_obj_is_true(args[ARG_sync].u_obj); - - if (sync) { - // Flush out any pending responses. - // If the last call was sync == False there may be outstanding responses - // still to be received (possible many if we just had a burst of unsync send()s). - // We need to wait for all pending responses if this call has sync = True. - _wait_for_pending_responses(self); - } - const uint8_t *peer_addr = _get_peer_addr(args[ARG_mac].u_obj); // Get a pointer to the data buffer of the message mp_buffer_info_t message; mp_get_buffer_raise(args[ARG_message].u_obj, &message, MP_BUFFER_READ); - // Send the packet - try, try again if internal esp-now buffers are full. - esp_err_t err; - size_t saved_failures = self->tx_failures; - mp_uint_t start = mp_hal_ticks_ms(); - - while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(peer_addr, message.buf, message.len))) && - (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { - RUN_BACKGROUND_TASKS; - } - check_esp_err(err); - - // Increment the sent packet count. - // If peer_addr == NULL msg will be sent to all peers EXCEPT any broadcast or multicast addresses. - self->tx_packets += ((peer_addr == NULL) ? self->peers_count : 1); - - if (sync) { - // Wait for and tally all the expected responses from peers - _wait_for_pending_responses(self); - } - - // Return False if sync and any peers did not respond. - return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures)); + return common_hal_espnow_send(self, sync, peer_addr, &message); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); -//| def recv(self, buffers: List[WriteableBuffer]) -> int: -//| """Loads mac, message, rssi and timestamp into the provided buffers. +//| def recv(self) -> Optional[ESPNowPacket]: +//| """Receive a message from the peer(s). //| -//| If buffers is 2 elements long, the mac and message will be -//| loaded into the 1st and 2nd elements. -//| If buffers is 4 elements long, the rssi and timestamp values will be -//| loaded into the 3rd and 4th elements. -//| -//| :param List[WriteableBuffer] buffers: List of buffers to be loaded. -//| -//| :returns: Length of the message.""" +//| :returns: An `ESPNowPacket` if available in the buffer, otherwise `None`.""" //| ... STATIC mp_obj_t espnow_recv(mp_obj_t self_in, mp_obj_t buffers) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - mp_obj_list_t *list = MP_OBJ_TO_PTR(buffers); - if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) { - mp_arg_error_invalid(MP_QSTR_buffers); - } - - mp_obj_array_t *msg = MP_OBJ_TO_PTR(list->items[1]); - if (mp_obj_is_type(msg, &mp_type_bytearray)) { - msg->len += msg->free; // Make all the space in msg array available - msg->free = 0; - } - - uint8_t *peer_buf = _get_bytes_len(list->items[0], ESP_NOW_ETH_ALEN, MP_BUFFER_WRITE); - uint8_t *msg_buf = _get_bytes_len(msg, ESP_NOW_MAX_DATA_LEN, MP_BUFFER_WRITE); - - // Read the packet header from the incoming buffer - espnow_header_t header; - if (!ringbuf_get_n(self->recv_buffer, (uint8_t *)&header, sizeof(header))) { - return MP_OBJ_NEW_SMALL_INT(0); - } - - uint8_t msg_len = header.msg_len; - - // Check the message packet header format and read the message data - if (header.magic != ESPNOW_MAGIC || - msg_len > ESP_NOW_MAX_DATA_LEN || - !ringbuf_get_n(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) || - !ringbuf_get_n(self->recv_buffer, msg_buf, msg_len)) { - mp_arg_error_invalid(MP_QSTR_buffer); - } - if (mp_obj_is_type(msg, &mp_type_bytearray)) { - // Set the length of the message bytearray. - size_t size = msg->len + msg->free; - msg->len = msg_len; - msg->free = size - msg_len; - } - - // Update rssi value in the peer device table - _update_rssi(self, peer_buf, header.rssi, header.time_ms); - if (list->len == 4) { - list->items[2] = MP_OBJ_NEW_SMALL_INT(header.rssi); - list->items[3] = mp_obj_new_int(header.time_ms); - } - - return MP_OBJ_NEW_SMALL_INT(msg_len); + return common_hal_espnow_recv(self); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_recv_obj, espnow_recv); @@ -581,7 +312,9 @@ static void _update_peer_info(size_t n_args, const mp_obj_t *pos_args, mp_map_t memcpy(peer.peer_addr, _get_peer_addr(args[ARG_mac].u_obj), ESP_NOW_ETH_ALEN); if (modify) { - check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); + if (esp_now_get_peer(peer.peer_addr, &peer) != ESP_OK) { + mp_raise_RuntimeError(translate("peer not found")); + } } else { if (esp_now_is_peer_exist(peer.peer_addr)) { mp_raise_RuntimeError(translate("peer already exists")); @@ -593,7 +326,7 @@ static void _update_peer_info(size_t n_args, const mp_obj_t *pos_args, mp_map_t const mp_obj_t channel = args[ARG_channel].u_obj; if (channel != mp_const_none) { - peer.channel = mp_arg_validate_int_range(mp_obj_get_int(channel), 1, 14, MP_QSTR_channel); + peer.channel = mp_arg_validate_int_range(mp_obj_get_int(channel), 0, 14, MP_QSTR_channel); } const mp_obj_t interface = args[ARG_interface].u_obj; @@ -837,7 +570,7 @@ STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt } espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return (espnow_deinited(self)) ? 0 : // If not initialized + return (common_hal_espnow_deinited(self)) ? 0 : // If not initialized arg ^ ( // If no data in the buffer, unset the Read ready flag ((!ringbuf_num_filled(self->recv_buffer)) ? MP_STREAM_POLL_RD : 0) | diff --git a/ports/espressif/bindings/espnow/ESPNowPacket.c b/ports/espressif/bindings/espnow/ESPNowPacket.c new file mode 100644 index 0000000000..82fcfcce98 --- /dev/null +++ b/ports/espressif/bindings/espnow/ESPNowPacket.c @@ -0,0 +1,70 @@ +/* + * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "bindings/espnow/ESPNowPacket.h" + +//| class ESPNowPacket: +//| """A packet retreived from ESP-NOW communication protocol""" +//| +//| mac: ReadableBuffer +//| """The sender's mac address (length = 6 bytes)""" +//| +//| msg: RedableBuffer +//| """The message sent by the peer (length <= 250 bytes)""" +//| +//| rssi: int +//| """The received signal strength indication (in dBm from -127 to 0)""" +//| +//| time: int +//| """The is the time in milliseconds since device last booted""" +//| + +const mp_obj_namedtuple_type_t espnow_packet_type_obj = { + .base = { + .base = { + .type = &mp_type_type + }, + .flags = MP_TYPE_FLAG_EXTENDED, + .name = MP_QSTR_ESPNowPacket, + .print = namedtuple_print, + .parent = &mp_type_tuple, + .make_new = namedtuple_make_new, + .attr = namedtuple_attr, + MP_TYPE_EXTENDED_FIELDS( + .unary_op = mp_obj_tuple_unary_op, + .binary_op = mp_obj_tuple_binary_op, + .subscr = mp_obj_tuple_subscr, + .getiter = mp_obj_tuple_getiter, + ), + }, + .n_fields = 4, + .fields = { + MP_QSTR_mac, + MP_QSTR_msg, + MP_QSTR_rssi, + MP_QSTR_time, + }, +}; diff --git a/ports/espressif/bindings/espnow/ESPNowPacket.h b/ports/espressif/bindings/espnow/ESPNowPacket.h new file mode 100644 index 0000000000..87fc51ee92 --- /dev/null +++ b/ports/espressif/bindings/espnow/ESPNowPacket.h @@ -0,0 +1,30 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/objnamedtuple.h" +extern const mp_obj_namedtuple_type_t espnow_packet_type_obj; diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c index 5661885911..746e9696a9 100644 --- a/ports/espressif/bindings/espnow/__init__.c +++ b/ports/espressif/bindings/espnow/__init__.c @@ -28,6 +28,7 @@ #include "bindings/espnow/__init__.h" #include "bindings/espnow/ESPNow.h" +#include "bindings/espnow/ESPNowPacket.h" //| """ESP-NOW Module //| @@ -75,9 +76,11 @@ STATIC const mp_rom_map_elem_t espnow_module_globals_table[] = { // module name - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espnow) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_espnow) }, + // module classes - { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&espnow_type) }, + { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&espnow_type) }, + { MP_ROM_QSTR(MP_QSTR_ESPNowPacket),MP_ROM_PTR(&espnow_packet_type_obj) }, }; STATIC MP_DEFINE_CONST_DICT(espnow_module_globals, espnow_module_globals_table); diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c new file mode 100644 index 0000000000..6e49f5f54a --- /dev/null +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -0,0 +1,327 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2020 Nick Moore + * Copyright (c) 2018 shawwwn + * Copyright (c) 2020-2021 Glenn Moloney @glenn20 + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "bindings/espnow/ESPNowPacket.h" +#include "shared-bindings/wifi/__init__.h" + +#include "common-hal/espnow/ESPNow.h" + +#include "mphalport.h" + +#include "esp_now.h" + +#define ESPNOW_MAGIC 0x99 + +// The maximum length of an espnow packet (bytes) +#define MAX_PACKET_LEN (sizeof(espnow_packet_t) + ESP_NOW_MAX_DATA_LEN) + +// Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes +// Will allocate an additional 7 bytes for buffer overhead +#define DEFAULT_RECV_BUFFER_SIZE (2 * MAX_PACKET_LEN) + +// Time to wait (millisec) for responses from sent packets: (2 seconds). +#define DEFAULT_SEND_TIMEOUT_MS (2 * 1000) + +// Number of milliseconds to wait for pending responses to sent packets. +// This is a fallback which should never be reached. +#define PENDING_RESPONSES_TIMEOUT_MS 100 +#define PENDING_RESPONSES_BUSY_POLL_MS 10 + +// ESPNow packet format for the receive buffer. +// Use this for peeking at the header of the next packet in the buffer. +typedef struct { + uint8_t magic; // = ESPNOW_MAGIC + uint8_t msg_len; // Length of the message + uint32_t time_ms; // Timestamp (ms) when packet is received + int8_t rssi; // RSSI value (dBm) (-127 to 0) +} __attribute__((packed)) espnow_header_t; + +typedef struct { + espnow_header_t header; // The header + uint8_t peer[6]; // Peer address + uint8_t msg[0]; // Message is up to 250 bytes +} __attribute__((packed)) espnow_packet_t; + +static void check_esp_err(esp_err_t status) { + if (status != ESP_OK) { + mp_raise_RuntimeError(translate("an error occured")); + } +} + +// Return a pointer to the ESPNow module singleton +static espnow_obj_t *_get_singleton(void) { + return MP_STATE_PORT(espnow_singleton); +} + +// --- The ESP-NOW send and recv callback routines --- + +// Callback triggered when a sent packet is acknowledged by the peer (or not). +// Just count the number of responses and number of failures. +// These are used in the send() logic. +static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { + espnow_obj_t *self = _get_singleton(); + self->tx_responses++; + if (status != ESP_NOW_SEND_SUCCESS) { + self->tx_failures++; + } +} + +static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg); + +// Callback triggered when an ESP-NOW packet is received. +// Write the peer MAC address and the message into the recv_buffer as an ESPNow packet. +// If the buffer is full, drop the message and increment the dropped count. +static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { + espnow_obj_t *self = _get_singleton(); + ringbuf_t *buf = self->recv_buffer; + + if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { + self->rx_failures++; + return; + } + + espnow_header_t header; + header.magic = ESPNOW_MAGIC; + header.msg_len = msg_len; + header.rssi = _get_rssi_from_wifi_packet(msg); + header.time_ms = mp_hal_ticks_ms(); + + ringbuf_put_n(buf, (uint8_t *)&header, sizeof(header)); + ringbuf_put_n(buf, mac, ESP_NOW_ETH_ALEN); + ringbuf_put_n(buf, msg, msg_len); + + self->rx_packets++; +} + +bool common_hal_espnow_deinited(espnow_obj_t *self) { + return self->recv_buffer == NULL; +} + +// Initialize the ESP-NOW software stack, +// register callbacks and allocate the recv data buffers. +void common_hal_espnow_init(espnow_obj_t *self) { + if (!common_hal_espnow_deinited(self)) { + return; + } + + self->recv_buffer = m_new_obj(ringbuf_t); + if (!ringbuf_alloc(self->recv_buffer, self->recv_buffer_size, true)) { + m_malloc_fail(self->recv_buffer_size); + } + + if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + common_hal_wifi_init(false); + common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); + } + + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, self->phy_rate)); + check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, self->phy_rate)); + + check_esp_err(esp_now_init()); + check_esp_err(esp_now_register_send_cb(send_cb)); + check_esp_err(esp_now_register_recv_cb(recv_cb)); +} + +// De-initialize the ESP-NOW software stack, +// disable callbacks and deallocate the recv data buffers. +void common_hal_espnow_deinit(espnow_obj_t *self) { + if (self == NULL || common_hal_espnow_deinited(self)) { + return; + } + + check_esp_err(esp_now_unregister_send_cb()); + check_esp_err(esp_now_unregister_recv_cb()); + check_esp_err(esp_now_deinit()); + + self->recv_buffer->buf = NULL; + self->recv_buffer = NULL; + self->peers_count = 0; // esp_now_deinit() removes all peers. + self->tx_packets = self->tx_responses; +} + +void espnow_reset(void) { + common_hal_espnow_deinit(_get_singleton()); + MP_STATE_PORT(espnow_singleton) = NULL; +} + +void common_hal_espnow_set_buffer_size(espnow_obj_t *self, mp_int_t value) { + self->recv_buffer_size = mp_arg_validate_int_min(value, MAX_PACKET_LEN, MP_QSTR_buffer_size); +}; + +void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value) { + self->phy_rate = mp_arg_validate_int_range(value, 0, WIFI_PHY_RATE_MAX - 1, MP_QSTR_phy_rate); +}; + +void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key) { + check_esp_err(esp_now_set_pmk(key)); +} + +// --- Maintaining the peer table and reading RSSI values --- + +// We maintain a peers table for several reasons, to: +// - support monitoring the RSSI values for all peers; and +// - to return unique bytestrings for each peer which supports more efficient +// application memory usage and peer handling. + +// Get the RSSI value from the wifi packet header +static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { + // Warning: Secret magic to get the rssi from the wifi packet header + // See espnow.c:espnow_recv_cb() at https://github.com/espressif/esp-now/ + // In the wifi packet the msg comes after a wifi_promiscuous_pkt_t + // and a espnow_frame_format_t. + // Backtrack to get a pointer to the wifi_promiscuous_pkt_t. + #define SIZEOF_ESPNOW_FRAME_FORMAT 39 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + wifi_promiscuous_pkt_t *wifi_packet = (wifi_promiscuous_pkt_t *)( + msg - SIZEOF_ESPNOW_FRAME_FORMAT - sizeof(wifi_promiscuous_pkt_t)); + #pragma GCC diagnostic pop + return wifi_packet->rx_ctrl.rssi; +} + +// Lookup a peer in the peers table and return a reference to the item in the peers_table. +// Add peer to the table if it is not found (may alloc memory). Will not return NULL. +static mp_map_elem_t *_lookup_add_peer(espnow_obj_t *self, const uint8_t *peer) { + // We do not want to allocate any new memory in the case that the peer + // already exists in the peers_table (which is almost all the time). + // So, we use a byte string on the stack and look that up in the dict. + mp_map_t *map = mp_obj_dict_get_map(self->peers_table); + mp_obj_str_t peer_obj = {{&mp_type_bytes}, 0, ESP_NOW_ETH_ALEN, peer}; + mp_map_elem_t *item = mp_map_lookup(map, &peer_obj, MP_MAP_LOOKUP); + if (item == NULL) { + // If not found, add the peer using a new bytestring + map->is_fixed = 0; // Allow to modify the dict + mp_obj_t new_peer = mp_obj_new_bytes(peer, ESP_NOW_ETH_ALEN); + item = mp_map_lookup(map, new_peer, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + item->value = mp_obj_new_list(2, NULL); + map->is_fixed = 1; // Relock the dict + } + return item; +} + +// Update the peers table with the new rssi value from a received packet and +// return a reference to the item in the peers_table. +static void _update_rssi(espnow_obj_t *self, const uint8_t *peer, int8_t rssi, uint32_t time_ms) { + // Lookup the peer in the device table + mp_map_elem_t *item = _lookup_add_peer(self, peer); + mp_obj_list_t *list = MP_OBJ_TO_PTR(item->value); + list->items[0] = MP_OBJ_NEW_SMALL_INT(rssi); + list->items[1] = mp_obj_new_int(time_ms); +} + +// --- Send and Receive ESP-NOW data --- + +// Used by espnow_send() for sends() with sync==True. +// Wait till all pending sent packet responses have been received. +// ie. self->tx_responses == self->tx_packets. +static void _wait_for_pending_responses(espnow_obj_t *self) { + mp_uint_t t, start = mp_hal_ticks_ms(); + while (self->tx_responses < self->tx_packets) { + if ((t = mp_hal_ticks_ms() - start) > PENDING_RESPONSES_TIMEOUT_MS) { + mp_raise_OSError(MP_ETIMEDOUT); + } + if (t > PENDING_RESPONSES_BUSY_POLL_MS) { + // After 10ms of busy waiting give other tasks a look in. + RUN_BACKGROUND_TASKS; + } + } +} + +mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const bool sync, const uint8_t *mac, const mp_buffer_info_t *message) { + if (sync) { + // Flush out any pending responses. + // If the last call was sync == False there may be outstanding responses + // still to be received (possible many if we just had a burst of unsync send()s). + // We need to wait for all pending responses if this call has sync = True. + _wait_for_pending_responses(self); + } + + // Send the packet - try, try again if internal esp-now buffers are full. + esp_err_t err; + size_t saved_failures = self->tx_failures; + mp_uint_t start = mp_hal_ticks_ms(); + + while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(mac, message->buf, message->len))) && + (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { + RUN_BACKGROUND_TASKS; + } + check_esp_err(err); + + // Increment the sent packet count. + // If mac == NULL msg will be sent to all peers EXCEPT any broadcast or multicast addresses. + self->tx_packets += ((mac == NULL) ? self->peers_count : 1); + + if (sync) { + // Wait for and tally all the expected responses from peers + _wait_for_pending_responses(self); + } + + // Return False if sync and any peers did not respond. + return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures)); +} + +mp_obj_t common_hal_espnow_recv(espnow_obj_t *self) { + if (!ringbuf_num_filled(self->recv_buffer)) { + return mp_const_none; + } + + // Read the packet header from the incoming buffer + espnow_header_t header; + if (ringbuf_get_n(self->recv_buffer, (uint8_t *)&header, sizeof(header)) != sizeof(header)) { + mp_arg_error_invalid(MP_QSTR_buffer); + } + + uint8_t msg_len = header.msg_len; + + uint8_t mac_buf[ESP_NOW_ETH_ALEN]; + uint8_t msg_buf[msg_len]; + + // Check the message packet header format and read the message data + if (header.magic != ESPNOW_MAGIC || + msg_len > ESP_NOW_MAX_DATA_LEN || + ringbuf_get_n(self->recv_buffer, mac_buf, ESP_NOW_ETH_ALEN) != ESP_NOW_ETH_ALEN || + ringbuf_get_n(self->recv_buffer, msg_buf, msg_len) != msg_len) { + mp_arg_error_invalid(MP_QSTR_buffer); + } + + // Update rssi value in the peer device table + _update_rssi(self, mac_buf, header.rssi, header.time_ms); + + mp_obj_t elems[4] = { + mp_obj_new_bytes(mac_buf, ESP_NOW_ETH_ALEN), + mp_obj_new_bytes(msg_buf, msg_len), + MP_OBJ_NEW_SMALL_INT(header.rssi), + mp_obj_new_int(header.time_ms), + }; + + return namedtuple_make_new((const mp_obj_type_t *)&espnow_packet_type_obj, 4, 0, elems); +} diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h new file mode 100644 index 0000000000..54761c00df --- /dev/null +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -0,0 +1,57 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/ringbuf.h" + +#include "esp_wifi.h" + +// The data structure for the espnow_singleton. +typedef struct _espnow_obj_t { + mp_obj_base_t base; + ringbuf_t *recv_buffer; // A buffer for received packets + size_t recv_buffer_size; // The size of the recv_buffer + wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. + volatile size_t rx_packets; // # of received packets + volatile size_t rx_failures; // # of dropped packets (buffer full) + size_t tx_packets; // # of sent packets + volatile size_t tx_responses; // # of sent packet responses received + volatile size_t tx_failures; // # of sent packet responses failed + size_t peers_count; // Cache the # of peers for send(sync=True) + mp_obj_t peers_table; // A dictionary of discovered peers +} espnow_obj_t; + +extern void espnow_reset(void); + +extern void common_hal_espnow_init(espnow_obj_t *self); +extern void common_hal_espnow_deinit(espnow_obj_t *self); +extern bool common_hal_espnow_deinited(espnow_obj_t *self); + +extern void common_hal_espnow_set_buffer_size(espnow_obj_t *self, mp_int_t value); +extern void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value); +extern void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key); + +extern mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const bool sync, const uint8_t *mac, const mp_buffer_info_t *message); +extern mp_obj_t common_hal_espnow_recv(espnow_obj_t *self); From 7028a3adfe370be6fc93bc3f2456c36cbbb593c9 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Thu, 2 Feb 2023 21:34:24 +0530 Subject: [PATCH 08/29] rework espnow api --- locale/circuitpython.pot | 12 +- ports/espressif/Makefile | 6 +- ports/espressif/bindings/espnow/ESPNow.c | 352 +++--------------- .../espressif/bindings/espnow/ESPNowPacket.c | 2 +- ports/espressif/bindings/espnow/Peer.c | 254 +++++++++++++ ports/espressif/bindings/espnow/Peer.h | 37 ++ ports/espressif/bindings/espnow/Peers.c | 221 +++++++++++ ports/espressif/bindings/espnow/Peers.h | 37 ++ ports/espressif/bindings/espnow/__init__.c | 29 +- ports/espressif/common-hal/espnow/ESPNow.c | 8 +- ports/espressif/common-hal/espnow/ESPNow.h | 7 +- 11 files changed, 641 insertions(+), 324 deletions(-) create mode 100644 ports/espressif/bindings/espnow/Peer.c create mode 100644 ports/espressif/bindings/espnow/Peer.h create mode 100644 ports/espressif/bindings/espnow/Peers.c create mode 100644 ports/espressif/bindings/espnow/Peers.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1b44383086..da9e0ac0f2 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -124,7 +124,7 @@ msgstr "" msgid "%q init failed" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -2431,7 +2431,7 @@ msgstr "" msgid "addresses is empty" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/bindings/espnow/Peers.c #: ports/espressif/common-hal/espnow/ESPNow.c msgid "an error occured" msgstr "" @@ -3816,14 +3816,6 @@ msgstr "" msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "peer already exists" -msgstr "" - -#: ports/espressif/bindings/espnow/ESPNow.c -msgid "peer not found" -msgstr "" - #: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c msgid "pixel coordinates out of bounds" msgstr "" diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 76d443dd68..8e326e18ab 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -126,9 +126,13 @@ ifeq ($(DEBUG), 1) # CFLAGS += -fno-inline -fno-ipa-sra else CFLAGS += -DNDEBUG -ggdb3 - OPTIMIZATION_FLAGS ?= -O2 # RISC-V is larger than xtensa # Use -Os for RISC-V when it overflows + ifeq ($(IDF_TARGET_ARCH),riscv) + OPTIMIZATION_FLAGS ?= -Os + else + OPTIMIZATION_FLAGS ?= -O2 + endif endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index b120b2cdff..9a1ddfb80f 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -27,27 +27,32 @@ * THE SOFTWARE. */ -#include "esp_now.h" - #include "py/runtime.h" #include "py/objarray.h" #include "py/objproperty.h" #include "py/stream.h" -#include "py/ringbuf.h" -#include "mphalport.h" - -#include "bindings/espnow/__init__.h" #include "bindings/espnow/ESPNow.h" #include "shared-bindings/util.h" #include "common-hal/espnow/ESPNow.h" -static void check_esp_err(esp_err_t status) { - if (status != ESP_OK) { - mp_raise_RuntimeError(translate("an error occured")); - } +#include "esp_now.h" + +// Return C pointer to byte memory string/bytes/bytearray in obj. +// Raise ValueError if the length does not match expected len. +static const uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(obj, &bufinfo, rw); + mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); + return (uint8_t *)bufinfo.buf; +} + +// Return C pointer to the MAC address. +// Raise ValueError if mac is wrong type or is not 6 bytes long. +static const uint8_t *_get_peer_addr(mp_obj_t mac) { + return mp_obj_is_true(mac) ? _get_bytes_len(mac, ESP_NOW_ETH_ALEN, MP_BUFFER_READ) : NULL; } // --- Initialisation and Config functions --- @@ -89,6 +94,7 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t common_hal_espnow_set_buffer_size(self, args[ARG_buffer_size].u_int); common_hal_espnow_set_phy_rate(self, args[ARG_phy_rate].u_int); + self->peers = espnow_peers_new(); self->peers_table = mp_obj_new_dict(0); // Prevent user code modifying the dict @@ -102,14 +108,30 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t return self; } -// Return C pointer to byte memory string/bytes/bytearray in obj. -// Raise ValueError if the length does not match expected len. -static const uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(obj, &bufinfo, rw); - mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); - return (uint8_t *)bufinfo.buf; +//| def deinit(self) -> None: +//| """Deinitializes ESP-NOW and releases it for another program.""" +//| ... +STATIC mp_obj_t espnow_deinit(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_deinit(self); + return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_deinit_obj, espnow_deinit); + +//| def __enter__(self) -> ESPNow: +//| """No-op used by Context Managers.""" +//| ... +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +STATIC mp_obj_t espnow_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return espnow_deinit(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow___exit___obj, 4, 4, espnow_obj___exit__); //| def set_pmk(self, pmk: ReadableBuffer) -> None: //| """Set the ESP-NOW Primary Master Key (pmk) for encrypted communications. @@ -123,27 +145,6 @@ STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); -//| active: bool -//| """Initialize or de-initialize the `ESPNow` communication protocol.""" -//| -STATIC mp_obj_t espnow_get_active(const mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(!common_hal_espnow_deinited(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_active_obj, espnow_get_active); - -STATIC mp_obj_t espnow_set_active(const mp_obj_t self_in, const mp_obj_t value) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_is_true(value) ? common_hal_espnow_init(self) : common_hal_espnow_deinit(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_active_obj, espnow_set_active); - -MP_PROPERTY_GETSET(espnow_active_obj, - (mp_obj_t)&espnow_get_active_obj, - (mp_obj_t)&espnow_set_active_obj); - - //| buffer_size: int //| """The size of the internal ring buffer.""" //| @@ -202,39 +203,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_stats_obj, espnow_get_stats); MP_PROPERTY_GETTER(espnow_stats_obj, (mp_obj_t)&espnow_get_stats_obj); -// --- Maintaining the peer table and reading RSSI values --- - -// We maintain a peers table for several reasons, to: -// - support monitoring the RSSI values for all peers; and -// - to return unique bytestrings for each peer which supports more efficient -// application memory usage and peer handling. - -// Get the RSSI value from the wifi packet header -static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { - // Warning: Secret magic to get the rssi from the wifi packet header - // See espnow.c:espnow_recv_cb() at https://github.com/espressif/esp-now/ - // In the wifi packet the msg comes after a wifi_promiscuous_pkt_t - // and a espnow_frame_format_t. - // Backtrack to get a pointer to the wifi_promiscuous_pkt_t. - #define SIZEOF_ESPNOW_FRAME_FORMAT 39 - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - wifi_promiscuous_pkt_t *wifi_packet = (wifi_promiscuous_pkt_t *)( - msg - SIZEOF_ESPNOW_FRAME_FORMAT - sizeof(wifi_promiscuous_pkt_t)); - #pragma GCC diagnostic pop - return wifi_packet->rx_ctrl.rssi; -} - -// --- Handling espnow packets in the recv buffer --- - // --- Send and Receive ESP-NOW data --- -// Return C pointer to the MAC address. -// Raise ValueError if mac is wrong type or is not 6 bytes long. -static const uint8_t *_get_peer_addr(mp_obj_t mac) { - return mp_obj_is_true(mac) ? _get_bytes_len(mac, ESP_NOW_ETH_ALEN, MP_BUFFER_READ) : NULL; -} - //| def send( //| self, //| message: ReadableBuffer, @@ -284,246 +254,38 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); //| //| :returns: An `ESPNowPacket` if available in the buffer, otherwise `None`.""" //| ... -STATIC mp_obj_t espnow_recv(mp_obj_t self_in, mp_obj_t buffers) { +STATIC mp_obj_t espnow_recv(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); return common_hal_espnow_recv(self); } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_recv_obj, espnow_recv); - -// --- Peer Management Functions --- - -// Common code for add_peer() and mod_peer() to process the args. -static void _update_peer_info(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool modify) { - enum { ARG_mac, ARG_lmk, ARG_channel, ARG_interface, ARG_encrypt }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_mac, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_lmk, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_channel, MP_ARG_INT, { .u_obj = mp_const_none } }, - { MP_QSTR_interface,MP_ARG_INT, { .u_obj = mp_const_none } }, - { MP_QSTR_encrypt, MP_ARG_BOOL,{ .u_obj = mp_const_none } }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - esp_now_peer_info_t peer = {0}; - memcpy(peer.peer_addr, _get_peer_addr(args[ARG_mac].u_obj), ESP_NOW_ETH_ALEN); - - if (modify) { - if (esp_now_get_peer(peer.peer_addr, &peer) != ESP_OK) { - mp_raise_RuntimeError(translate("peer not found")); - } - } else { - if (esp_now_is_peer_exist(peer.peer_addr)) { - mp_raise_RuntimeError(translate("peer already exists")); - } - peer.channel = 0; - peer.ifidx = WIFI_IF_STA; - peer.encrypt = false; - } - - const mp_obj_t channel = args[ARG_channel].u_obj; - if (channel != mp_const_none) { - peer.channel = mp_arg_validate_int_range(mp_obj_get_int(channel), 0, 14, MP_QSTR_channel); - } - - const mp_obj_t interface = args[ARG_interface].u_obj; - if (interface != mp_const_none) { - peer.ifidx = (wifi_interface_t)mp_arg_validate_int_range(mp_obj_get_int(interface), 0, 1, MP_QSTR_interface); - } - - const mp_obj_t encrypt = args[ARG_encrypt].u_obj; - if (encrypt != mp_const_none) { - peer.encrypt = mp_obj_is_true(encrypt); - } - - const mp_obj_t lmk = args[ARG_lmk].u_obj; - if (lmk != mp_const_none) { - memcpy(peer.lmk, _get_bytes_len(lmk, ESP_NOW_KEY_LEN, MP_BUFFER_READ), ESP_NOW_KEY_LEN); - } else if (peer.encrypt) { - mp_raise_ValueError_varg(translate("%q is %q"), MP_QSTR_lmk, MP_QSTR_None); - } - - check_esp_err((modify) ? esp_now_mod_peer(&peer) : esp_now_add_peer(&peer)); -} - -// Update the cached peer count in self->peers_count; -// The peers_count ignores broadcast and multicast addresses and is used for the -// send() logic and is updated from add_peer(), mod_peer() and del_peer(). -static void _update_peer_count(espnow_obj_t *self) { - esp_now_peer_info_t peer = {0}; - bool from_head = true; - int count = 0; - - // esp_now_fetch_peer() skips over any broadcast or multicast addresses - while (esp_now_fetch_peer(from_head, &peer) == ESP_OK) { - from_head = false; - if (++count >= ESP_NOW_MAX_TOTAL_PEER_NUM) { - break; // Should not happen - } - } - - self->peers_count = count; -} - -//| def add_peer( -//| self, -//| mac: ReadableBuffer, -//| lmk: Optional[ReadableBuffer], -//| channel: int = 0, -//| interface: int = 0, -//| encrypt: bool = False, -//| ) -> None: -//| """Add peer. -//| -//| :param ReadableBuffer mac: The mac address of the peer. -//| :param ReadableBuffer lmk: The Local Master Key (lmk) of the peer. -//| :param int channel: The peer's channel. Default: 0 ie. use the current channel. -//| :param int interface: The WiFi interface to use. Default: 0 ie. STA. -//| :param bool encrypt: Whether or not to use encryption.""" -//| ... -STATIC mp_obj_t espnow_add_peer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - espnow_obj_t *self = pos_args[0]; - check_for_deinit(self); - - _update_peer_info(n_args, pos_args, kw_args, false); - _update_peer_count(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_add_peer_obj, 2, espnow_add_peer); - -//| def mod_peer( -//| self, -//| mac: ReadableBuffer, -//| lmk: Optional[ReadableBuffer], -//| channel: int = 0, -//| interface: int = 0, -//| encrypt: bool = False, -//| ) -> None: -//| """Modify peer. -//| -//| :param ReadableBuffer mac: The mac address of the peer. -//| :param ReadableBuffer lmk: The Local Master Key (lmk) of the peer. -//| :param int channel: The peer's channel. Default: 0 ie. use the current channel. -//| :param int interface: The WiFi interface to use. Default: 0 ie. STA. -//| :param bool encrypt: Whether or not to use encryption.""" -//| ... -STATIC mp_obj_t espnow_mod_peer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - espnow_obj_t *self = pos_args[0]; - check_for_deinit(self); - - _update_peer_info(n_args, pos_args, kw_args, true); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_mod_peer_obj, 2, espnow_mod_peer); - -//| def del_peer(self, mac: ReadableBuffer) -> None: -//| """Delete peer. -//| -//| :param ReadableBuffer mac: The mac address of the peer.""" -//| ... -STATIC mp_obj_t espnow_del_peer(mp_obj_t self_in, mp_obj_t mac) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - uint8_t peer_addr[ESP_NOW_ETH_ALEN]; - memcpy(peer_addr, _get_peer_addr(mac), ESP_NOW_ETH_ALEN); - - check_esp_err(esp_now_del_peer(peer_addr)); - _update_peer_count(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_del_peer_obj, espnow_del_peer); - -// Convert a peer_info struct to python tuple -// Used by espnow_get_peer() and espnow_get_peers() -static mp_obj_t _peer_info_to_tuple(const esp_now_peer_info_t *peer) { - return MP_OBJ_NEW_TUPLE( - mp_obj_new_bytes(peer->peer_addr, MP_ARRAY_SIZE(peer->peer_addr)), - mp_obj_new_bytes(peer->lmk, MP_ARRAY_SIZE(peer->lmk)), - mp_obj_new_int(peer->channel), - mp_obj_new_int(peer->ifidx), - mp_obj_new_bool(peer->encrypt)); -} - -//| def get_peer(self, mac: ReadableBuffer) -> Tuple[bytes, int, int, bool]: -//| """Get the peer info for mac as a `tuple`. -//| -//| :param ReadableBuffer mac: The mac address of the peer. -//| -//| :returns: A `tuple` of (mac, lmk, channel, interface, encrypt).""" -//| ... -STATIC mp_obj_t espnow_get_peer(mp_obj_t self_in, mp_obj_t mac) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - esp_now_peer_info_t peer = {0}; - memcpy(peer.peer_addr, _get_peer_addr(mac), ESP_NOW_ETH_ALEN); - check_esp_err(esp_now_get_peer(peer.peer_addr, &peer)); - - return _peer_info_to_tuple(&peer); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_get_peer_obj, espnow_get_peer); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_recv_obj, espnow_recv); // --- Peer Related Properties --- -//| peers: Tuple[Tuple[bytes, bytes, int, int, bool], ...] -//| """The peer info records for all registered `ESPNow` peers. (read-only) -//| -//| A `tuple` of tuples: ((mac, lmk, channel, interface, encrypt), ...).""" +//| peers: Peers +//| """The peer info records for all registered `ESPNow` peers. (read-only)""" //| STATIC mp_obj_t espnow_get_peers(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - - // Build and initialize the peer info tuple. - mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->peers_count, NULL); - esp_now_peer_info_t peer = {0}; - - for (size_t i = 0; i < peerinfo_tuple->len; i++) { - esp_err_t status = esp_now_fetch_peer((i == 0), &peer); - peerinfo_tuple->items[i] = (status == ESP_OK ? _peer_info_to_tuple(&peer) : mp_const_none); - } - - return peerinfo_tuple; + return MP_OBJ_FROM_PTR(self->peers); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_obj, espnow_get_peers); MP_PROPERTY_GETTER(espnow_peers_obj, (mp_obj_t)&espnow_get_peers_obj); -//| peers_count: Tuple[int, int] -//| """The number of registered peers in a `tuple` of (num_total_peers, num_encrypted_peers). (read-only)""" -//| -STATIC mp_obj_t espnow_get_peers_count(mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - esp_now_peer_num_t peer_num = {0}; - check_esp_err(esp_now_get_peer_num(&peer_num)); - return MP_OBJ_NEW_TUPLE( - mp_obj_new_int(peer_num.total_num), - mp_obj_new_int(peer_num.encrypt_num)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_count_obj, espnow_get_peers_count); - -MP_PROPERTY_GETTER(espnow_peers_count_obj, - (mp_obj_t)&espnow_get_peers_count_obj); - //| peers_table: Dict[bytes, List[int]] //| """The dictionary of peers we have seen. (read-only) //| //| A `dict` of {peer: [rssi, time], ...} //| //| where: -//| peer is a byte string containing the 6-byte mac address of the peer. -//| rssi is the wifi signal strength from the last msg received (in dBm from -127 to 0). -//| time is the time in milliseconds since device last booted.""" +//| * peer is a byte string containing the 6-byte mac address of the peer. +//| * rssi is the wifi signal strength from the last msg received (in dBm from -127 to 0). +//| * time is the time in milliseconds since device last booted.""" //| STATIC mp_obj_t espnow_get_peers_table(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -535,26 +297,25 @@ MP_PROPERTY_GETTER(espnow_peers_table_obj, (mp_obj_t)&espnow_get_peers_table_obj); STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { + // Context managers + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&espnow___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&espnow_deinit_obj) }, + // Config parameters { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) }, - { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&espnow_active_obj) }, { MP_ROM_QSTR(MP_QSTR_buffer_size), MP_ROM_PTR(&espnow_buffer_size_obj) }, { MP_ROM_QSTR(MP_QSTR_phy_rate), MP_ROM_PTR(&espnow_phy_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_stats), MP_ROM_PTR(&espnow_stats_obj) }, // Send and receive messages { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&espnow_recv_obj) }, - // Peer management functions - { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_mod_peer), MP_ROM_PTR(&espnow_mod_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_del_peer), MP_ROM_PTR(&espnow_del_peer_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_peer), MP_ROM_PTR(&espnow_get_peer_obj) }, - // Peer related properties { MP_ROM_QSTR(MP_QSTR_peers), MP_ROM_PTR(&espnow_peers_obj) }, - { MP_ROM_QSTR(MP_QSTR_peers_count), MP_ROM_PTR(&espnow_peers_count_obj) }, { MP_ROM_QSTR(MP_QSTR_peers_table), MP_ROM_PTR(&espnow_peers_table_obj) }, }; STATIC MP_DEFINE_CONST_DICT(espnow_locals_dict, espnow_locals_dict_table); @@ -570,7 +331,7 @@ STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt } espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return (common_hal_espnow_deinited(self)) ? 0 : // If not initialized + return (common_hal_espnow_deinited(self)) ? 0 : // If not initialized arg ^ ( // If no data in the buffer, unset the Read ready flag ((!ringbuf_num_filled(self->recv_buffer)) ? MP_STREAM_POLL_RD : 0) | @@ -590,6 +351,7 @@ STATIC const mp_stream_p_t espnow_stream_p = { //| def __len__(self) -> int: //| """Return the number of `bytes` available to read. Used to implement ``len()``.""" //| ... +//| STATIC mp_obj_t espnow_unary_op(mp_unary_op_t op, mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); size_t len = ringbuf_num_filled(self->recv_buffer); @@ -599,7 +361,7 @@ STATIC mp_obj_t espnow_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_LEN: return mp_obj_new_int_from_uint(len); default: - return MP_OBJ_NULL; // op not supported + return MP_OBJ_NULL; // op not supported } } diff --git a/ports/espressif/bindings/espnow/ESPNowPacket.c b/ports/espressif/bindings/espnow/ESPNowPacket.c index 82fcfcce98..9d582a00eb 100644 --- a/ports/espressif/bindings/espnow/ESPNowPacket.c +++ b/ports/espressif/bindings/espnow/ESPNowPacket.c @@ -32,7 +32,7 @@ //| mac: ReadableBuffer //| """The sender's mac address (length = 6 bytes)""" //| -//| msg: RedableBuffer +//| msg: ReadableBuffer //| """The message sent by the peer (length <= 250 bytes)""" //| //| rssi: int diff --git a/ports/espressif/bindings/espnow/Peer.c b/ports/espressif/bindings/espnow/Peer.c new file mode 100644 index 0000000000..6dcf2732aa --- /dev/null +++ b/ports/espressif/bindings/espnow/Peer.c @@ -0,0 +1,254 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "bindings/espnow/Peer.h" + +// TODO: check peer already exist +// TODO: check peer dosen't exist + +// Return C pointer to the ReadableBuffer. +// Raise ValueError if the length does not match expected len. +static const uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(obj, &bufinfo, rw); + mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); + return (uint8_t *)bufinfo.buf; +} + +// Return C pointer to the MAC address. +// Raise ValueError if mac is wrong type or is not 6 bytes long. +static const uint8_t *_get_peer_addr(mp_obj_t mac) { + return mp_obj_is_true(mac) ? _get_bytes_len(mac, ESP_NOW_ETH_ALEN, MP_BUFFER_READ) : NULL; +} + +//| class Peer: +//| """A data class to store parameters specific to a peer.""" +//| +//| def __init__( +//| self, +//| mac: bytes, +//| lmk: Optional[bytes], +//| channel: int = 0, +//| interface: int = 0, +//| encrypt: bool = False, +//| ) -> None: +//| """Construct a new peer object. +//| +//| :param bytes mac: The mac address of the peer. +//| :param bytes lmk: The Local Master Key (lmk) of the peer. +//| :param int channel: The peer's channel. Default: 0 ie. use the current channel. +//| :param int interface: The WiFi interface to use. Default: 0 ie. STA. +//| :param bool encrypt: Whether or not to use encryption. +//| """ +//| ... +STATIC mp_obj_t espnow_peer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_mac, ARG_lmk, ARG_channel, ARG_interface, ARG_encrypt }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mac, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_lmk, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_channel, MP_ARG_INT, { .u_obj = mp_const_none } }, + { MP_QSTR_interface,MP_ARG_INT, { .u_obj = mp_const_none } }, + { MP_QSTR_encrypt, MP_ARG_BOOL,{ .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + espnow_peer_obj_t *self = m_new_obj(espnow_peer_obj_t); + self->base.type = &espnow_peer_type; + self->peer_info = (esp_now_peer_info_t) { + .channel = 0, + .ifidx = WIFI_IF_STA, + .encrypt = false + }; + + memcpy(self->peer_info.peer_addr, _get_peer_addr(args[ARG_mac].u_obj), ESP_NOW_ETH_ALEN); + + const mp_obj_t channel = args[ARG_channel].u_obj; + if (channel != mp_const_none) { + self->peer_info.channel = mp_arg_validate_int_range(mp_obj_get_int(channel), 0, 14, MP_QSTR_channel); + } + + const mp_obj_t interface = args[ARG_interface].u_obj; + if (interface != mp_const_none) { + self->peer_info.ifidx = (wifi_interface_t)mp_arg_validate_int_range(mp_obj_get_int(interface), 0, 1, MP_QSTR_interface); + } + + const mp_obj_t encrypt = args[ARG_encrypt].u_obj; + if (encrypt != mp_const_none) { + self->peer_info.encrypt = mp_obj_is_true(encrypt); + } + + const mp_obj_t lmk = args[ARG_lmk].u_obj; + if (lmk != mp_const_none) { + memcpy(self->peer_info.lmk, _get_bytes_len(lmk, ESP_NOW_KEY_LEN, MP_BUFFER_READ), ESP_NOW_KEY_LEN); + } else if (self->peer_info.encrypt && !self->peer_info.lmk) { + mp_raise_ValueError_varg(translate("%q is %q"), MP_QSTR_lmk, MP_QSTR_None); + } + + return self; +} + +//| mac: ReadableBuffer +//| """The WiFi mac to use.""" +//| +STATIC mp_obj_t espnow_peer_get_mac(const mp_obj_t self_in) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bytes(self->peer_info.peer_addr, MP_ARRAY_SIZE(self->peer_info.peer_addr)); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_get_mac_obj, espnow_peer_get_mac); + +STATIC mp_obj_t espnow_peer_set_mac(const mp_obj_t self_in, const mp_obj_t value) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + memcpy(self->peer_info.peer_addr, _get_peer_addr(value), ESP_NOW_ETH_ALEN); + esp_now_mod_peer(&self->peer_info); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_peer_set_mac_obj, espnow_peer_set_mac); + +MP_PROPERTY_GETSET(espnow_peer_mac_obj, + (mp_obj_t)&espnow_peer_get_mac_obj, + (mp_obj_t)&espnow_peer_set_mac_obj); + +//| lmk: ReadableBuffer +//| """The WiFi lmk to use.""" +//| +STATIC mp_obj_t espnow_peer_get_lmk(const mp_obj_t self_in) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bytes(self->peer_info.lmk, MP_ARRAY_SIZE(self->peer_info.lmk)); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_get_lmk_obj, espnow_peer_get_lmk); + +STATIC mp_obj_t espnow_peer_set_lmk(const mp_obj_t self_in, const mp_obj_t value) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + memcpy(self->peer_info.lmk, _get_bytes_len(value, ESP_NOW_KEY_LEN, MP_BUFFER_READ), ESP_NOW_KEY_LEN); + esp_now_mod_peer(&self->peer_info); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_peer_set_lmk_obj, espnow_peer_set_lmk); + +MP_PROPERTY_GETSET(espnow_peer_lmk_obj, + (mp_obj_t)&espnow_peer_get_lmk_obj, + (mp_obj_t)&espnow_peer_set_lmk_obj); + +//| channel: int +//| """The WiFi channel to use.""" +//| +STATIC mp_obj_t espnow_peer_get_channel(const mp_obj_t self_in) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->peer_info.channel); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_get_channel_obj, espnow_peer_get_channel); + +STATIC mp_obj_t espnow_peer_set_channel(const mp_obj_t self_in, const mp_obj_t value) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->peer_info.channel = mp_arg_validate_int_range(mp_obj_get_int(value), 0, 14, MP_QSTR_channel); + esp_now_mod_peer(&self->peer_info); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_peer_set_channel_obj, espnow_peer_set_channel); + +MP_PROPERTY_GETSET(espnow_peer_channel_obj, + (mp_obj_t)&espnow_peer_get_channel_obj, + (mp_obj_t)&espnow_peer_set_channel_obj); + +//| interface: int +//| """The WiFi interface to use.""" +//| +STATIC mp_obj_t espnow_peer_get_interface(const mp_obj_t self_in) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->peer_info.ifidx); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_get_interface_obj, espnow_peer_get_interface); + +STATIC mp_obj_t espnow_peer_set_interface(const mp_obj_t self_in, const mp_obj_t value) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->peer_info.ifidx = (wifi_interface_t)mp_arg_validate_int_range(mp_obj_get_int(value), 0, 1, MP_QSTR_interface); + esp_now_mod_peer(&self->peer_info); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_peer_set_interface_obj, espnow_peer_set_interface); + +MP_PROPERTY_GETSET(espnow_peer_interface_obj, + (mp_obj_t)&espnow_peer_get_interface_obj, + (mp_obj_t)&espnow_peer_set_interface_obj); + +//| encrypted: bool +//| """Whether or not to use encryption.""" +//| +STATIC mp_obj_t espnow_peer_get_encrypted(const mp_obj_t self_in) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->peer_info.encrypt); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_get_encrypted_obj, espnow_peer_get_encrypted); + +STATIC mp_obj_t espnow_peer_set_encrypted(const mp_obj_t self_in, const mp_obj_t value) { + espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); + + self->peer_info.encrypt = mp_obj_is_true(value); + + if (!self->peer_info.lmk) { + mp_raise_ValueError_varg(translate("%q is %q"), MP_QSTR_lmk, MP_QSTR_None); + } + + esp_now_mod_peer(&self->peer_info); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(espnow_peer_set_encrypted_obj, espnow_peer_set_encrypted); + +MP_PROPERTY_GETSET(espnow_peer_encrypted_obj, + (mp_obj_t)&espnow_peer_get_encrypted_obj, + (mp_obj_t)&espnow_peer_set_encrypted_obj); + +STATIC const mp_rom_map_elem_t espnow_peer_locals_dict_table[] = { + // Peer parameters + { MP_ROM_QSTR(MP_QSTR_mac), MP_ROM_PTR(&espnow_peer_mac_obj) }, + { MP_ROM_QSTR(MP_QSTR_lmk), MP_ROM_PTR(&espnow_peer_lmk_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&espnow_peer_channel_obj) }, + { MP_ROM_QSTR(MP_QSTR_interface), MP_ROM_PTR(&espnow_peer_interface_obj) }, + { MP_ROM_QSTR(MP_QSTR_encrypted), MP_ROM_PTR(&espnow_peer_encrypted_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(espnow_peer_locals_dict, espnow_peer_locals_dict_table); + +const mp_obj_type_t espnow_peer_type = { + { &mp_type_type }, + .name = MP_QSTR_Peer, + .make_new = espnow_peer_make_new, + .locals_dict = (mp_obj_t)&espnow_peer_locals_dict, +}; diff --git a/ports/espressif/bindings/espnow/Peer.h b/ports/espressif/bindings/espnow/Peer.h new file mode 100644 index 0000000000..e4cb828472 --- /dev/null +++ b/ports/espressif/bindings/espnow/Peer.h @@ -0,0 +1,37 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +#include "esp_now.h" + +typedef struct { + mp_obj_base_t base; + esp_now_peer_info_t peer_info; +} espnow_peer_obj_t; + +const mp_obj_type_t espnow_peer_type; diff --git a/ports/espressif/bindings/espnow/Peers.c b/ports/espressif/bindings/espnow/Peers.c new file mode 100644 index 0000000000..4f0c310f3d --- /dev/null +++ b/ports/espressif/bindings/espnow/Peers.c @@ -0,0 +1,221 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/objlist.h" +#include "py/runtime.h" + +#include "bindings/espnow/Peer.h" +#include "bindings/espnow/Peers.h" + +#include "esp_now.h" + +static void check_esp_err(esp_err_t status) { + if (status != ESP_OK) { + mp_raise_RuntimeError(translate("an error occured")); + } +} + +//| class Peers: +//| """A class that provides peer managment functions. Sequence[Peer].""" +//| + +//| def append(self, peer: Peer) -> None: +//| """Append peer. +//| +//| :param Peer peer: The peer object to append. +//| """ +//| ... +STATIC mp_obj_t espnow_peers_append(mp_obj_t self_in, mp_obj_t arg) { + espnow_peer_obj_t *peer = MP_OBJ_TO_PTR(mp_arg_validate_type(arg, &espnow_peer_type, MP_QSTR_Peer)); + check_esp_err(esp_now_add_peer(&peer->peer_info)); + espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_list_append(self->list, arg); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_peers_append_obj, espnow_peers_append); + +//| def remove(self, peer: Peer) -> None: +//| """Remove peer. +//| +//| :param Peer peer: The peer object to remove. +//| """ +//| ... +//| +STATIC mp_obj_t espnow_peers_remove(mp_obj_t self_in, mp_obj_t arg) { + espnow_peer_obj_t *peer = MP_OBJ_TO_PTR(mp_arg_validate_type(arg, &espnow_peer_type, MP_QSTR_Peer)); + check_esp_err(esp_now_del_peer(peer->peer_info.peer_addr)); + espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_list_remove(self->list, arg); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_peers_remove_obj, espnow_peers_remove); + +STATIC const mp_rom_map_elem_t espnow_peers_locals_dict_table[] = { + // Peer management functions + { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&espnow_peers_append_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&espnow_peers_remove_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(espnow_peers_locals_dict, espnow_peers_locals_dict_table); + +/******************************************************************************/ +/* peers print */ + +STATIC void espnow_peers_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); + const char *item_separator = ", "; + if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { + kind = PRINT_REPR; + } else { + #if MICROPY_PY_UJSON_SEPARATORS + item_separator = MP_PRINT_GET_EXT(print)->item_separator; + #endif + } + mp_print_str(print, "["); + for (size_t i = 0; i < list->len; i++) { + if (i > 0) { + mp_print_str(print, item_separator); + } + mp_obj_print_helper(print, list->items[i], kind); + } + mp_print_str(print, "]"); +} + +/******************************************************************************/ +/* peers unary_op */ + +STATIC mp_obj_t espnow_peers_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(list->len != 0); + case MP_UNARY_OP_LEN: + return MP_OBJ_NEW_SMALL_INT(list->len); + #if MICROPY_PY_SYS_GETSIZEOF + case MP_UNARY_OP_SIZEOF: { + size_t sz = sizeof(*list) + sizeof(mp_obj_t) * list->alloc; + return MP_OBJ_NEW_SMALL_INT(sz); + } + #endif + default: + return MP_OBJ_NULL; // op not supported + } +} + +/******************************************************************************/ +/* peers subscript */ + +STATIC mp_obj_t espnow_peers_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + if (value != MP_OBJ_SENTINEL) { + return MP_OBJ_NULL; // op not supported + } + + espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); + + // load + #if MICROPY_PY_BUILTINS_SLICE + if (mp_obj_is_type(index, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(list->len, index, &slice)) { + return mp_seq_extract_slice(list->len, list->items, &slice); + } + + mp_obj_list_t *res = MP_OBJ_TO_PTR(mp_obj_new_list(slice.stop - slice.start, NULL)); + mp_seq_copy(res->items, list->items + slice.start, res->len, mp_obj_t); + return MP_OBJ_FROM_PTR(res); + } + #endif + size_t index_val = mp_get_index(list->base.type, list->len, index, false); + return list->items[index_val]; +} + +/******************************************************************************/ +/* peers iterator */ + +typedef struct _espnow_peers_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_t peers; + size_t cur; +} espnow_peers_it_t; + +STATIC mp_obj_t espnow_peers_it_iternext(mp_obj_t self_in) { + espnow_peers_it_t *self = MP_OBJ_TO_PTR(self_in); + espnow_peers_obj_t *peers = MP_OBJ_TO_PTR(self->peers); + mp_obj_list_t *list = MP_OBJ_TO_PTR(peers->list); + if (self->cur < list->len) { + mp_obj_t o_out = list->items[self->cur]; + self->cur += 1; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +STATIC mp_obj_t espnow_peers_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(espnow_peers_it_t) <= sizeof(mp_obj_iter_buf_t)); + espnow_peers_it_t *o = (espnow_peers_it_t *)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = espnow_peers_it_iternext; + o->peers = o_in; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} + +espnow_peers_obj_t *espnow_peers_new(void) { + espnow_peers_obj_t *self = m_new_obj(espnow_peers_obj_t); + self->base.type = &espnow_peers_type; + self->list = mp_obj_new_list(0, NULL); + return self; +} + +const mp_obj_type_t espnow_peers_type = { + { &mp_type_type }, + .name = MP_QSTR_Peers, + .print = espnow_peers_print, + // .make_new = espnow_peers_make_new, + .locals_dict = (mp_obj_t)&espnow_peers_locals_dict, + .flags = MP_TYPE_FLAG_EXTENDED, + MP_TYPE_EXTENDED_FIELDS( + .unary_op = espnow_peers_unary_op, + .subscr = espnow_peers_subscr, + .getiter = espnow_peers_getiter, + ), +}; + +/* +STATIC mp_obj_t espnow_peers_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)type_in; + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + espnow_peers_obj_t *self = m_new_obj(espnow_peers_obj_t); + self->base.type = &espnow_peers_type; + self->list = mp_obj_new_list_from_iter(args[0]); + + return MP_OBJ_FROM_PTR(self); +} +*/ diff --git a/ports/espressif/bindings/espnow/Peers.h b/ports/espressif/bindings/espnow/Peers.h new file mode 100644 index 0000000000..e871ae86c0 --- /dev/null +++ b/ports/espressif/bindings/espnow/Peers.h @@ -0,0 +1,37 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t list; +} espnow_peers_obj_t; + +extern const mp_obj_type_t espnow_peers_type; +extern espnow_peers_obj_t *espnow_peers_new(void); diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c index 746e9696a9..d92221c691 100644 --- a/ports/espressif/bindings/espnow/__init__.c +++ b/ports/espressif/bindings/espnow/__init__.c @@ -29,6 +29,8 @@ #include "bindings/espnow/__init__.h" #include "bindings/espnow/ESPNow.h" #include "bindings/espnow/ESPNowPacket.h" +#include "bindings/espnow/Peer.h" +#include "bindings/espnow/Peers.h" //| """ESP-NOW Module //| @@ -44,14 +46,13 @@ //| import espnow //| //| e = espnow.ESPNow() -//| e.active(True) -//| peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' # MAC address of peer's wifi interface -//| e.add_peer(peer) +//| peer = espnow.Peer(mac=b'\xaa\xaa\xaa\xaa\xaa\xaa') +//| e.peers.append(peer) //| -//| e.send("Starting...") # Send to all peers +//| e.send("Starting...") //| for i in range(100): //| e.send(peer, str(i)*20, True) -//| e.send(b'end') +//| e.send(b'end') //| //| **Receiver** //| @@ -60,16 +61,18 @@ //| import espnow //| //| e = espnow.ESPNow() -//| e.active(True) -//| peer = b'\xaa\xaa\xaa\xaa\xaa\xaa' # MAC address of peer's wifi interface -//| e.add_peer(peer) +//| packets = [] //| //| while True: -//| host, msg = e.recv() -//| if msg: # msg == None if timeout in recv() -//| print(host, msg) -//| if msg == b'end': +//| if e: +//| packet = e.recv() +//| packets.append(packet) +//| if packet.msg == b'end': //| break +//| +//| print("packets:", f"length={len(packets)}") +//| for packet in packets: +//| print(packet) //| """ //| ... //| @@ -81,6 +84,8 @@ STATIC const mp_rom_map_elem_t espnow_module_globals_table[] = { // module classes { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&espnow_type) }, { MP_ROM_QSTR(MP_QSTR_ESPNowPacket),MP_ROM_PTR(&espnow_packet_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_Peer), MP_ROM_PTR(&espnow_peer_type) }, + { MP_ROM_QSTR(MP_QSTR_Peers), MP_ROM_PTR(&espnow_peers_type) }, }; STATIC MP_DEFINE_CONST_DICT(espnow_module_globals, espnow_module_globals_table); diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index 6e49f5f54a..e906c2a9d6 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -123,7 +123,7 @@ static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { } bool common_hal_espnow_deinited(espnow_obj_t *self) { - return self->recv_buffer == NULL; + return self == NULL || self->recv_buffer == NULL; } // Initialize the ESP-NOW software stack, @@ -154,7 +154,7 @@ void common_hal_espnow_init(espnow_obj_t *self) { // De-initialize the ESP-NOW software stack, // disable callbacks and deallocate the recv data buffers. void common_hal_espnow_deinit(espnow_obj_t *self) { - if (self == NULL || common_hal_espnow_deinited(self)) { + if (common_hal_espnow_deinited(self)) { return; } @@ -164,7 +164,7 @@ void common_hal_espnow_deinit(espnow_obj_t *self) { self->recv_buffer->buf = NULL; self->recv_buffer = NULL; - self->peers_count = 0; // esp_now_deinit() removes all peers. + // self->peers_count = 0; // esp_now_deinit() removes all peers. self->tx_packets = self->tx_responses; } @@ -278,7 +278,7 @@ mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const bool sync, const uint8 // Increment the sent packet count. // If mac == NULL msg will be sent to all peers EXCEPT any broadcast or multicast addresses. - self->tx_packets += ((mac == NULL) ? self->peers_count : 1); + self->tx_packets += ((mac == NULL) ? ((mp_obj_list_t *)self->peers->list)->len : 1); if (sync) { // Wait for and tally all the expected responses from peers diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h index 54761c00df..85108af7a7 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.h +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -24,8 +24,13 @@ * THE SOFTWARE. */ +#pragma once + +#include "py/obj.h" #include "py/ringbuf.h" +#include "bindings/espnow/Peers.h" + #include "esp_wifi.h" // The data structure for the espnow_singleton. @@ -39,7 +44,7 @@ typedef struct _espnow_obj_t { size_t tx_packets; // # of sent packets volatile size_t tx_responses; // # of sent packet responses received volatile size_t tx_failures; // # of sent packet responses failed - size_t peers_count; // Cache the # of peers for send(sync=True) + espnow_peers_obj_t *peers; // Cache the # of peers for send(sync=True) mp_obj_t peers_table; // A dictionary of discovered peers } espnow_obj_t; From f100838ae56aa8e2ecbc00c039c35be80c91b8e1 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 3 Feb 2023 10:14:50 +0530 Subject: [PATCH 09/29] remove `peers_table` from espnow --- ports/espressif/bindings/espnow/ESPNow.c | 24 -------- ports/espressif/common-hal/espnow/ESPNow.c | 72 +++++----------------- ports/espressif/common-hal/espnow/ESPNow.h | 1 - 3 files changed, 15 insertions(+), 82 deletions(-) diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 9a1ddfb80f..622f80020d 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -95,10 +95,6 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t common_hal_espnow_set_phy_rate(self, args[ARG_phy_rate].u_int); self->peers = espnow_peers_new(); - self->peers_table = mp_obj_new_dict(0); - - // Prevent user code modifying the dict - mp_obj_dict_get_map(self->peers_table)->is_fixed = 1; // Set the global singleton pointer for the espnow protocol. MP_STATE_PORT(espnow_singleton) = self; @@ -277,25 +273,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_obj, espnow_get_peers); MP_PROPERTY_GETTER(espnow_peers_obj, (mp_obj_t)&espnow_get_peers_obj); -//| peers_table: Dict[bytes, List[int]] -//| """The dictionary of peers we have seen. (read-only) -//| -//| A `dict` of {peer: [rssi, time], ...} -//| -//| where: -//| * peer is a byte string containing the 6-byte mac address of the peer. -//| * rssi is the wifi signal strength from the last msg received (in dBm from -127 to 0). -//| * time is the time in milliseconds since device last booted.""" -//| -STATIC mp_obj_t espnow_get_peers_table(mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return self->peers_table; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_table_obj, espnow_get_peers_table); - -MP_PROPERTY_GETTER(espnow_peers_table_obj, - (mp_obj_t)&espnow_get_peers_table_obj); - STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { // Context managers { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, @@ -316,7 +293,6 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { // Peer related properties { MP_ROM_QSTR(MP_QSTR_peers), MP_ROM_PTR(&espnow_peers_obj) }, - { MP_ROM_QSTR(MP_QSTR_peers_table), MP_ROM_PTR(&espnow_peers_table_obj) }, }; STATIC MP_DEFINE_CONST_DICT(espnow_locals_dict, espnow_locals_dict_table); diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index e906c2a9d6..a9e2e45f1f 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -95,7 +95,21 @@ static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { } } -static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg); +// Get the RSSI value from the wifi packet header +static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { + // Warning: Secret magic to get the rssi from the wifi packet header + // See espnow.c:espnow_recv_cb() at https://github.com/espressif/esp-now/ + // In the wifi packet the msg comes after a wifi_promiscuous_pkt_t + // and a espnow_frame_format_t. + // Backtrack to get a pointer to the wifi_promiscuous_pkt_t. + #define SIZEOF_ESPNOW_FRAME_FORMAT 39 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + wifi_promiscuous_pkt_t *wifi_packet = (wifi_promiscuous_pkt_t *)( + msg - SIZEOF_ESPNOW_FRAME_FORMAT - sizeof(wifi_promiscuous_pkt_t)); + #pragma GCC diagnostic pop + return wifi_packet->rx_ctrl.rssi; +} // Callback triggered when an ESP-NOW packet is received. // Write the peer MAC address and the message into the recv_buffer as an ESPNow packet. @@ -185,59 +199,6 @@ void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key) { check_esp_err(esp_now_set_pmk(key)); } -// --- Maintaining the peer table and reading RSSI values --- - -// We maintain a peers table for several reasons, to: -// - support monitoring the RSSI values for all peers; and -// - to return unique bytestrings for each peer which supports more efficient -// application memory usage and peer handling. - -// Get the RSSI value from the wifi packet header -static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { - // Warning: Secret magic to get the rssi from the wifi packet header - // See espnow.c:espnow_recv_cb() at https://github.com/espressif/esp-now/ - // In the wifi packet the msg comes after a wifi_promiscuous_pkt_t - // and a espnow_frame_format_t. - // Backtrack to get a pointer to the wifi_promiscuous_pkt_t. - #define SIZEOF_ESPNOW_FRAME_FORMAT 39 - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - wifi_promiscuous_pkt_t *wifi_packet = (wifi_promiscuous_pkt_t *)( - msg - SIZEOF_ESPNOW_FRAME_FORMAT - sizeof(wifi_promiscuous_pkt_t)); - #pragma GCC diagnostic pop - return wifi_packet->rx_ctrl.rssi; -} - -// Lookup a peer in the peers table and return a reference to the item in the peers_table. -// Add peer to the table if it is not found (may alloc memory). Will not return NULL. -static mp_map_elem_t *_lookup_add_peer(espnow_obj_t *self, const uint8_t *peer) { - // We do not want to allocate any new memory in the case that the peer - // already exists in the peers_table (which is almost all the time). - // So, we use a byte string on the stack and look that up in the dict. - mp_map_t *map = mp_obj_dict_get_map(self->peers_table); - mp_obj_str_t peer_obj = {{&mp_type_bytes}, 0, ESP_NOW_ETH_ALEN, peer}; - mp_map_elem_t *item = mp_map_lookup(map, &peer_obj, MP_MAP_LOOKUP); - if (item == NULL) { - // If not found, add the peer using a new bytestring - map->is_fixed = 0; // Allow to modify the dict - mp_obj_t new_peer = mp_obj_new_bytes(peer, ESP_NOW_ETH_ALEN); - item = mp_map_lookup(map, new_peer, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - item->value = mp_obj_new_list(2, NULL); - map->is_fixed = 1; // Relock the dict - } - return item; -} - -// Update the peers table with the new rssi value from a received packet and -// return a reference to the item in the peers_table. -static void _update_rssi(espnow_obj_t *self, const uint8_t *peer, int8_t rssi, uint32_t time_ms) { - // Lookup the peer in the device table - mp_map_elem_t *item = _lookup_add_peer(self, peer); - mp_obj_list_t *list = MP_OBJ_TO_PTR(item->value); - list->items[0] = MP_OBJ_NEW_SMALL_INT(rssi); - list->items[1] = mp_obj_new_int(time_ms); -} - // --- Send and Receive ESP-NOW data --- // Used by espnow_send() for sends() with sync==True. @@ -313,9 +274,6 @@ mp_obj_t common_hal_espnow_recv(espnow_obj_t *self) { mp_arg_error_invalid(MP_QSTR_buffer); } - // Update rssi value in the peer device table - _update_rssi(self, mac_buf, header.rssi, header.time_ms); - mp_obj_t elems[4] = { mp_obj_new_bytes(mac_buf, ESP_NOW_ETH_ALEN), mp_obj_new_bytes(msg_buf, msg_len), diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h index 85108af7a7..63d5f94f26 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.h +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -45,7 +45,6 @@ typedef struct _espnow_obj_t { volatile size_t tx_responses; // # of sent packet responses received volatile size_t tx_failures; // # of sent packet responses failed espnow_peers_obj_t *peers; // Cache the # of peers for send(sync=True) - mp_obj_t peers_table; // A dictionary of discovered peers } espnow_obj_t; extern void espnow_reset(void); From e30126e335abcdd078db2ec14cf1a30d5dc6cdbf Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 3 Feb 2023 11:08:13 +0530 Subject: [PATCH 10/29] remove `sync` from espnow --- ports/espressif/bindings/espnow/ESPNow.c | 13 +------ ports/espressif/common-hal/espnow/ESPNow.c | 43 ++-------------------- ports/espressif/common-hal/espnow/ESPNow.h | 2 +- 3 files changed, 7 insertions(+), 51 deletions(-) diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 622f80020d..07e80c3b67 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -205,18 +205,11 @@ MP_PROPERTY_GETTER(espnow_stats_obj, //| self, //| message: ReadableBuffer, //| mac: Optional[ReadableBuffer], -//| sync: bool = True, //| ) -> bool: -//| """Send a message to the peer's mac address. Optionally wait for a response. +//| """Send a message to the peer's mac address. //| //| :param ReadableBuffer message: The message to send (length <= 250 bytes). //| :param ReadableBuffer mac: The peer's address (length = 6 bytes). If `None` or any non-true value, send to all registered peers. -//| :param bool sync: If `True`, wait for response from peer(s) after sending. -//| -//| :returns: -//| `True` if sync == `False` and message sent successfully. -//| `True` if sync == `True` and message is received successfully by all recipients -//| `False` if sync == `True` and message is not received by at least one recipient //| //| :raises EAGAIN: if the internal espnow buffers are full.""" //| ... @@ -225,7 +218,6 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k static const mp_arg_t allowed_args[] = { { MP_QSTR_message, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_mac, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_sync, MP_ARG_BOOL, { .u_bool = mp_const_true } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -234,14 +226,13 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k espnow_obj_t *self = pos_args[0]; check_for_deinit(self); - const bool sync = mp_obj_is_true(args[ARG_sync].u_obj); const uint8_t *peer_addr = _get_peer_addr(args[ARG_mac].u_obj); // Get a pointer to the data buffer of the message mp_buffer_info_t message; mp_get_buffer_raise(args[ARG_message].u_obj, &message, MP_BUFFER_READ); - return common_hal_espnow_send(self, sync, peer_addr, &message); + return common_hal_espnow_send(self, peer_addr, &message); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index a9e2e45f1f..b95258f5f5 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -49,12 +49,7 @@ #define DEFAULT_RECV_BUFFER_SIZE (2 * MAX_PACKET_LEN) // Time to wait (millisec) for responses from sent packets: (2 seconds). -#define DEFAULT_SEND_TIMEOUT_MS (2 * 1000) - -// Number of milliseconds to wait for pending responses to sent packets. -// This is a fallback which should never be reached. -#define PENDING_RESPONSES_TIMEOUT_MS 100 -#define PENDING_RESPONSES_BUSY_POLL_MS 10 +#define DEFAULT_SEND_TIMEOUT_MS (1000) // ESPNow packet format for the receive buffer. // Use this for peeking at the header of the next packet in the buffer. @@ -201,34 +196,10 @@ void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key) { // --- Send and Receive ESP-NOW data --- -// Used by espnow_send() for sends() with sync==True. -// Wait till all pending sent packet responses have been received. -// ie. self->tx_responses == self->tx_packets. -static void _wait_for_pending_responses(espnow_obj_t *self) { - mp_uint_t t, start = mp_hal_ticks_ms(); - while (self->tx_responses < self->tx_packets) { - if ((t = mp_hal_ticks_ms() - start) > PENDING_RESPONSES_TIMEOUT_MS) { - mp_raise_OSError(MP_ETIMEDOUT); - } - if (t > PENDING_RESPONSES_BUSY_POLL_MS) { - // After 10ms of busy waiting give other tasks a look in. - RUN_BACKGROUND_TASKS; - } - } -} -mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const bool sync, const uint8_t *mac, const mp_buffer_info_t *message) { - if (sync) { - // Flush out any pending responses. - // If the last call was sync == False there may be outstanding responses - // still to be received (possible many if we just had a burst of unsync send()s). - // We need to wait for all pending responses if this call has sync = True. - _wait_for_pending_responses(self); - } - - // Send the packet - try, try again if internal esp-now buffers are full. +mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const uint8_t *mac, const mp_buffer_info_t *message) { + // Send the packet - keep trying until timeout if the internal esp-now buffers are full. esp_err_t err; - size_t saved_failures = self->tx_failures; mp_uint_t start = mp_hal_ticks_ms(); while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(mac, message->buf, message->len))) && @@ -241,13 +212,7 @@ mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const bool sync, const uint8 // If mac == NULL msg will be sent to all peers EXCEPT any broadcast or multicast addresses. self->tx_packets += ((mac == NULL) ? ((mp_obj_list_t *)self->peers->list)->len : 1); - if (sync) { - // Wait for and tally all the expected responses from peers - _wait_for_pending_responses(self); - } - - // Return False if sync and any peers did not respond. - return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures)); + return mp_const_none; } mp_obj_t common_hal_espnow_recv(espnow_obj_t *self) { diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h index 63d5f94f26..02ca90d5c4 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.h +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -57,5 +57,5 @@ extern void common_hal_espnow_set_buffer_size(espnow_obj_t *self, mp_int_t value extern void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value); extern void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key); -extern mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const bool sync, const uint8_t *mac, const mp_buffer_info_t *message); +extern mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const uint8_t *mac, const mp_buffer_info_t *message); extern mp_obj_t common_hal_espnow_recv(espnow_obj_t *self); From cac90a6969a02c7879764c80c672af4b4eb75708 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 3 Feb 2023 12:35:06 +0530 Subject: [PATCH 11/29] refactor common espnow functions --- ports/espressif/bindings/espnow/ESPNow.c | 20 ++--------- ports/espressif/bindings/espnow/Peer.c | 24 +++---------- ports/espressif/common-hal/espnow/__init__.c | 37 ++++++++++++++++++++ ports/espressif/common-hal/espnow/__init__.h | 30 ++++++++++++++++ 4 files changed, 75 insertions(+), 36 deletions(-) create mode 100644 ports/espressif/common-hal/espnow/__init__.c create mode 100644 ports/espressif/common-hal/espnow/__init__.h diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 07e80c3b67..39eb7a5019 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -36,25 +36,11 @@ #include "shared-bindings/util.h" +#include "common-hal/espnow/__init__.h" #include "common-hal/espnow/ESPNow.h" #include "esp_now.h" -// Return C pointer to byte memory string/bytes/bytearray in obj. -// Raise ValueError if the length does not match expected len. -static const uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(obj, &bufinfo, rw); - mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); - return (uint8_t *)bufinfo.buf; -} - -// Return C pointer to the MAC address. -// Raise ValueError if mac is wrong type or is not 6 bytes long. -static const uint8_t *_get_peer_addr(mp_obj_t mac) { - return mp_obj_is_true(mac) ? _get_bytes_len(mac, ESP_NOW_ETH_ALEN, MP_BUFFER_READ) : NULL; -} - // --- Initialisation and Config functions --- static void check_for_deinit(espnow_obj_t *self) { @@ -136,7 +122,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow___exit___obj, 4, 4, espnow_obj //| ... STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_set_pmk(self, _get_bytes_len(key, ESP_NOW_KEY_LEN, MP_BUFFER_READ)); + common_hal_espnow_set_pmk(self, common_hal_espnow_get_bytes_len(key, ESP_NOW_KEY_LEN)); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); @@ -226,7 +212,7 @@ STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k espnow_obj_t *self = pos_args[0]; check_for_deinit(self); - const uint8_t *peer_addr = _get_peer_addr(args[ARG_mac].u_obj); + const uint8_t *peer_addr = common_hal_espnow_get_bytes_len(args[ARG_mac].u_obj, ESP_NOW_ETH_ALEN); // Get a pointer to the data buffer of the message mp_buffer_info_t message; diff --git a/ports/espressif/bindings/espnow/Peer.c b/ports/espressif/bindings/espnow/Peer.c index 6dcf2732aa..7b6cc5f668 100644 --- a/ports/espressif/bindings/espnow/Peer.c +++ b/ports/espressif/bindings/espnow/Peer.c @@ -29,25 +29,11 @@ #include "py/runtime.h" #include "bindings/espnow/Peer.h" +#include "common-hal/espnow/__init__.h" // TODO: check peer already exist // TODO: check peer dosen't exist -// Return C pointer to the ReadableBuffer. -// Raise ValueError if the length does not match expected len. -static const uint8_t *_get_bytes_len(mp_obj_t obj, size_t len, mp_uint_t rw) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(obj, &bufinfo, rw); - mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); - return (uint8_t *)bufinfo.buf; -} - -// Return C pointer to the MAC address. -// Raise ValueError if mac is wrong type or is not 6 bytes long. -static const uint8_t *_get_peer_addr(mp_obj_t mac) { - return mp_obj_is_true(mac) ? _get_bytes_len(mac, ESP_NOW_ETH_ALEN, MP_BUFFER_READ) : NULL; -} - //| class Peer: //| """A data class to store parameters specific to a peer.""" //| @@ -89,7 +75,7 @@ STATIC mp_obj_t espnow_peer_make_new(const mp_obj_type_t *type, size_t n_args, s .encrypt = false }; - memcpy(self->peer_info.peer_addr, _get_peer_addr(args[ARG_mac].u_obj), ESP_NOW_ETH_ALEN); + memcpy(self->peer_info.peer_addr, common_hal_espnow_get_bytes_len(args[ARG_mac].u_obj, ESP_NOW_ETH_ALEN), ESP_NOW_ETH_ALEN); const mp_obj_t channel = args[ARG_channel].u_obj; if (channel != mp_const_none) { @@ -108,7 +94,7 @@ STATIC mp_obj_t espnow_peer_make_new(const mp_obj_type_t *type, size_t n_args, s const mp_obj_t lmk = args[ARG_lmk].u_obj; if (lmk != mp_const_none) { - memcpy(self->peer_info.lmk, _get_bytes_len(lmk, ESP_NOW_KEY_LEN, MP_BUFFER_READ), ESP_NOW_KEY_LEN); + memcpy(self->peer_info.lmk, common_hal_espnow_get_bytes_len(lmk, ESP_NOW_KEY_LEN), ESP_NOW_KEY_LEN); } else if (self->peer_info.encrypt && !self->peer_info.lmk) { mp_raise_ValueError_varg(translate("%q is %q"), MP_QSTR_lmk, MP_QSTR_None); } @@ -128,7 +114,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_get_mac_obj, espnow_peer_get_mac); STATIC mp_obj_t espnow_peer_set_mac(const mp_obj_t self_in, const mp_obj_t value) { espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); - memcpy(self->peer_info.peer_addr, _get_peer_addr(value), ESP_NOW_ETH_ALEN); + memcpy(self->peer_info.peer_addr, common_hal_espnow_get_bytes_len(value, ESP_NOW_ETH_ALEN), ESP_NOW_ETH_ALEN); esp_now_mod_peer(&self->peer_info); return mp_const_none; @@ -151,7 +137,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_get_lmk_obj, espnow_peer_get_lmk); STATIC mp_obj_t espnow_peer_set_lmk(const mp_obj_t self_in, const mp_obj_t value) { espnow_peer_obj_t *self = MP_OBJ_TO_PTR(self_in); - memcpy(self->peer_info.lmk, _get_bytes_len(value, ESP_NOW_KEY_LEN, MP_BUFFER_READ), ESP_NOW_KEY_LEN); + memcpy(self->peer_info.lmk, common_hal_espnow_get_bytes_len(value, ESP_NOW_KEY_LEN), ESP_NOW_KEY_LEN); esp_now_mod_peer(&self->peer_info); return mp_const_none; diff --git a/ports/espressif/common-hal/espnow/__init__.c b/ports/espressif/common-hal/espnow/__init__.c new file mode 100644 index 0000000000..498cd49dc9 --- /dev/null +++ b/ports/espressif/common-hal/espnow/__init__.c @@ -0,0 +1,37 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "common-hal/espnow/__init__.h" +#include "py/runtime.h" + +// Return C pointer to byte memory string/bytes/bytearray in obj. +// Raise ValueError if the length does not match expected len. +const uint8_t *common_hal_espnow_get_bytes_len(mp_obj_t obj, size_t len) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(bufinfo.len, len, MP_QSTR_buffer); + return (uint8_t *)bufinfo.buf; +} diff --git a/ports/espressif/common-hal/espnow/__init__.h b/ports/espressif/common-hal/espnow/__init__.h new file mode 100644 index 0000000000..bb1950d98c --- /dev/null +++ b/ports/espressif/common-hal/espnow/__init__.h @@ -0,0 +1,30 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +extern const uint8_t *common_hal_espnow_get_bytes_len(mp_obj_t obj, size_t len); From a1644f15ea7278cdf2fb96a25f549bafc3d8c8a9 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 3 Feb 2023 15:42:44 +0530 Subject: [PATCH 12/29] use esp error for espnow --- locale/circuitpython.pot | 32 +++---- ports/espressif/Makefile | 10 ++- ports/espressif/bindings/espnow/Peers.c | 12 +-- ports/espressif/common-hal/espidf/__init__.c | 9 +- ports/espressif/common-hal/espnow/ESPNow.c | 30 +++---- ports/espressif/esp_error.c | 91 -------------------- 6 files changed, 46 insertions(+), 138 deletions(-) delete mode 100644 ports/espressif/esp_error.c diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 10993652aa..4337991721 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -222,7 +222,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "" @@ -680,7 +680,7 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1067,7 +1067,7 @@ msgstr "" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1235,8 +1235,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "" @@ -1266,7 +1265,7 @@ msgstr "" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1275,7 +1274,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1307,7 +1306,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1667,11 +1666,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1679,7 +1678,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1855,7 +1854,7 @@ msgstr "" msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1875,7 +1874,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2341,7 +2340,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" @@ -2431,11 +2430,6 @@ msgstr "" msgid "addresses is empty" msgstr "" -#: ports/espressif/bindings/espnow/Peers.c -#: ports/espressif/common-hal/espnow/ESPNow.c -msgid "an error occured" -msgstr "" - #: py/compile.c msgid "annotation must be an identifier" msgstr "" diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index d844fc88bd..cc6d451153 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -218,7 +218,6 @@ endif SRC_C += \ background.c \ mphalport.c \ - bindings/espidf/__init__.c \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ shared/netutils/netutils.c \ @@ -252,8 +251,6 @@ ifneq ($(CIRCUITPY_BLEIO),0) SRC_C += common-hal/_bleio/ble_events.c endif -SRC_C += $(wildcard common-hal/espidf/*.c) - ifneq ($(CIRCUITPY_ESPCAMERA),0) SRC_CAMERA := \ $(wildcard common-hal/espcamera/*.c) \ @@ -263,6 +260,13 @@ CFLAGS += -isystem esp32-camera/driver/include CFLAGS += -isystem esp32-camera/conversions/include endif +ifneq ($(CIRCUITPY_ESPIDF),0) +SRC_ESPIDF := \ + $(wildcard common-hal/espidf/*.c) \ + $(wildcard bindings/espidf/*.c) +SRC_C += $(SRC_ESPIDF) +endif + ifneq ($(CIRCUITPY_ESPNOW),0) SRC_ESPNOW := \ $(wildcard common-hal/espnow/*.c) \ diff --git a/ports/espressif/bindings/espnow/Peers.c b/ports/espressif/bindings/espnow/Peers.c index 4f0c310f3d..13c44c3423 100644 --- a/ports/espressif/bindings/espnow/Peers.c +++ b/ports/espressif/bindings/espnow/Peers.c @@ -28,17 +28,13 @@ #include "py/objlist.h" #include "py/runtime.h" +#include "bindings/espidf/__init__.h" + #include "bindings/espnow/Peer.h" #include "bindings/espnow/Peers.h" #include "esp_now.h" -static void check_esp_err(esp_err_t status) { - if (status != ESP_OK) { - mp_raise_RuntimeError(translate("an error occured")); - } -} - //| class Peers: //| """A class that provides peer managment functions. Sequence[Peer].""" //| @@ -51,7 +47,7 @@ static void check_esp_err(esp_err_t status) { //| ... STATIC mp_obj_t espnow_peers_append(mp_obj_t self_in, mp_obj_t arg) { espnow_peer_obj_t *peer = MP_OBJ_TO_PTR(mp_arg_validate_type(arg, &espnow_peer_type, MP_QSTR_Peer)); - check_esp_err(esp_now_add_peer(&peer->peer_info)); + CHECK_ESP_RESULT(esp_now_add_peer(&peer->peer_info)); espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_list_append(self->list, arg); } @@ -66,7 +62,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_peers_append_obj, espnow_peers_append); //| STATIC mp_obj_t espnow_peers_remove(mp_obj_t self_in, mp_obj_t arg) { espnow_peer_obj_t *peer = MP_OBJ_TO_PTR(mp_arg_validate_type(arg, &espnow_peer_type, MP_QSTR_Peer)); - check_esp_err(esp_now_del_peer(peer->peer_info.peer_addr)); + CHECK_ESP_RESULT(esp_now_del_peer(peer->peer_info.peer_addr)); espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_list_remove(self->list, arg); } diff --git a/ports/espressif/common-hal/espidf/__init__.c b/ports/espressif/common-hal/espidf/__init__.c index 183ebb3817..d2d00ebc56 100644 --- a/ports/espressif/common-hal/espidf/__init__.c +++ b/ports/espressif/common-hal/espidf/__init__.c @@ -29,7 +29,9 @@ #include "supervisor/memory.h" #include "py/runtime.h" +#include "esp_now.h" #include "esp_log.h" + #define TAG "espidf" #ifdef CONFIG_SPIRAM @@ -180,14 +182,19 @@ void raise_esp_error(esp_err_t err) { // tests must be in descending order MP_STATIC_ASSERT(ESP_ERR_FLASH_BASE > ESP_ERR_MESH_BASE); - MP_STATIC_ASSERT(ESP_ERR_MESH_BASE > ESP_ERR_WIFI_BASE); + MP_STATIC_ASSERT(ESP_ERR_MESH_BASE > ESP_ERR_ESPNOW_BASE); + MP_STATIC_ASSERT(ESP_ERR_ESPNOW_BASE > ESP_ERR_WIFI_BASE); + if (err >= ESP_ERR_FLASH_BASE) { group = "Flash"; } else if (err >= ESP_ERR_MESH_BASE) { group = "Mesh"; + } else if (err >= ESP_ERR_ESPNOW_BASE) { + group = "ESP-NOW"; } else if (err >= ESP_ERR_WIFI_BASE) { group = "WiFi"; } + mp_raise_msg_varg(exception_type, translate("%s error 0x%x"), group, err); } diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index b95258f5f5..19c0e4a116 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -30,7 +30,9 @@ #include "py/mperrno.h" #include "py/runtime.h" +#include "bindings/espidf/__init__.h" #include "bindings/espnow/ESPNowPacket.h" + #include "shared-bindings/wifi/__init__.h" #include "common-hal/espnow/ESPNow.h" @@ -41,6 +43,8 @@ #define ESPNOW_MAGIC 0x99 +// TODO: deinit wifi? + // The maximum length of an espnow packet (bytes) #define MAX_PACKET_LEN (sizeof(espnow_packet_t) + ESP_NOW_MAX_DATA_LEN) @@ -66,12 +70,6 @@ typedef struct { uint8_t msg[0]; // Message is up to 250 bytes } __attribute__((packed)) espnow_packet_t; -static void check_esp_err(esp_err_t status) { - if (status != ESP_OK) { - mp_raise_RuntimeError(translate("an error occured")); - } -} - // Return a pointer to the ESPNow module singleton static espnow_obj_t *_get_singleton(void) { return MP_STATE_PORT(espnow_singleton); @@ -152,12 +150,12 @@ void common_hal_espnow_init(espnow_obj_t *self) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); } - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, self->phy_rate)); - check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, self->phy_rate)); + CHECK_ESP_RESULT(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, self->phy_rate)); + CHECK_ESP_RESULT(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, self->phy_rate)); - check_esp_err(esp_now_init()); - check_esp_err(esp_now_register_send_cb(send_cb)); - check_esp_err(esp_now_register_recv_cb(recv_cb)); + CHECK_ESP_RESULT(esp_now_init()); + CHECK_ESP_RESULT(esp_now_register_send_cb(send_cb)); + CHECK_ESP_RESULT(esp_now_register_recv_cb(recv_cb)); } // De-initialize the ESP-NOW software stack, @@ -167,9 +165,9 @@ void common_hal_espnow_deinit(espnow_obj_t *self) { return; } - check_esp_err(esp_now_unregister_send_cb()); - check_esp_err(esp_now_unregister_recv_cb()); - check_esp_err(esp_now_deinit()); + CHECK_ESP_RESULT(esp_now_unregister_send_cb()); + CHECK_ESP_RESULT(esp_now_unregister_recv_cb()); + CHECK_ESP_RESULT(esp_now_deinit()); self->recv_buffer->buf = NULL; self->recv_buffer = NULL; @@ -191,7 +189,7 @@ void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value) { }; void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key) { - check_esp_err(esp_now_set_pmk(key)); + CHECK_ESP_RESULT(esp_now_set_pmk(key)); } // --- Send and Receive ESP-NOW data --- @@ -206,7 +204,7 @@ mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const uint8_t *mac, const mp (mp_hal_ticks_ms() - start) <= DEFAULT_SEND_TIMEOUT_MS) { RUN_BACKGROUND_TASKS; } - check_esp_err(err); + CHECK_ESP_RESULT(err); // Increment the sent packet count. // If mac == NULL msg will be sent to all peers EXCEPT any broadcast or multicast addresses. diff --git a/ports/espressif/esp_error.c b/ports/espressif/esp_error.c deleted file mode 100644 index 4bc44674b7..0000000000 --- a/ports/espressif/esp_error.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "esp_error.h" -#include "py/runtime.h" - -#include "bindings/espidf/__init__.h" - -void raise_esp_error(esp_err_t err) { - const compressed_string_t *msg = NULL; - const mp_obj_type_t *exception_type = &mp_type_espidf_IDFError; - switch (err) { - case ESP_FAIL: - msg = translate("Generic Failure"); - break; - case ESP_ERR_NO_MEM: - exception_type = &mp_type_espidf_MemoryError; - msg = translate("Out of memory"); - break; - case ESP_ERR_INVALID_ARG: - msg = translate("Invalid argument"); - break; - case ESP_ERR_INVALID_STATE: - msg = translate("Invalid state"); - break; - case ESP_ERR_INVALID_SIZE: - msg = translate("Invalid size"); - break; - case ESP_ERR_NOT_FOUND: - msg = translate("Requested resource not found"); - break; - case ESP_ERR_NOT_SUPPORTED: - msg = translate("Operation or feature not supported"); - break; - case ESP_ERR_TIMEOUT: - msg = translate("Operation timed out"); - break; - case ESP_ERR_INVALID_RESPONSE: - msg = translate("Received response was invalid"); - break; - case ESP_ERR_INVALID_CRC: - msg = translate("CRC or checksum was invalid"); - break; - case ESP_ERR_INVALID_VERSION: - msg = translate("Version was invalid"); - break; - case ESP_ERR_INVALID_MAC: - msg = translate("MAC address was invalid"); - break; - } - if (msg) { - mp_raise_msg(exception_type, msg); - } - - const char *group = "ESP-IDF"; - - // tests must be in descending order - MP_STATIC_ASSERT(ESP_ERR_FLASH_BASE > ESP_ERR_MESH_BASE); - MP_STATIC_ASSERT(ESP_ERR_MESH_BASE > ESP_ERR_WIFI_BASE); - if (err >= ESP_ERR_FLASH_BASE) { - group = "Flash"; - } else if (err >= ESP_ERR_MESH_BASE) { - group = "Mesh"; - } else if (err >= ESP_ERR_WIFI_BASE) { - group = "WiFi"; - } - mp_raise_msg_varg(exception_type, translate("%s error 0x%x"), group, err); -} From ff95e9616099e2b7f14b46c69a556714d41359ed Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Sat, 4 Feb 2023 01:03:33 +0530 Subject: [PATCH 13/29] add `ESPNowStats` class and more --- ports/espressif/bindings/espnow/ESPNow.c | 81 +++++++++-------- .../espressif/bindings/espnow/ESPNowPacket.c | 4 +- ports/espressif/bindings/espnow/ESPNowStats.c | 87 +++++++++++++++++++ ports/espressif/bindings/espnow/ESPNowStats.h | 38 ++++++++ ports/espressif/bindings/espnow/Peers.c | 2 + ports/espressif/bindings/espnow/__init__.c | 4 +- ports/espressif/common-hal/espnow/ESPNow.c | 77 ++++++++-------- ports/espressif/common-hal/espnow/ESPNow.h | 11 ++- 8 files changed, 220 insertions(+), 84 deletions(-) create mode 100644 ports/espressif/bindings/espnow/ESPNowStats.c create mode 100644 ports/espressif/bindings/espnow/ESPNowStats.h diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 39eb7a5019..33bb882873 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -27,9 +27,8 @@ * THE SOFTWARE. */ -#include "py/runtime.h" -#include "py/objarray.h" #include "py/objproperty.h" +#include "py/runtime.h" #include "py/stream.h" #include "bindings/espnow/ESPNow.h" @@ -74,19 +73,15 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t mp_raise_RuntimeError(translate("Already running")); } + // Allocate a new object self = m_new_obj(espnow_obj_t); self->base.type = &espnow_type; - common_hal_espnow_set_buffer_size(self, args[ARG_buffer_size].u_int); - common_hal_espnow_set_phy_rate(self, args[ARG_phy_rate].u_int); - - self->peers = espnow_peers_new(); + // Construct the object + common_hal_espnow_construct(self, args[ARG_buffer_size].u_int, args[ARG_phy_rate].u_int); // Set the global singleton pointer for the espnow protocol. MP_STATE_PORT(espnow_singleton) = self; - - common_hal_espnow_init(self); - return self; } @@ -167,23 +162,29 @@ MP_PROPERTY_GETSET(espnow_phy_rate_obj, (mp_obj_t)&espnow_get_phy_rate_obj, (mp_obj_t)&espnow_set_phy_rate_obj); -//| stats: Tuple[int, int, int, int, int] -//| """Provide some useful stats in a `tuple` of -//| (tx_packets, tx_responses, tx_failures, rx_packets, rx_failures). (read-only)""" +//| tx_stats: ESPNowStats +//| """The ``TX`` packet statistics.""" //| -STATIC mp_obj_t espnow_get_stats(mp_obj_t self_in) { +STATIC mp_obj_t espnow_get_tx_stats(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_TUPLE( - mp_obj_new_int(self->tx_packets), - mp_obj_new_int(self->tx_responses), - mp_obj_new_int(self->tx_failures), - mp_obj_new_int(self->rx_packets), - mp_obj_new_int(self->rx_failures)); + return MP_OBJ_FROM_PTR(self->tx_stats); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_stats_obj, espnow_get_stats); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_tx_stats_obj, espnow_get_tx_stats); -MP_PROPERTY_GETTER(espnow_stats_obj, - (mp_obj_t)&espnow_get_stats_obj); +MP_PROPERTY_GETTER(espnow_tx_stats_obj, + (mp_obj_t)&espnow_get_tx_stats_obj); + +//| rx_stats: ESPNowStats +//| """The ``RX`` packet statistics.""" +//| +STATIC mp_obj_t espnow_get_rx_stats(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_FROM_PTR(self->rx_stats); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_rx_stats_obj, espnow_get_rx_stats); + +MP_PROPERTY_GETTER(espnow_rx_stats_obj, + (mp_obj_t)&espnow_get_rx_stats_obj); // --- Send and Receive ESP-NOW data --- @@ -195,9 +196,8 @@ MP_PROPERTY_GETTER(espnow_stats_obj, //| """Send a message to the peer's mac address. //| //| :param ReadableBuffer message: The message to send (length <= 250 bytes). -//| :param ReadableBuffer mac: The peer's address (length = 6 bytes). If `None` or any non-true value, send to all registered peers. -//| -//| :raises EAGAIN: if the internal espnow buffers are full.""" +//| :param ReadableBuffer mac: The peer's address (length = 6 bytes). +//| If `None` or any non-true value, send to all registered peers.""" //| ... STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_message, ARG_mac, ARG_sync }; @@ -255,6 +255,7 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&espnow___exit___obj) }, + // Deinit the object { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&espnow_deinit_obj) }, // Config parameters @@ -262,7 +263,9 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_buffer_size), MP_ROM_PTR(&espnow_buffer_size_obj) }, { MP_ROM_QSTR(MP_QSTR_phy_rate), MP_ROM_PTR(&espnow_phy_rate_obj) }, - { MP_ROM_QSTR(MP_QSTR_stats), MP_ROM_PTR(&espnow_stats_obj) }, + // Packet statistics + { MP_ROM_QSTR(MP_QSTR_tx_stats), MP_ROM_PTR(&espnow_tx_stats_obj) }, + { MP_ROM_QSTR(MP_QSTR_rx_stats), MP_ROM_PTR(&espnow_rx_stats_obj) }, // Send and receive messages { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, @@ -278,21 +281,25 @@ STATIC MP_DEFINE_CONST_DICT(espnow_locals_dict, espnow_locals_dict_table); // Support ioctl(MP_STREAM_POLL, ) for asyncio STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { - if (request != MP_STREAM_POLL) { - *errcode = MP_EINVAL; - return MP_STREAM_ERROR; - } - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return (common_hal_espnow_deinited(self)) ? 0 : // If not initialized - arg ^ ( - // If no data in the buffer, unset the Read ready flag - ((!ringbuf_num_filled(self->recv_buffer)) ? MP_STREAM_POLL_RD : 0) | - // If still waiting for responses, unset the Write ready flag - ((self->tx_responses < self->tx_packets) ? MP_STREAM_POLL_WR : 0)); + check_for_deinit(self); + switch (request) { + case MP_STREAM_POLL: { + mp_uint_t flags = arg; + mp_uint_t ret = 0; + if ((flags & MP_STREAM_POLL_RD) && ringbuf_num_filled(self->recv_buffer) > 0) { + ret |= MP_STREAM_POLL_RD; + } + return ret; + } + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } } STATIC const mp_stream_p_t espnow_stream_p = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream) .ioctl = espnow_stream_ioctl, }; diff --git a/ports/espressif/bindings/espnow/ESPNowPacket.c b/ports/espressif/bindings/espnow/ESPNowPacket.c index 9d582a00eb..7cbf2caed0 100644 --- a/ports/espressif/bindings/espnow/ESPNowPacket.c +++ b/ports/espressif/bindings/espnow/ESPNowPacket.c @@ -27,7 +27,7 @@ #include "bindings/espnow/ESPNowPacket.h" //| class ESPNowPacket: -//| """A packet retreived from ESP-NOW communication protocol""" +//| """A packet retrieved from ESP-NOW communication protocol""" //| //| mac: ReadableBuffer //| """The sender's mac address (length = 6 bytes)""" @@ -39,7 +39,7 @@ //| """The received signal strength indication (in dBm from -127 to 0)""" //| //| time: int -//| """The is the time in milliseconds since device last booted""" +//| """The time in milliseconds since the device last booted when the packet was received""" //| const mp_obj_namedtuple_type_t espnow_packet_type_obj = { diff --git a/ports/espressif/bindings/espnow/ESPNowStats.c b/ports/espressif/bindings/espnow/ESPNowStats.c new file mode 100644 index 0000000000..babd8e4d83 --- /dev/null +++ b/ports/espressif/bindings/espnow/ESPNowStats.c @@ -0,0 +1,87 @@ +/* + * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "bindings/espnow/ESPNowStats.h" +#include "py/objproperty.h" + +//| class ESPNowStats: +//| """Provide some useful packet tx/rx statistics.""" +//| + +//| success: int +//| """The number of successes. (read-only) +//| +//| * In case of transmit ``TX``: +//| The number of tx packets received by the peer(s) ``ESP_NOW_SEND_SUCCESS``. +//| +//| * In case of receive ``RX``: +//| The number of rx packets captured in the buffer.""" +//| +STATIC mp_obj_t espnow_stats_get_success(const mp_obj_t self_in) { + espnow_stats_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->success); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_stats_get_success_obj, espnow_stats_get_success); + +MP_PROPERTY_GETTER(espnow_stats_success_obj, + (mp_obj_t)&espnow_stats_get_success_obj); + +//| failure: int +//| """The number of failures. (read-only) +//| +//| * In case of transmit ``TX``: +//| The number of failed tx packets ``ESP_NOW_SEND_FAIL``. +//| +//| * In case of receive ``RX``: +//| The number of dropped rx packets due to buffer overflow.""" +//| +STATIC mp_obj_t espnow_stats_get_failure(const mp_obj_t self_in) { + espnow_stats_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->failure); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_stats_get_failure_obj, espnow_stats_get_failure); + +MP_PROPERTY_GETTER(espnow_stats_failure_obj, + (mp_obj_t)&espnow_stats_get_failure_obj); + +STATIC const mp_rom_map_elem_t espnow_stats_locals_dict_table[] = { + // Peer parameters + { MP_ROM_QSTR(MP_QSTR_success), MP_ROM_PTR(&espnow_stats_success_obj) }, + { MP_ROM_QSTR(MP_QSTR_failure), MP_ROM_PTR(&espnow_stats_failure_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(espnow_stats_locals_dict, espnow_stats_locals_dict_table); + +espnow_stats_obj_t *espnow_stats_new(void) { + espnow_stats_obj_t *self = m_new_obj(espnow_stats_obj_t); + self->base.type = &espnow_stats_type; + return self; +} + +const mp_obj_type_t espnow_stats_type = { + { &mp_type_type }, + .name = MP_QSTR_ESPNowStats, + .locals_dict = (mp_obj_t)&espnow_stats_locals_dict, +}; diff --git a/ports/espressif/bindings/espnow/ESPNowStats.h b/ports/espressif/bindings/espnow/ESPNowStats.h new file mode 100644 index 0000000000..a9a578a8bf --- /dev/null +++ b/ports/espressif/bindings/espnow/ESPNowStats.h @@ -0,0 +1,38 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + volatile size_t success; + volatile size_t failure; +} espnow_stats_obj_t; + +const mp_obj_type_t espnow_stats_type; +extern espnow_stats_obj_t *espnow_stats_new(void); diff --git a/ports/espressif/bindings/espnow/Peers.c b/ports/espressif/bindings/espnow/Peers.c index 13c44c3423..843bff644a 100644 --- a/ports/espressif/bindings/espnow/Peers.c +++ b/ports/espressif/bindings/espnow/Peers.c @@ -35,6 +35,8 @@ #include "esp_now.h" +// TODO: Check for deinit + //| class Peers: //| """A class that provides peer managment functions. Sequence[Peer].""" //| diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c index d92221c691..f64a6433dd 100644 --- a/ports/espressif/bindings/espnow/__init__.c +++ b/ports/espressif/bindings/espnow/__init__.c @@ -29,6 +29,7 @@ #include "bindings/espnow/__init__.h" #include "bindings/espnow/ESPNow.h" #include "bindings/espnow/ESPNowPacket.h" +#include "bindings/espnow/ESPNowStats.h" #include "bindings/espnow/Peer.h" #include "bindings/espnow/Peers.h" @@ -51,7 +52,7 @@ //| //| e.send("Starting...") //| for i in range(100): -//| e.send(peer, str(i)*20, True) +//| e.send(str(i)*20) //| e.send(b'end') //| //| **Receiver** @@ -84,6 +85,7 @@ STATIC const mp_rom_map_elem_t espnow_module_globals_table[] = { // module classes { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&espnow_type) }, { MP_ROM_QSTR(MP_QSTR_ESPNowPacket),MP_ROM_PTR(&espnow_packet_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_ESPNowStats), MP_ROM_PTR(&espnow_stats_type) }, { MP_ROM_QSTR(MP_QSTR_Peer), MP_ROM_PTR(&espnow_peer_type) }, { MP_ROM_QSTR(MP_QSTR_Peers), MP_ROM_PTR(&espnow_peers_type) }, }; diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index 19c0e4a116..96a7cfdfaa 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -45,14 +45,15 @@ // TODO: deinit wifi? -// The maximum length of an espnow packet (bytes) +// The min/max length of an espnow packet (bytes) +#define MIN_PACKET_LEN (sizeof(espnow_packet_t)) #define MAX_PACKET_LEN (sizeof(espnow_packet_t) + ESP_NOW_MAX_DATA_LEN) // Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes // Will allocate an additional 7 bytes for buffer overhead #define DEFAULT_RECV_BUFFER_SIZE (2 * MAX_PACKET_LEN) -// Time to wait (millisec) for responses from sent packets: (2 seconds). +// Time to wait (millisec) for responses from sent packets: (1 seconds). #define DEFAULT_SEND_TIMEOUT_MS (1000) // ESPNow packet format for the receive buffer. @@ -70,27 +71,34 @@ typedef struct { uint8_t msg[0]; // Message is up to 250 bytes } __attribute__((packed)) espnow_packet_t; -// Return a pointer to the ESPNow module singleton -static espnow_obj_t *_get_singleton(void) { - return MP_STATE_PORT(espnow_singleton); -} - // --- The ESP-NOW send and recv callback routines --- // Callback triggered when a sent packet is acknowledged by the peer (or not). // Just count the number of responses and number of failures. // These are used in the send() logic. static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { - espnow_obj_t *self = _get_singleton(); - self->tx_responses++; - if (status != ESP_NOW_SEND_SUCCESS) { - self->tx_failures++; + espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); + if (status == ESP_NOW_SEND_SUCCESS) { + self->tx_stats->success++; + } else { + self->tx_stats->failure++; } } -// Get the RSSI value from the wifi packet header -static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { - // Warning: Secret magic to get the rssi from the wifi packet header +// Callback triggered when an ESP-NOW packet is received. +// Write the peer MAC address and the message into the recv_buffer as an ESPNow packet. +// If the buffer is full, drop the message and increment the dropped count. +static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { + espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); + ringbuf_t *buf = self->recv_buffer; + + if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { + self->rx_stats->failure++; + return; + } + + // Get the RSSI value from the wifi packet header + // Secret magic to get the rssi from the wifi packet header // See espnow.c:espnow_recv_cb() at https://github.com/espressif/esp-now/ // In the wifi packet the msg comes after a wifi_promiscuous_pkt_t // and a espnow_frame_format_t. @@ -101,38 +109,37 @@ static inline int8_t _get_rssi_from_wifi_packet(const uint8_t *msg) { wifi_promiscuous_pkt_t *wifi_packet = (wifi_promiscuous_pkt_t *)( msg - SIZEOF_ESPNOW_FRAME_FORMAT - sizeof(wifi_promiscuous_pkt_t)); #pragma GCC diagnostic pop - return wifi_packet->rx_ctrl.rssi; -} - -// Callback triggered when an ESP-NOW packet is received. -// Write the peer MAC address and the message into the recv_buffer as an ESPNow packet. -// If the buffer is full, drop the message and increment the dropped count. -static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { - espnow_obj_t *self = _get_singleton(); - ringbuf_t *buf = self->recv_buffer; - - if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { - self->rx_failures++; - return; - } espnow_header_t header; header.magic = ESPNOW_MAGIC; header.msg_len = msg_len; - header.rssi = _get_rssi_from_wifi_packet(msg); + header.rssi = wifi_packet->rx_ctrl.rssi; header.time_ms = mp_hal_ticks_ms(); ringbuf_put_n(buf, (uint8_t *)&header, sizeof(header)); ringbuf_put_n(buf, mac, ESP_NOW_ETH_ALEN); ringbuf_put_n(buf, msg, msg_len); - self->rx_packets++; + self->rx_stats->success++; } bool common_hal_espnow_deinited(espnow_obj_t *self) { return self == NULL || self->recv_buffer == NULL; } +// Construct the ESPNow object +void common_hal_espnow_construct(espnow_obj_t *self, mp_int_t buffer_size, mp_int_t phy_rate) { + common_hal_espnow_set_buffer_size(self, buffer_size); + common_hal_espnow_set_phy_rate(self, phy_rate); + + self->tx_stats = espnow_stats_new(); + self->rx_stats = espnow_stats_new(); + + self->peers = espnow_peers_new(); + + common_hal_espnow_init(self); +} + // Initialize the ESP-NOW software stack, // register callbacks and allocate the recv data buffers. void common_hal_espnow_init(espnow_obj_t *self) { @@ -171,17 +178,15 @@ void common_hal_espnow_deinit(espnow_obj_t *self) { self->recv_buffer->buf = NULL; self->recv_buffer = NULL; - // self->peers_count = 0; // esp_now_deinit() removes all peers. - self->tx_packets = self->tx_responses; } void espnow_reset(void) { - common_hal_espnow_deinit(_get_singleton()); + common_hal_espnow_deinit(MP_STATE_PORT(espnow_singleton)); MP_STATE_PORT(espnow_singleton) = NULL; } void common_hal_espnow_set_buffer_size(espnow_obj_t *self, mp_int_t value) { - self->recv_buffer_size = mp_arg_validate_int_min(value, MAX_PACKET_LEN, MP_QSTR_buffer_size); + self->recv_buffer_size = mp_arg_validate_int_min(value, MIN_PACKET_LEN, MP_QSTR_buffer_size); }; void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value) { @@ -206,10 +211,6 @@ mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const uint8_t *mac, const mp } CHECK_ESP_RESULT(err); - // Increment the sent packet count. - // If mac == NULL msg will be sent to all peers EXCEPT any broadcast or multicast addresses. - self->tx_packets += ((mac == NULL) ? ((mp_obj_list_t *)self->peers->list)->len : 1); - return mp_const_none; } diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h index 02ca90d5c4..87e3fb7168 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.h +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -29,6 +29,7 @@ #include "py/obj.h" #include "py/ringbuf.h" +#include "bindings/espnow/ESPNowStats.h" #include "bindings/espnow/Peers.h" #include "esp_wifi.h" @@ -39,16 +40,14 @@ typedef struct _espnow_obj_t { ringbuf_t *recv_buffer; // A buffer for received packets size_t recv_buffer_size; // The size of the recv_buffer wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. - volatile size_t rx_packets; // # of received packets - volatile size_t rx_failures; // # of dropped packets (buffer full) - size_t tx_packets; // # of sent packets - volatile size_t tx_responses; // # of sent packet responses received - volatile size_t tx_failures; // # of sent packet responses failed - espnow_peers_obj_t *peers; // Cache the # of peers for send(sync=True) + espnow_stats_obj_t *tx_stats; // The tx packet stats + espnow_stats_obj_t *rx_stats; // The rx packet stats + espnow_peers_obj_t *peers; // The sequence of peers } espnow_obj_t; extern void espnow_reset(void); +extern void common_hal_espnow_construct(espnow_obj_t *self, mp_int_t buffer_size, mp_int_t phy_rate); extern void common_hal_espnow_init(espnow_obj_t *self); extern void common_hal_espnow_deinit(espnow_obj_t *self); extern bool common_hal_espnow_deinited(espnow_obj_t *self); From c0a9c71057be49e87327ec487e5f924d9d3d9e7c Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Sun, 5 Feb 2023 01:18:18 +0530 Subject: [PATCH 14/29] replace `ESPNowStats` with `Communicate` class and more --- ports/espressif/bindings/espnow/Communicate.c | 197 ++++++++++++++++++ .../espnow/{ESPNowStats.h => Communicate.h} | 7 +- ports/espressif/bindings/espnow/ESPNow.c | 105 ++-------- .../espressif/bindings/espnow/ESPNowPacket.c | 10 +- ports/espressif/bindings/espnow/ESPNowStats.c | 87 -------- ports/espressif/bindings/espnow/Peers.c | 17 +- ports/espressif/bindings/espnow/__init__.c | 8 +- ports/espressif/common-hal/espnow/ESPNow.c | 18 +- ports/espressif/common-hal/espnow/ESPNow.h | 16 +- ports/espressif/common-hal/espnow/__init__.c | 9 + ports/espressif/common-hal/espnow/__init__.h | 4 +- 11 files changed, 264 insertions(+), 214 deletions(-) create mode 100644 ports/espressif/bindings/espnow/Communicate.c rename ports/espressif/bindings/espnow/{ESPNowStats.h => Communicate.h} (91%) delete mode 100644 ports/espressif/bindings/espnow/ESPNowStats.c diff --git a/ports/espressif/bindings/espnow/Communicate.c b/ports/espressif/bindings/espnow/Communicate.c new file mode 100644 index 0000000000..2e6e63fe46 --- /dev/null +++ b/ports/espressif/bindings/espnow/Communicate.c @@ -0,0 +1,197 @@ +/* + * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython + * + * The MIT License (MIT) + * + * Copyright (c) 2023 MicroDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "bindings/espnow/Peer.h" +#include "common-hal/espnow/__init__.h" + +// --- Send and Receive ESP-NOW data --- + +//| class Communicate: +//| """Provides methods and statistics related to communication +//| with the ESP-NOW peers. +//| +//| Dictionary: +//| * "Send" = "Transmit" = ``TX`` +//| * "Recv" = "Receive" = ``RX`` +//| """ +//| +//| def __init__(self) -> None: +//| """You cannot create an instance of `Communicate`.""" +//| ... + +//| job: str +//| """Used to decide whether to call `__send` or `__recv`. (read-only)""" +//| +STATIC mp_obj_t espnow_com_get_job(const mp_obj_t self_in) { + espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_QSTR(self->job); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_com_get_job_obj, espnow_com_get_job); + +MP_PROPERTY_GETTER(espnow_com_job_obj, + (mp_obj_t)&espnow_com_get_job_obj); + +//| success: int +//| """The number of successes. (read-only) +//| +//| * In case of transmit ``TX``: +//| The number of tx packets received by the peer(s) ``ESP_NOW_SEND_SUCCESS``. +//| +//| * In case of receive ``RX``: +//| The number of rx packets captured in the buffer.""" +//| +STATIC mp_obj_t espnow_com_get_success(const mp_obj_t self_in) { + espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->success); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_com_get_success_obj, espnow_com_get_success); + +MP_PROPERTY_GETTER(espnow_com_success_obj, + (mp_obj_t)&espnow_com_get_success_obj); + +//| failure: int +//| """The number of failures. (read-only) +//| +//| * In case of transmit ``TX``: +//| The number of failed tx packets ``ESP_NOW_SEND_FAIL``. +//| +//| * In case of receive ``RX``: +//| The number of dropped rx packets due to buffer overflow.""" +//| +STATIC mp_obj_t espnow_com_get_failure(const mp_obj_t self_in) { + espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->failure); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_com_get_failure_obj, espnow_com_get_failure); + +MP_PROPERTY_GETTER(espnow_com_failure_obj, + (mp_obj_t)&espnow_com_get_failure_obj); + +//| def __send( +//| self, +//| message: ReadableBuffer, +//| peer: Peer, +//| ) -> bool: +//| """Send a message to the peer's mac address. +//| +//| :param ReadableBuffer message: The message to send (length <= 250 bytes). +//| :param Peer peer: Send message to this peer. If `None`, send to all registered peers. +//| """ +//| ... +STATIC mp_obj_t espnow_com___send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_message, ARG_peer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_message, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_peer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + espnow_obj_t *self = pos_args[0]; + common_hal_espnow_check_for_deinit(self); + + // Get a pointer to the data buffer of the message + mp_buffer_info_t message; + mp_get_buffer_raise(args[ARG_message].u_obj, &message, MP_BUFFER_READ); + + const uint8_t *mac = NULL; + if (args[ARG_peer].u_obj != mp_const_none) { + const espnow_peer_obj_t *peer = MP_OBJ_FROM_PTR(mp_arg_validate_type_or_none(args[ARG_peer].u_obj, &espnow_peer_type, MP_QSTR_peer)); + mac = peer->peer_info.peer_addr; + } + + return common_hal_espnow_send(self, &message, mac); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_com___send_obj, 2, espnow_com___send); + +//| def __recv(self) -> Optional[ESPNowPacket]: +//| """Receive a message from the peer(s). +//| +//| :returns: An `ESPNowPacket` if available in the buffer, otherwise `None`.""" +//| ... +STATIC mp_obj_t espnow_com___recv(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_check_for_deinit(self); + + return common_hal_espnow_recv(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_com___recv_obj, espnow_com___recv); + +STATIC const mp_rom_map_elem_t espnow_com_locals_dict_table[] = { + // Config parameters + { MP_ROM_QSTR(MP_QSTR_job), MP_ROM_PTR(&espnow_com_job_obj) }, + + // Packet statistics + { MP_ROM_QSTR(MP_QSTR_success), MP_ROM_PTR(&espnow_com_success_obj) }, + { MP_ROM_QSTR(MP_QSTR_failure), MP_ROM_PTR(&espnow_com_failure_obj) }, + + // Communication methods + { MP_ROM_QSTR(MP_QSTR___send), MP_ROM_PTR(&espnow_com___send_obj) }, + { MP_ROM_QSTR(MP_QSTR___recv), MP_ROM_PTR(&espnow_com___recv_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(espnow_com_locals_dict, espnow_com_locals_dict_table); + +//| def __call__(self, *args: Optional[Any], **kwargs: Optional[Any]) -> Optional[Any]: +//| """Calls the private `__send` or `__recv` methods with the supplied ``args`` and ``kwargs`` +//| based on whether the job parameter is set to ``send`` or ``recv``.""" +//| ... +//| +STATIC mp_obj_t espnow_com_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t meth = NULL; + switch (self->job) { + case MP_QSTR_send: + meth = MP_OBJ_FROM_PTR(&espnow_com___send_obj); + break; + case MP_QSTR_recv: + meth = MP_OBJ_FROM_PTR(&espnow_com___recv_obj); + break; + default: + break; + } + return meth ? mp_call_method_self_n_kw(meth, MP_STATE_PORT(espnow_singleton), n_args, n_kw, args) : mp_const_none; +} + +espnow_com_obj_t *espnow_com_new(qstr job) { + espnow_com_obj_t *self = m_new_obj(espnow_com_obj_t); + self->base.type = &espnow_com_type; + self->job = job; + return self; +} + +const mp_obj_type_t espnow_com_type = { + { &mp_type_type }, + .name = MP_QSTR_Communicate, + .locals_dict = (mp_obj_t)&espnow_com_locals_dict, + .flags = MP_TYPE_FLAG_EXTENDED, + MP_TYPE_EXTENDED_FIELDS( + .call = &espnow_com_call, + ), +}; diff --git a/ports/espressif/bindings/espnow/ESPNowStats.h b/ports/espressif/bindings/espnow/Communicate.h similarity index 91% rename from ports/espressif/bindings/espnow/ESPNowStats.h rename to ports/espressif/bindings/espnow/Communicate.h index a9a578a8bf..194784f8b4 100644 --- a/ports/espressif/bindings/espnow/ESPNowStats.h +++ b/ports/espressif/bindings/espnow/Communicate.h @@ -32,7 +32,8 @@ typedef struct { mp_obj_base_t base; volatile size_t success; volatile size_t failure; -} espnow_stats_obj_t; + qstr job; +} espnow_com_obj_t; -const mp_obj_type_t espnow_stats_type; -extern espnow_stats_obj_t *espnow_stats_new(void); +const mp_obj_type_t espnow_com_type; +extern espnow_com_obj_t *espnow_com_new(qstr job); diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 33bb882873..8eb82af31a 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -32,22 +32,12 @@ #include "py/stream.h" #include "bindings/espnow/ESPNow.h" - -#include "shared-bindings/util.h" - #include "common-hal/espnow/__init__.h" -#include "common-hal/espnow/ESPNow.h" #include "esp_now.h" // --- Initialisation and Config functions --- -static void check_for_deinit(espnow_obj_t *self) { - if (common_hal_espnow_deinited(self)) { - raise_deinited_error(); - } -} - //| class ESPNow: //| """Provides access to the ESP-NOW protocol.""" //| @@ -82,7 +72,7 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t // Set the global singleton pointer for the espnow protocol. MP_STATE_PORT(espnow_singleton) = self; - return self; + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: @@ -90,6 +80,7 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t //| ... STATIC mp_obj_t espnow_deinit(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_check_for_deinit(self); common_hal_espnow_deinit(self); return mp_const_none; } @@ -117,6 +108,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow___exit___obj, 4, 4, espnow_obj //| ... STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_check_for_deinit(self); common_hal_espnow_set_pmk(self, common_hal_espnow_get_bytes_len(key, ESP_NOW_KEY_LEN)); return mp_const_none; } @@ -133,6 +125,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_buffer_size_obj, espnow_get_buffer_size); STATIC mp_obj_t espnow_set_buffer_size(const mp_obj_t self_in, const mp_obj_t value) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_check_for_deinit(self); common_hal_espnow_set_buffer_size(self, mp_obj_get_int(value)); return mp_const_none; } @@ -153,6 +146,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_phy_rate_obj, espnow_get_phy_rate); STATIC mp_obj_t espnow_set_phy_rate(const mp_obj_t self_in, const mp_obj_t value) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_check_for_deinit(self); common_hal_espnow_set_phy_rate(self, mp_obj_get_int(value)); return mp_const_none; } @@ -162,78 +156,29 @@ MP_PROPERTY_GETSET(espnow_phy_rate_obj, (mp_obj_t)&espnow_get_phy_rate_obj, (mp_obj_t)&espnow_set_phy_rate_obj); -//| tx_stats: ESPNowStats -//| """The ``TX`` packet statistics.""" +//| send: Communicate +//| """A `Communicate` object with ``job`` set to ``send``. (read-only)""" //| -STATIC mp_obj_t espnow_get_tx_stats(mp_obj_t self_in) { +STATIC mp_obj_t espnow_get_send(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->tx_stats); + return MP_OBJ_FROM_PTR(self->send); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_tx_stats_obj, espnow_get_tx_stats); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_send_obj, espnow_get_send); -MP_PROPERTY_GETTER(espnow_tx_stats_obj, - (mp_obj_t)&espnow_get_tx_stats_obj); +MP_PROPERTY_GETTER(espnow_send_call_obj, + (mp_obj_t)&espnow_get_send_obj); -//| rx_stats: ESPNowStats -//| """The ``RX`` packet statistics.""" +//| recv: Communicate +//| """A `Communicate` object with ``job`` set to ``recv``. (read-only)""" //| -STATIC mp_obj_t espnow_get_rx_stats(mp_obj_t self_in) { +STATIC mp_obj_t espnow_get_recv(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->rx_stats); + return MP_OBJ_FROM_PTR(self->recv); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_rx_stats_obj, espnow_get_rx_stats); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_recv_obj, espnow_get_recv); -MP_PROPERTY_GETTER(espnow_rx_stats_obj, - (mp_obj_t)&espnow_get_rx_stats_obj); - -// --- Send and Receive ESP-NOW data --- - -//| def send( -//| self, -//| message: ReadableBuffer, -//| mac: Optional[ReadableBuffer], -//| ) -> bool: -//| """Send a message to the peer's mac address. -//| -//| :param ReadableBuffer message: The message to send (length <= 250 bytes). -//| :param ReadableBuffer mac: The peer's address (length = 6 bytes). -//| If `None` or any non-true value, send to all registered peers.""" -//| ... -STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_message, ARG_mac, ARG_sync }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_message, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_mac, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - espnow_obj_t *self = pos_args[0]; - check_for_deinit(self); - - const uint8_t *peer_addr = common_hal_espnow_get_bytes_len(args[ARG_mac].u_obj, ESP_NOW_ETH_ALEN); - - // Get a pointer to the data buffer of the message - mp_buffer_info_t message; - mp_get_buffer_raise(args[ARG_message].u_obj, &message, MP_BUFFER_READ); - - return common_hal_espnow_send(self, peer_addr, &message); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); - -//| def recv(self) -> Optional[ESPNowPacket]: -//| """Receive a message from the peer(s). -//| -//| :returns: An `ESPNowPacket` if available in the buffer, otherwise `None`.""" -//| ... -STATIC mp_obj_t espnow_recv(mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - return common_hal_espnow_recv(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_recv_obj, espnow_recv); +MP_PROPERTY_GETTER(espnow_recv_call_obj, + (mp_obj_t)&espnow_get_recv_obj); // --- Peer Related Properties --- @@ -242,7 +187,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_recv_obj, espnow_recv); //| STATIC mp_obj_t espnow_get_peers(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); return MP_OBJ_FROM_PTR(self->peers); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_obj, espnow_get_peers); @@ -263,13 +207,9 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_buffer_size), MP_ROM_PTR(&espnow_buffer_size_obj) }, { MP_ROM_QSTR(MP_QSTR_phy_rate), MP_ROM_PTR(&espnow_phy_rate_obj) }, - // Packet statistics - { MP_ROM_QSTR(MP_QSTR_tx_stats), MP_ROM_PTR(&espnow_tx_stats_obj) }, - { MP_ROM_QSTR(MP_QSTR_rx_stats), MP_ROM_PTR(&espnow_rx_stats_obj) }, - // Send and receive messages - { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, - { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&espnow_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_call_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&espnow_recv_call_obj) }, // Peer related properties { MP_ROM_QSTR(MP_QSTR_peers), MP_ROM_PTR(&espnow_peers_obj) }, @@ -282,7 +222,7 @@ STATIC MP_DEFINE_CONST_DICT(espnow_locals_dict, espnow_locals_dict_table); // Support ioctl(MP_STREAM_POLL, ) for asyncio STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); + common_hal_espnow_check_for_deinit(self); switch (request) { case MP_STREAM_POLL: { mp_uint_t flags = arg; @@ -314,6 +254,7 @@ STATIC const mp_stream_p_t espnow_stream_p = { //| STATIC mp_obj_t espnow_unary_op(mp_unary_op_t op, mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_espnow_check_for_deinit(self); size_t len = ringbuf_num_filled(self->recv_buffer); switch (op) { case MP_UNARY_OP_BOOL: diff --git a/ports/espressif/bindings/espnow/ESPNowPacket.c b/ports/espressif/bindings/espnow/ESPNowPacket.c index 7cbf2caed0..f8bc8e8418 100644 --- a/ports/espressif/bindings/espnow/ESPNowPacket.c +++ b/ports/espressif/bindings/espnow/ESPNowPacket.c @@ -27,19 +27,19 @@ #include "bindings/espnow/ESPNowPacket.h" //| class ESPNowPacket: -//| """A packet retrieved from ESP-NOW communication protocol""" +//| """A packet retrieved from ESP-NOW communication protocol. A namedtuple.""" //| //| mac: ReadableBuffer -//| """The sender's mac address (length = 6 bytes)""" +//| """The sender's mac address (length = 6 bytes).""" //| //| msg: ReadableBuffer -//| """The message sent by the peer (length <= 250 bytes)""" +//| """The message sent by the peer (length <= 250 bytes).""" //| //| rssi: int -//| """The received signal strength indication (in dBm from -127 to 0)""" +//| """The received signal strength indication (in dBm from -127 to 0).""" //| //| time: int -//| """The time in milliseconds since the device last booted when the packet was received""" +//| """The time in milliseconds since the device last booted when the packet was received.""" //| const mp_obj_namedtuple_type_t espnow_packet_type_obj = { diff --git a/ports/espressif/bindings/espnow/ESPNowStats.c b/ports/espressif/bindings/espnow/ESPNowStats.c deleted file mode 100644 index babd8e4d83..0000000000 --- a/ports/espressif/bindings/espnow/ESPNowStats.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython - * - * The MIT License (MIT) - * - * Copyright (c) 2023 MicroDev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "bindings/espnow/ESPNowStats.h" -#include "py/objproperty.h" - -//| class ESPNowStats: -//| """Provide some useful packet tx/rx statistics.""" -//| - -//| success: int -//| """The number of successes. (read-only) -//| -//| * In case of transmit ``TX``: -//| The number of tx packets received by the peer(s) ``ESP_NOW_SEND_SUCCESS``. -//| -//| * In case of receive ``RX``: -//| The number of rx packets captured in the buffer.""" -//| -STATIC mp_obj_t espnow_stats_get_success(const mp_obj_t self_in) { - espnow_stats_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int_from_uint(self->success); -} -MP_DEFINE_CONST_FUN_OBJ_1(espnow_stats_get_success_obj, espnow_stats_get_success); - -MP_PROPERTY_GETTER(espnow_stats_success_obj, - (mp_obj_t)&espnow_stats_get_success_obj); - -//| failure: int -//| """The number of failures. (read-only) -//| -//| * In case of transmit ``TX``: -//| The number of failed tx packets ``ESP_NOW_SEND_FAIL``. -//| -//| * In case of receive ``RX``: -//| The number of dropped rx packets due to buffer overflow.""" -//| -STATIC mp_obj_t espnow_stats_get_failure(const mp_obj_t self_in) { - espnow_stats_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int_from_uint(self->failure); -} -MP_DEFINE_CONST_FUN_OBJ_1(espnow_stats_get_failure_obj, espnow_stats_get_failure); - -MP_PROPERTY_GETTER(espnow_stats_failure_obj, - (mp_obj_t)&espnow_stats_get_failure_obj); - -STATIC const mp_rom_map_elem_t espnow_stats_locals_dict_table[] = { - // Peer parameters - { MP_ROM_QSTR(MP_QSTR_success), MP_ROM_PTR(&espnow_stats_success_obj) }, - { MP_ROM_QSTR(MP_QSTR_failure), MP_ROM_PTR(&espnow_stats_failure_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(espnow_stats_locals_dict, espnow_stats_locals_dict_table); - -espnow_stats_obj_t *espnow_stats_new(void) { - espnow_stats_obj_t *self = m_new_obj(espnow_stats_obj_t); - self->base.type = &espnow_stats_type; - return self; -} - -const mp_obj_type_t espnow_stats_type = { - { &mp_type_type }, - .name = MP_QSTR_ESPNowStats, - .locals_dict = (mp_obj_t)&espnow_stats_locals_dict, -}; diff --git a/ports/espressif/bindings/espnow/Peers.c b/ports/espressif/bindings/espnow/Peers.c index 843bff644a..e3f858c1c9 100644 --- a/ports/espressif/bindings/espnow/Peers.c +++ b/ports/espressif/bindings/espnow/Peers.c @@ -40,6 +40,9 @@ //| class Peers: //| """A class that provides peer managment functions. Sequence[Peer].""" //| +//| def __init__(self) -> None: +//| """You cannot create an instance of `Peers`.""" +//| ... //| def append(self, peer: Peer) -> None: //| """Append peer. @@ -195,7 +198,6 @@ const mp_obj_type_t espnow_peers_type = { { &mp_type_type }, .name = MP_QSTR_Peers, .print = espnow_peers_print, - // .make_new = espnow_peers_make_new, .locals_dict = (mp_obj_t)&espnow_peers_locals_dict, .flags = MP_TYPE_FLAG_EXTENDED, MP_TYPE_EXTENDED_FIELDS( @@ -204,16 +206,3 @@ const mp_obj_type_t espnow_peers_type = { .getiter = espnow_peers_getiter, ), }; - -/* -STATIC mp_obj_t espnow_peers_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - (void)type_in; - mp_arg_check_num(n_args, n_kw, 0, 1, false); - - espnow_peers_obj_t *self = m_new_obj(espnow_peers_obj_t); - self->base.type = &espnow_peers_type; - self->list = mp_obj_new_list_from_iter(args[0]); - - return MP_OBJ_FROM_PTR(self); -} -*/ diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c index f64a6433dd..2b95085c5d 100644 --- a/ports/espressif/bindings/espnow/__init__.c +++ b/ports/espressif/bindings/espnow/__init__.c @@ -24,12 +24,10 @@ * THE SOFTWARE. */ -#include "shared-bindings/util.h" - #include "bindings/espnow/__init__.h" #include "bindings/espnow/ESPNow.h" #include "bindings/espnow/ESPNowPacket.h" -#include "bindings/espnow/ESPNowStats.h" +#include "bindings/espnow/Communicate.h" #include "bindings/espnow/Peer.h" #include "bindings/espnow/Peers.h" @@ -51,7 +49,7 @@ //| e.peers.append(peer) //| //| e.send("Starting...") -//| for i in range(100): +//| for i in range(10): //| e.send(str(i)*20) //| e.send(b'end') //| @@ -85,7 +83,7 @@ STATIC const mp_rom_map_elem_t espnow_module_globals_table[] = { // module classes { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&espnow_type) }, { MP_ROM_QSTR(MP_QSTR_ESPNowPacket),MP_ROM_PTR(&espnow_packet_type_obj) }, - { MP_ROM_QSTR(MP_QSTR_ESPNowStats), MP_ROM_PTR(&espnow_stats_type) }, + { MP_ROM_QSTR(MP_QSTR_Communicate), MP_ROM_PTR(&espnow_com_type) }, { MP_ROM_QSTR(MP_QSTR_Peer), MP_ROM_PTR(&espnow_peer_type) }, { MP_ROM_QSTR(MP_QSTR_Peers), MP_ROM_PTR(&espnow_peers_type) }, }; diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index 96a7cfdfaa..df766ad32f 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -53,8 +53,8 @@ // Will allocate an additional 7 bytes for buffer overhead #define DEFAULT_RECV_BUFFER_SIZE (2 * MAX_PACKET_LEN) -// Time to wait (millisec) for responses from sent packets: (1 seconds). -#define DEFAULT_SEND_TIMEOUT_MS (1000) +// Time to wait (millisec) for responses from sent packets: (2 seconds). +#define DEFAULT_SEND_TIMEOUT_MS (2000) // ESPNow packet format for the receive buffer. // Use this for peeking at the header of the next packet in the buffer. @@ -79,9 +79,9 @@ typedef struct { static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); if (status == ESP_NOW_SEND_SUCCESS) { - self->tx_stats->success++; + self->send->success++; } else { - self->tx_stats->failure++; + self->send->failure++; } } @@ -93,7 +93,7 @@ static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { ringbuf_t *buf = self->recv_buffer; if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { - self->rx_stats->failure++; + self->recv->failure++; return; } @@ -120,7 +120,7 @@ static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { ringbuf_put_n(buf, mac, ESP_NOW_ETH_ALEN); ringbuf_put_n(buf, msg, msg_len); - self->rx_stats->success++; + self->recv->success++; } bool common_hal_espnow_deinited(espnow_obj_t *self) { @@ -132,8 +132,8 @@ void common_hal_espnow_construct(espnow_obj_t *self, mp_int_t buffer_size, mp_in common_hal_espnow_set_buffer_size(self, buffer_size); common_hal_espnow_set_phy_rate(self, phy_rate); - self->tx_stats = espnow_stats_new(); - self->rx_stats = espnow_stats_new(); + self->send = espnow_com_new(MP_QSTR_send); + self->recv = espnow_com_new(MP_QSTR_recv); self->peers = espnow_peers_new(); @@ -200,7 +200,7 @@ void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key) { // --- Send and Receive ESP-NOW data --- -mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const uint8_t *mac, const mp_buffer_info_t *message) { +mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const mp_buffer_info_t *message, const uint8_t *mac) { // Send the packet - keep trying until timeout if the internal esp-now buffers are full. esp_err_t err; mp_uint_t start = mp_hal_ticks_ms(); diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h index 87e3fb7168..32e9a4c44c 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.h +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -29,7 +29,7 @@ #include "py/obj.h" #include "py/ringbuf.h" -#include "bindings/espnow/ESPNowStats.h" +#include "bindings/espnow/Communicate.h" #include "bindings/espnow/Peers.h" #include "esp_wifi.h" @@ -37,12 +37,12 @@ // The data structure for the espnow_singleton. typedef struct _espnow_obj_t { mp_obj_base_t base; - ringbuf_t *recv_buffer; // A buffer for received packets - size_t recv_buffer_size; // The size of the recv_buffer - wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. - espnow_stats_obj_t *tx_stats; // The tx packet stats - espnow_stats_obj_t *rx_stats; // The rx packet stats - espnow_peers_obj_t *peers; // The sequence of peers + ringbuf_t *recv_buffer; // A buffer for received packets + size_t recv_buffer_size; // The size of the recv_buffer + wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. + espnow_com_obj_t *send; // The tx packet stats + espnow_com_obj_t *recv; // The rx packet stats + espnow_peers_obj_t *peers; // The sequence of peers } espnow_obj_t; extern void espnow_reset(void); @@ -56,5 +56,5 @@ extern void common_hal_espnow_set_buffer_size(espnow_obj_t *self, mp_int_t value extern void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value); extern void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key); -extern mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const uint8_t *mac, const mp_buffer_info_t *message); +extern mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const mp_buffer_info_t *message, const uint8_t *mac); extern mp_obj_t common_hal_espnow_recv(espnow_obj_t *self); diff --git a/ports/espressif/common-hal/espnow/__init__.c b/ports/espressif/common-hal/espnow/__init__.c index 498cd49dc9..77196f3349 100644 --- a/ports/espressif/common-hal/espnow/__init__.c +++ b/ports/espressif/common-hal/espnow/__init__.c @@ -25,7 +25,16 @@ */ #include "common-hal/espnow/__init__.h" + #include "py/runtime.h" +#include "shared-bindings/util.h" + +// Raise ValueError if the ESPNow object is deinited +void common_hal_espnow_check_for_deinit(espnow_obj_t *self) { + if (common_hal_espnow_deinited(self)) { + raise_deinited_error(); + } +} // Return C pointer to byte memory string/bytes/bytearray in obj. // Raise ValueError if the length does not match expected len. diff --git a/ports/espressif/common-hal/espnow/__init__.h b/ports/espressif/common-hal/espnow/__init__.h index bb1950d98c..068da3507a 100644 --- a/ports/espressif/common-hal/espnow/__init__.h +++ b/ports/espressif/common-hal/espnow/__init__.h @@ -26,5 +26,7 @@ #pragma once -#include "py/obj.h" +#include "common-hal/espnow/ESPNow.h" + +extern void common_hal_espnow_check_for_deinit(espnow_obj_t *self); extern const uint8_t *common_hal_espnow_get_bytes_len(mp_obj_t obj, size_t len); From 6c54bc9fd9237caf793c16a37f624154be5375d5 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Sun, 5 Feb 2023 12:31:08 +0530 Subject: [PATCH 15/29] more espnow changes - improve docs - use existing list methods - change `recv` to `read` --- ports/espressif/bindings/espnow/Communicate.c | 34 ++++---- ports/espressif/bindings/espnow/ESPNow.c | 20 ++--- ports/espressif/bindings/espnow/Peers.c | 84 ++----------------- ports/espressif/bindings/espnow/__init__.c | 2 +- ports/espressif/common-hal/espnow/ESPNow.c | 10 +-- ports/espressif/common-hal/espnow/ESPNow.h | 6 +- 6 files changed, 46 insertions(+), 110 deletions(-) diff --git a/ports/espressif/bindings/espnow/Communicate.c b/ports/espressif/bindings/espnow/Communicate.c index 2e6e63fe46..5016dcfdda 100644 --- a/ports/espressif/bindings/espnow/Communicate.c +++ b/ports/espressif/bindings/espnow/Communicate.c @@ -36,9 +36,9 @@ //| """Provides methods and statistics related to communication //| with the ESP-NOW peers. //| -//| Dictionary: +//| Terminology: //| * "Send" = "Transmit" = ``TX`` -//| * "Recv" = "Receive" = ``RX`` +//| * "Read" = ``RX`` //| """ //| //| def __init__(self) -> None: @@ -46,7 +46,7 @@ //| ... //| job: str -//| """Used to decide whether to call `__send` or `__recv`. (read-only)""" +//| """Used to decide whether to call `__send` or `__read`. (read-only)""" //| STATIC mp_obj_t espnow_com_get_job(const mp_obj_t self_in) { espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -97,9 +97,11 @@ MP_PROPERTY_GETTER(espnow_com_failure_obj, //| self, //| message: ReadableBuffer, //| peer: Peer, -//| ) -> bool: +//| ) -> None: //| """Send a message to the peer's mac address. //| +//| This blocks until a timeout of ``2`` seconds if the ESP-NOW internal buffers are full. +//| //| :param ReadableBuffer message: The message to send (length <= 250 bytes). //| :param Peer peer: Send message to this peer. If `None`, send to all registered peers. //| """ @@ -131,18 +133,20 @@ STATIC mp_obj_t espnow_com___send(size_t n_args, const mp_obj_t *pos_args, mp_ma } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_com___send_obj, 2, espnow_com___send); -//| def __recv(self) -> Optional[ESPNowPacket]: -//| """Receive a message from the peer(s). +//| def __read(self) -> Optional[ESPNowPacket]: +//| """Read a packet from the receive buffer. +//| +//| This is non-blocking, the packet is received asynchronously from the peer(s). //| //| :returns: An `ESPNowPacket` if available in the buffer, otherwise `None`.""" //| ... -STATIC mp_obj_t espnow_com___recv(mp_obj_t self_in) { +STATIC mp_obj_t espnow_com___read(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_espnow_check_for_deinit(self); - return common_hal_espnow_recv(self); + return common_hal_espnow_read(self); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_com___recv_obj, espnow_com___recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_com___read_obj, espnow_com___read); STATIC const mp_rom_map_elem_t espnow_com_locals_dict_table[] = { // Config parameters @@ -153,14 +157,14 @@ STATIC const mp_rom_map_elem_t espnow_com_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_failure), MP_ROM_PTR(&espnow_com_failure_obj) }, // Communication methods - { MP_ROM_QSTR(MP_QSTR___send), MP_ROM_PTR(&espnow_com___send_obj) }, - { MP_ROM_QSTR(MP_QSTR___recv), MP_ROM_PTR(&espnow_com___recv_obj) }, + { MP_ROM_QSTR(MP_QSTR___send), MP_ROM_PTR(&espnow_com___send_obj) }, + { MP_ROM_QSTR(MP_QSTR___read), MP_ROM_PTR(&espnow_com___read_obj) }, }; STATIC MP_DEFINE_CONST_DICT(espnow_com_locals_dict, espnow_com_locals_dict_table); //| def __call__(self, *args: Optional[Any], **kwargs: Optional[Any]) -> Optional[Any]: -//| """Calls the private `__send` or `__recv` methods with the supplied ``args`` and ``kwargs`` -//| based on whether the job parameter is set to ``send`` or ``recv``.""" +//| """Calls the private `__send` or `__read` methods with the supplied ``args`` and ``kwargs`` +//| based on whether the job parameter is set to ``send`` or ``read``.""" //| ... //| STATIC mp_obj_t espnow_com_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -170,8 +174,8 @@ STATIC mp_obj_t espnow_com_call(mp_obj_t self_in, size_t n_args, size_t n_kw, co case MP_QSTR_send: meth = MP_OBJ_FROM_PTR(&espnow_com___send_obj); break; - case MP_QSTR_recv: - meth = MP_OBJ_FROM_PTR(&espnow_com___recv_obj); + case MP_QSTR_read: + meth = MP_OBJ_FROM_PTR(&espnow_com___read_obj); break; default: break; diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 8eb82af31a..bf1dcc9eb4 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -165,20 +165,20 @@ STATIC mp_obj_t espnow_get_send(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_send_obj, espnow_get_send); -MP_PROPERTY_GETTER(espnow_send_call_obj, +MP_PROPERTY_GETTER(espnow_send_obj, (mp_obj_t)&espnow_get_send_obj); -//| recv: Communicate -//| """A `Communicate` object with ``job`` set to ``recv``. (read-only)""" +//| read: Communicate +//| """A `Communicate` object with ``job`` set to ``read``. (read-only)""" //| -STATIC mp_obj_t espnow_get_recv(mp_obj_t self_in) { +STATIC mp_obj_t espnow_get_read(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->recv); + return MP_OBJ_FROM_PTR(self->read); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_recv_obj, espnow_get_recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_read_obj, espnow_get_read); -MP_PROPERTY_GETTER(espnow_recv_call_obj, - (mp_obj_t)&espnow_get_recv_obj); +MP_PROPERTY_GETTER(espnow_read_obj, + (mp_obj_t)&espnow_get_read_obj); // --- Peer Related Properties --- @@ -208,8 +208,8 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_phy_rate), MP_ROM_PTR(&espnow_phy_rate_obj) }, // Send and receive messages - { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_call_obj) }, - { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&espnow_recv_call_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&espnow_read_obj) }, // Peer related properties { MP_ROM_QSTR(MP_QSTR_peers), MP_ROM_PTR(&espnow_peers_obj) }, diff --git a/ports/espressif/bindings/espnow/Peers.c b/ports/espressif/bindings/espnow/Peers.c index e3f858c1c9..15d07c09d0 100644 --- a/ports/espressif/bindings/espnow/Peers.c +++ b/ports/espressif/bindings/espnow/Peers.c @@ -38,7 +38,7 @@ // TODO: Check for deinit //| class Peers: -//| """A class that provides peer managment functions. Sequence[Peer].""" +//| """Maintains a `list` of `Peer` internally and only exposes a subset of `list` methods.""" //| //| def __init__(self) -> None: //| """You cannot create an instance of `Peers`.""" @@ -86,22 +86,7 @@ STATIC MP_DEFINE_CONST_DICT(espnow_peers_locals_dict, espnow_peers_locals_dict_t STATIC void espnow_peers_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); - const char *item_separator = ", "; - if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) { - kind = PRINT_REPR; - } else { - #if MICROPY_PY_UJSON_SEPARATORS - item_separator = MP_PRINT_GET_EXT(print)->item_separator; - #endif - } - mp_print_str(print, "["); - for (size_t i = 0; i < list->len; i++) { - if (i > 0) { - mp_print_str(print, item_separator); - } - mp_obj_print_helper(print, list->items[i], kind); - } - mp_print_str(print, "]"); + return list->base.type->print(print, self->list, kind); } /******************************************************************************/ @@ -110,20 +95,7 @@ STATIC void espnow_peers_print(const mp_print_t *print, mp_obj_t self_in, mp_pri STATIC mp_obj_t espnow_peers_unary_op(mp_unary_op_t op, mp_obj_t self_in) { espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); - switch (op) { - case MP_UNARY_OP_BOOL: - return mp_obj_new_bool(list->len != 0); - case MP_UNARY_OP_LEN: - return MP_OBJ_NEW_SMALL_INT(list->len); - #if MICROPY_PY_SYS_GETSIZEOF - case MP_UNARY_OP_SIZEOF: { - size_t sz = sizeof(*list) + sizeof(mp_obj_t) * list->alloc; - return MP_OBJ_NEW_SMALL_INT(sz); - } - #endif - default: - return MP_OBJ_NULL; // op not supported - } + return list->base.type->ext->unary_op(op, self->list); } /******************************************************************************/ @@ -133,58 +105,18 @@ STATIC mp_obj_t espnow_peers_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t v if (value != MP_OBJ_SENTINEL) { return MP_OBJ_NULL; // op not supported } - espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); - - // load - #if MICROPY_PY_BUILTINS_SLICE - if (mp_obj_is_type(index, &mp_type_slice)) { - mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(list->len, index, &slice)) { - return mp_seq_extract_slice(list->len, list->items, &slice); - } - - mp_obj_list_t *res = MP_OBJ_TO_PTR(mp_obj_new_list(slice.stop - slice.start, NULL)); - mp_seq_copy(res->items, list->items + slice.start, res->len, mp_obj_t); - return MP_OBJ_FROM_PTR(res); - } - #endif - size_t index_val = mp_get_index(list->base.type, list->len, index, false); - return list->items[index_val]; + return list->base.type->ext->subscr(self->list, index, value); } /******************************************************************************/ /* peers iterator */ -typedef struct _espnow_peers_it_t { - mp_obj_base_t base; - mp_fun_1_t iternext; - mp_obj_t peers; - size_t cur; -} espnow_peers_it_t; - -STATIC mp_obj_t espnow_peers_it_iternext(mp_obj_t self_in) { - espnow_peers_it_t *self = MP_OBJ_TO_PTR(self_in); - espnow_peers_obj_t *peers = MP_OBJ_TO_PTR(self->peers); - mp_obj_list_t *list = MP_OBJ_TO_PTR(peers->list); - if (self->cur < list->len) { - mp_obj_t o_out = list->items[self->cur]; - self->cur += 1; - return o_out; - } else { - return MP_OBJ_STOP_ITERATION; - } -} - -STATIC mp_obj_t espnow_peers_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { - assert(sizeof(espnow_peers_it_t) <= sizeof(mp_obj_iter_buf_t)); - espnow_peers_it_t *o = (espnow_peers_it_t *)iter_buf; - o->base.type = &mp_type_polymorph_iter; - o->iternext = espnow_peers_it_iternext; - o->peers = o_in; - o->cur = 0; - return MP_OBJ_FROM_PTR(o); +STATIC mp_obj_t espnow_peers_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { + espnow_peers_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_list_t *list = MP_OBJ_TO_PTR(self->list); + return list->base.type->ext->getiter(self->list, iter_buf); } espnow_peers_obj_t *espnow_peers_new(void) { diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c index 2b95085c5d..b76e250f49 100644 --- a/ports/espressif/bindings/espnow/__init__.c +++ b/ports/espressif/bindings/espnow/__init__.c @@ -64,7 +64,7 @@ //| //| while True: //| if e: -//| packet = e.recv() +//| packet = e.read() //| packets.append(packet) //| if packet.msg == b'end': //| break diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index df766ad32f..662da8cf45 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -93,7 +93,7 @@ static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { ringbuf_t *buf = self->recv_buffer; if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { - self->recv->failure++; + self->read->failure++; return; } @@ -120,7 +120,7 @@ static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { ringbuf_put_n(buf, mac, ESP_NOW_ETH_ALEN); ringbuf_put_n(buf, msg, msg_len); - self->recv->success++; + self->read->success++; } bool common_hal_espnow_deinited(espnow_obj_t *self) { @@ -133,7 +133,7 @@ void common_hal_espnow_construct(espnow_obj_t *self, mp_int_t buffer_size, mp_in common_hal_espnow_set_phy_rate(self, phy_rate); self->send = espnow_com_new(MP_QSTR_send); - self->recv = espnow_com_new(MP_QSTR_recv); + self->read = espnow_com_new(MP_QSTR_read); self->peers = espnow_peers_new(); @@ -166,7 +166,7 @@ void common_hal_espnow_init(espnow_obj_t *self) { } // De-initialize the ESP-NOW software stack, -// disable callbacks and deallocate the recv data buffers. +// disable callbacks and deallocate the recv data buffer. void common_hal_espnow_deinit(espnow_obj_t *self) { if (common_hal_espnow_deinited(self)) { return; @@ -214,7 +214,7 @@ mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const mp_buffer_info_t *mess return mp_const_none; } -mp_obj_t common_hal_espnow_recv(espnow_obj_t *self) { +mp_obj_t common_hal_espnow_read(espnow_obj_t *self) { if (!ringbuf_num_filled(self->recv_buffer)) { return mp_const_none; } diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h index 32e9a4c44c..21f1646825 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.h +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -40,8 +40,8 @@ typedef struct _espnow_obj_t { ringbuf_t *recv_buffer; // A buffer for received packets size_t recv_buffer_size; // The size of the recv_buffer wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. - espnow_com_obj_t *send; // The tx packet stats - espnow_com_obj_t *recv; // The rx packet stats + espnow_com_obj_t *send; // For keeping tx stats + espnow_com_obj_t *read; // For keeping rx stats espnow_peers_obj_t *peers; // The sequence of peers } espnow_obj_t; @@ -57,4 +57,4 @@ extern void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value); extern void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key); extern mp_obj_t common_hal_espnow_send(espnow_obj_t *self, const mp_buffer_info_t *message, const uint8_t *mac); -extern mp_obj_t common_hal_espnow_recv(espnow_obj_t *self); +extern mp_obj_t common_hal_espnow_read(espnow_obj_t *self); From 7f8a3052be11075fa9bdfe53c0aa23d26a13a203 Mon Sep 17 00:00:00 2001 From: BrainBoardz <87398149+BrainBoardz@users.noreply.github.com> Date: Wed, 8 Mar 2023 16:25:18 -0500 Subject: [PATCH 16/29] Updated Pins.c definitions for SPI and I2C Removed "CD" from the pin definitions for (MISO, MOSI and SCK pins). Specifically Pins 13, 15 and 14. Added Pin definitions for I2C and SPI objects --- ports/espressif/boards/brainboardz_neuron/pins.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ports/espressif/boards/brainboardz_neuron/pins.c b/ports/espressif/boards/brainboardz_neuron/pins.c index b0cbb91563..31757e1843 100755 --- a/ports/espressif/boards/brainboardz_neuron/pins.c +++ b/ports/espressif/boards/brainboardz_neuron/pins.c @@ -25,13 +25,13 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, - { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO15) }, { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO16) }, @@ -63,6 +63,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, - + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) } }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From c133e79a08b336a456e8286a70e22c95a5743e4c Mon Sep 17 00:00:00 2001 From: BrainBoardz <87398149+BrainBoardz@users.noreply.github.com> Date: Wed, 8 Mar 2023 16:31:47 -0500 Subject: [PATCH 17/29] Updated mpconfigboard.h Add #defines for SPI_BUS_SCK, SPI_BUS_MOSI and SPI_BUS.MISO --- ports/espressif/boards/brainboardz_neuron/mpconfigboard.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h b/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h index 9507917ead..47be454d8b 100755 --- a/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h +++ b/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h @@ -31,3 +31,10 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO3) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO14) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO15) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO13) From 1200fe405f9e4e672e12e86daac216376671a777 Mon Sep 17 00:00:00 2001 From: BrainBoardz <87398149+BrainBoardz@users.noreply.github.com> Date: Wed, 8 Mar 2023 16:38:16 -0500 Subject: [PATCH 18/29] Change GPIO pins for SDA and SCL Chnage the SDA pin define to GPIO9 and SCL pin define to GPIO8. This now matches the currect GPIO pins numbers in pins.c The previous GPIO pins number in mpconfigboard.h were incorrect --- ports/espressif/boards/brainboardz_neuron/mpconfigboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h b/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h index 47be454d8b..72cda83c9b 100755 --- a/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h +++ b/ports/espressif/boards/brainboardz_neuron/mpconfigboard.h @@ -32,8 +32,8 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) -#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4) -#define DEFAULT_I2C_BUS_SDA (&pin_GPIO3) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO9) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO8) #define DEFAULT_SPI_BUS_SCK (&pin_GPIO14) #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO15) From 6da2ca6770e89a47484ab9a8499ea4830ec45d48 Mon Sep 17 00:00:00 2001 From: BrainBoardz <87398149+BrainBoardz@users.noreply.github.com> Date: Wed, 8 Mar 2023 16:46:31 -0500 Subject: [PATCH 19/29] Update pins.c Added a comma (,) to the the end of the definition for board_spi_obj --- ports/espressif/boards/brainboardz_neuron/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/brainboardz_neuron/pins.c b/ports/espressif/boards/brainboardz_neuron/pins.c index 31757e1843..b436045b05 100755 --- a/ports/espressif/boards/brainboardz_neuron/pins.c +++ b/ports/espressif/boards/brainboardz_neuron/pins.c @@ -65,6 +65,6 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) } + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 874ba4ec68dae62914d04edb543dd90bf98be8ba Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Thu, 9 Mar 2023 12:04:50 +0530 Subject: [PATCH 20/29] revert `Communicate` class and more --- ports/espressif/bindings/espnow/Communicate.c | 201 ------------------ ports/espressif/bindings/espnow/Communicate.h | 39 ---- ports/espressif/bindings/espnow/ESPNow.c | 182 ++++++++++++---- ports/espressif/bindings/espnow/__init__.c | 2 - ports/espressif/common-hal/espnow/ESPNow.c | 19 +- ports/espressif/common-hal/espnow/ESPNow.h | 17 +- ports/espressif/common-hal/espnow/__init__.c | 8 - ports/espressif/common-hal/espnow/__init__.h | 4 +- 8 files changed, 150 insertions(+), 322 deletions(-) delete mode 100644 ports/espressif/bindings/espnow/Communicate.c delete mode 100644 ports/espressif/bindings/espnow/Communicate.h diff --git a/ports/espressif/bindings/espnow/Communicate.c b/ports/espressif/bindings/espnow/Communicate.c deleted file mode 100644 index 5016dcfdda..0000000000 --- a/ports/espressif/bindings/espnow/Communicate.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython - * - * The MIT License (MIT) - * - * Copyright (c) 2023 MicroDev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/objproperty.h" -#include "py/runtime.h" - -#include "bindings/espnow/Peer.h" -#include "common-hal/espnow/__init__.h" - -// --- Send and Receive ESP-NOW data --- - -//| class Communicate: -//| """Provides methods and statistics related to communication -//| with the ESP-NOW peers. -//| -//| Terminology: -//| * "Send" = "Transmit" = ``TX`` -//| * "Read" = ``RX`` -//| """ -//| -//| def __init__(self) -> None: -//| """You cannot create an instance of `Communicate`.""" -//| ... - -//| job: str -//| """Used to decide whether to call `__send` or `__read`. (read-only)""" -//| -STATIC mp_obj_t espnow_com_get_job(const mp_obj_t self_in) { - espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_QSTR(self->job); -} -MP_DEFINE_CONST_FUN_OBJ_1(espnow_com_get_job_obj, espnow_com_get_job); - -MP_PROPERTY_GETTER(espnow_com_job_obj, - (mp_obj_t)&espnow_com_get_job_obj); - -//| success: int -//| """The number of successes. (read-only) -//| -//| * In case of transmit ``TX``: -//| The number of tx packets received by the peer(s) ``ESP_NOW_SEND_SUCCESS``. -//| -//| * In case of receive ``RX``: -//| The number of rx packets captured in the buffer.""" -//| -STATIC mp_obj_t espnow_com_get_success(const mp_obj_t self_in) { - espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int_from_uint(self->success); -} -MP_DEFINE_CONST_FUN_OBJ_1(espnow_com_get_success_obj, espnow_com_get_success); - -MP_PROPERTY_GETTER(espnow_com_success_obj, - (mp_obj_t)&espnow_com_get_success_obj); - -//| failure: int -//| """The number of failures. (read-only) -//| -//| * In case of transmit ``TX``: -//| The number of failed tx packets ``ESP_NOW_SEND_FAIL``. -//| -//| * In case of receive ``RX``: -//| The number of dropped rx packets due to buffer overflow.""" -//| -STATIC mp_obj_t espnow_com_get_failure(const mp_obj_t self_in) { - espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int_from_uint(self->failure); -} -MP_DEFINE_CONST_FUN_OBJ_1(espnow_com_get_failure_obj, espnow_com_get_failure); - -MP_PROPERTY_GETTER(espnow_com_failure_obj, - (mp_obj_t)&espnow_com_get_failure_obj); - -//| def __send( -//| self, -//| message: ReadableBuffer, -//| peer: Peer, -//| ) -> None: -//| """Send a message to the peer's mac address. -//| -//| This blocks until a timeout of ``2`` seconds if the ESP-NOW internal buffers are full. -//| -//| :param ReadableBuffer message: The message to send (length <= 250 bytes). -//| :param Peer peer: Send message to this peer. If `None`, send to all registered peers. -//| """ -//| ... -STATIC mp_obj_t espnow_com___send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_message, ARG_peer }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_message, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_peer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - espnow_obj_t *self = pos_args[0]; - common_hal_espnow_check_for_deinit(self); - - // Get a pointer to the data buffer of the message - mp_buffer_info_t message; - mp_get_buffer_raise(args[ARG_message].u_obj, &message, MP_BUFFER_READ); - - const uint8_t *mac = NULL; - if (args[ARG_peer].u_obj != mp_const_none) { - const espnow_peer_obj_t *peer = MP_OBJ_FROM_PTR(mp_arg_validate_type_or_none(args[ARG_peer].u_obj, &espnow_peer_type, MP_QSTR_peer)); - mac = peer->peer_info.peer_addr; - } - - return common_hal_espnow_send(self, &message, mac); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_com___send_obj, 2, espnow_com___send); - -//| def __read(self) -> Optional[ESPNowPacket]: -//| """Read a packet from the receive buffer. -//| -//| This is non-blocking, the packet is received asynchronously from the peer(s). -//| -//| :returns: An `ESPNowPacket` if available in the buffer, otherwise `None`.""" -//| ... -STATIC mp_obj_t espnow_com___read(mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_check_for_deinit(self); - - return common_hal_espnow_read(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_com___read_obj, espnow_com___read); - -STATIC const mp_rom_map_elem_t espnow_com_locals_dict_table[] = { - // Config parameters - { MP_ROM_QSTR(MP_QSTR_job), MP_ROM_PTR(&espnow_com_job_obj) }, - - // Packet statistics - { MP_ROM_QSTR(MP_QSTR_success), MP_ROM_PTR(&espnow_com_success_obj) }, - { MP_ROM_QSTR(MP_QSTR_failure), MP_ROM_PTR(&espnow_com_failure_obj) }, - - // Communication methods - { MP_ROM_QSTR(MP_QSTR___send), MP_ROM_PTR(&espnow_com___send_obj) }, - { MP_ROM_QSTR(MP_QSTR___read), MP_ROM_PTR(&espnow_com___read_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(espnow_com_locals_dict, espnow_com_locals_dict_table); - -//| def __call__(self, *args: Optional[Any], **kwargs: Optional[Any]) -> Optional[Any]: -//| """Calls the private `__send` or `__read` methods with the supplied ``args`` and ``kwargs`` -//| based on whether the job parameter is set to ``send`` or ``read``.""" -//| ... -//| -STATIC mp_obj_t espnow_com_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - espnow_com_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_t meth = NULL; - switch (self->job) { - case MP_QSTR_send: - meth = MP_OBJ_FROM_PTR(&espnow_com___send_obj); - break; - case MP_QSTR_read: - meth = MP_OBJ_FROM_PTR(&espnow_com___read_obj); - break; - default: - break; - } - return meth ? mp_call_method_self_n_kw(meth, MP_STATE_PORT(espnow_singleton), n_args, n_kw, args) : mp_const_none; -} - -espnow_com_obj_t *espnow_com_new(qstr job) { - espnow_com_obj_t *self = m_new_obj(espnow_com_obj_t); - self->base.type = &espnow_com_type; - self->job = job; - return self; -} - -const mp_obj_type_t espnow_com_type = { - { &mp_type_type }, - .name = MP_QSTR_Communicate, - .locals_dict = (mp_obj_t)&espnow_com_locals_dict, - .flags = MP_TYPE_FLAG_EXTENDED, - MP_TYPE_EXTENDED_FIELDS( - .call = &espnow_com_call, - ), -}; diff --git a/ports/espressif/bindings/espnow/Communicate.h b/ports/espressif/bindings/espnow/Communicate.h deleted file mode 100644 index 194784f8b4..0000000000 --- a/ports/espressif/bindings/espnow/Communicate.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2023 MicroDev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - volatile size_t success; - volatile size_t failure; - qstr job; -} espnow_com_obj_t; - -const mp_obj_type_t espnow_com_type; -extern espnow_com_obj_t *espnow_com_new(qstr job); diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index bf1dcc9eb4..d2f5d2268f 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -31,11 +31,23 @@ #include "py/runtime.h" #include "py/stream.h" +#include "shared-bindings/util.h" + #include "bindings/espnow/ESPNow.h" +#include "bindings/espnow/Peer.h" + #include "common-hal/espnow/__init__.h" +#include "common-hal/espnow/ESPNow.h" #include "esp_now.h" +// Raise ValueError if the ESPNow object is deinited +static void espnow_check_for_deinit(espnow_obj_t *self) { + if (common_hal_espnow_deinited(self)) { + raise_deinited_error(); + } +} + // --- Initialisation and Config functions --- //| class ESPNow: @@ -80,7 +92,7 @@ STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args, size_t //| ... STATIC mp_obj_t espnow_deinit(mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_check_for_deinit(self); + espnow_check_for_deinit(self); common_hal_espnow_deinit(self); return mp_const_none; } @@ -101,6 +113,111 @@ STATIC mp_obj_t espnow_obj___exit__(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow___exit___obj, 4, 4, espnow_obj___exit__); +// --- Send and Read messages --- + +//| def send( +//| self, +//| message: ReadableBuffer, +//| peer: Peer, +//| ) -> None: +//| """Send a message to the peer's mac address. +//| +//| This blocks until a timeout of ``2`` seconds if the ESP-NOW internal buffers are full. +//| +//| :param ReadableBuffer message: The message to send (length <= 250 bytes). +//| :param Peer peer: Send message to this peer. If `None`, send to all registered peers. +//| """ +//| ... +STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_message, ARG_peer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_message, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_peer, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + espnow_obj_t *self = pos_args[0]; + espnow_check_for_deinit(self); + + // Get a pointer to the data buffer of the message + mp_buffer_info_t message; + mp_get_buffer_raise(args[ARG_message].u_obj, &message, MP_BUFFER_READ); + + const uint8_t *mac = NULL; + if (args[ARG_peer].u_obj != mp_const_none) { + const espnow_peer_obj_t *peer = MP_OBJ_FROM_PTR(mp_arg_validate_type_or_none(args[ARG_peer].u_obj, &espnow_peer_type, MP_QSTR_peer)); + mac = peer->peer_info.peer_addr; + } + + return common_hal_espnow_send(self, &message, mac); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_send_obj, 2, espnow_send); + +//| def read(self) -> Optional[ESPNowPacket]: +//| """Read a packet from the receive buffer. +//| +//| This is non-blocking, the packet is received asynchronously from the peer(s). +//| +//| :returns: An `ESPNowPacket` if available in the buffer, otherwise `None`.""" +//| ... +STATIC mp_obj_t espnow_read(mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + espnow_check_for_deinit(self); + + return common_hal_espnow_read(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_read_obj, espnow_read); + +//| send_success: int +//| """The number of tx packets received by the peer(s) ``ESP_NOW_SEND_SUCCESS``. (read-only)""" +//| +STATIC mp_obj_t espnow_get_send_success(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->send_success); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_send_success_obj, espnow_get_send_success); + +MP_PROPERTY_GETTER(espnow_send_success_obj, + (mp_obj_t)&espnow_get_send_success_obj); + +//| send_failure: int +//| """The number of failed tx packets ``ESP_NOW_SEND_FAIL``. (read-only)""" +//| +STATIC mp_obj_t espnow_send_get_failure(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->send_failure); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_send_get_failure_obj, espnow_send_get_failure); + +MP_PROPERTY_GETTER(espnow_send_failure_obj, + (mp_obj_t)&espnow_send_get_failure_obj); + +//| read_success: int +//| """The number of rx packets captured in the buffer. (read-only)""" +//| +STATIC mp_obj_t espnow_get_read_success(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->read_success); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_read_success_obj, espnow_get_read_success); + +MP_PROPERTY_GETTER(espnow_read_success_obj, + (mp_obj_t)&espnow_get_read_success_obj); + +//| read_failure: int +//| """The number of dropped rx packets due to buffer overflow. (read-only)""" +//| +STATIC mp_obj_t espnow_read_get_failure(const mp_obj_t self_in) { + espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int_from_uint(self->read_failure); +} +MP_DEFINE_CONST_FUN_OBJ_1(espnow_read_get_failure_obj, espnow_read_get_failure); + +MP_PROPERTY_GETTER(espnow_read_failure_obj, + (mp_obj_t)&espnow_read_get_failure_obj); + //| def set_pmk(self, pmk: ReadableBuffer) -> None: //| """Set the ESP-NOW Primary Master Key (pmk) for encrypted communications. //| @@ -108,32 +225,23 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow___exit___obj, 4, 4, espnow_obj //| ... STATIC mp_obj_t espnow_set_pmk(mp_obj_t self_in, mp_obj_t key) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_check_for_deinit(self); + espnow_check_for_deinit(self); common_hal_espnow_set_pmk(self, common_hal_espnow_get_bytes_len(key, ESP_NOW_KEY_LEN)); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk); //| buffer_size: int -//| """The size of the internal ring buffer.""" +//| """The size of the internal ring buffer. (read-only)""" //| STATIC mp_obj_t espnow_get_buffer_size(const mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(self->recv_buffer_size); + return mp_obj_new_int_from_uint(self->recv_buffer_size); } MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_buffer_size_obj, espnow_get_buffer_size); -STATIC mp_obj_t espnow_set_buffer_size(const mp_obj_t self_in, const mp_obj_t value) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_check_for_deinit(self); - common_hal_espnow_set_buffer_size(self, mp_obj_get_int(value)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_buffer_size_obj, espnow_set_buffer_size); - -MP_PROPERTY_GETSET(espnow_buffer_size_obj, - (mp_obj_t)&espnow_get_buffer_size_obj, - (mp_obj_t)&espnow_set_buffer_size_obj); +MP_PROPERTY_GETTER(espnow_buffer_size_obj, + (mp_obj_t)&espnow_get_buffer_size_obj); //| phy_rate: int //| """The ESP-NOW physical layer rate.""" @@ -146,7 +254,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_phy_rate_obj, espnow_get_phy_rate); STATIC mp_obj_t espnow_set_phy_rate(const mp_obj_t self_in, const mp_obj_t value) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_check_for_deinit(self); + espnow_check_for_deinit(self); common_hal_espnow_set_phy_rate(self, mp_obj_get_int(value)); return mp_const_none; } @@ -156,30 +264,6 @@ MP_PROPERTY_GETSET(espnow_phy_rate_obj, (mp_obj_t)&espnow_get_phy_rate_obj, (mp_obj_t)&espnow_set_phy_rate_obj); -//| send: Communicate -//| """A `Communicate` object with ``job`` set to ``send``. (read-only)""" -//| -STATIC mp_obj_t espnow_get_send(mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->send); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_send_obj, espnow_get_send); - -MP_PROPERTY_GETTER(espnow_send_obj, - (mp_obj_t)&espnow_get_send_obj); - -//| read: Communicate -//| """A `Communicate` object with ``job`` set to ``read``. (read-only)""" -//| -STATIC mp_obj_t espnow_get_read(mp_obj_t self_in) { - espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->read); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_read_obj, espnow_get_read); - -MP_PROPERTY_GETTER(espnow_read_obj, - (mp_obj_t)&espnow_get_read_obj); - // --- Peer Related Properties --- //| peers: Peers @@ -202,15 +286,21 @@ STATIC const mp_rom_map_elem_t espnow_locals_dict_table[] = { // Deinit the object { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&espnow_deinit_obj) }, + // Send messages + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_send_success),MP_ROM_PTR(&espnow_send_success_obj)}, + { MP_ROM_QSTR(MP_QSTR_send_failure),MP_ROM_PTR(&espnow_send_failure_obj)}, + + // Read messages + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&espnow_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_success),MP_ROM_PTR(&espnow_read_success_obj)}, + { MP_ROM_QSTR(MP_QSTR_read_failure),MP_ROM_PTR(&espnow_read_failure_obj)}, + // Config parameters { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) }, { MP_ROM_QSTR(MP_QSTR_buffer_size), MP_ROM_PTR(&espnow_buffer_size_obj) }, { MP_ROM_QSTR(MP_QSTR_phy_rate), MP_ROM_PTR(&espnow_phy_rate_obj) }, - // Send and receive messages - { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&espnow_read_obj) }, - // Peer related properties { MP_ROM_QSTR(MP_QSTR_peers), MP_ROM_PTR(&espnow_peers_obj) }, }; @@ -222,7 +312,7 @@ STATIC MP_DEFINE_CONST_DICT(espnow_locals_dict, espnow_locals_dict_table); // Support ioctl(MP_STREAM_POLL, ) for asyncio STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_check_for_deinit(self); + espnow_check_for_deinit(self); switch (request) { case MP_STREAM_POLL: { mp_uint_t flags = arg; @@ -254,7 +344,7 @@ STATIC const mp_stream_p_t espnow_stream_p = { //| STATIC mp_obj_t espnow_unary_op(mp_unary_op_t op, mp_obj_t self_in) { espnow_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_espnow_check_for_deinit(self); + espnow_check_for_deinit(self); size_t len = ringbuf_num_filled(self->recv_buffer); switch (op) { case MP_UNARY_OP_BOOL: diff --git a/ports/espressif/bindings/espnow/__init__.c b/ports/espressif/bindings/espnow/__init__.c index b76e250f49..da15be49ea 100644 --- a/ports/espressif/bindings/espnow/__init__.c +++ b/ports/espressif/bindings/espnow/__init__.c @@ -27,7 +27,6 @@ #include "bindings/espnow/__init__.h" #include "bindings/espnow/ESPNow.h" #include "bindings/espnow/ESPNowPacket.h" -#include "bindings/espnow/Communicate.h" #include "bindings/espnow/Peer.h" #include "bindings/espnow/Peers.h" @@ -83,7 +82,6 @@ STATIC const mp_rom_map_elem_t espnow_module_globals_table[] = { // module classes { MP_ROM_QSTR(MP_QSTR_ESPNow), MP_ROM_PTR(&espnow_type) }, { MP_ROM_QSTR(MP_QSTR_ESPNowPacket),MP_ROM_PTR(&espnow_packet_type_obj) }, - { MP_ROM_QSTR(MP_QSTR_Communicate), MP_ROM_PTR(&espnow_com_type) }, { MP_ROM_QSTR(MP_QSTR_Peer), MP_ROM_PTR(&espnow_peer_type) }, { MP_ROM_QSTR(MP_QSTR_Peers), MP_ROM_PTR(&espnow_peers_type) }, }; diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index 662da8cf45..a048c7f9f1 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -79,9 +79,9 @@ typedef struct { static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); if (status == ESP_NOW_SEND_SUCCESS) { - self->send->success++; + self->send_success++; } else { - self->send->failure++; + self->send_failure++; } } @@ -93,7 +93,7 @@ static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { ringbuf_t *buf = self->recv_buffer; if (sizeof(espnow_packet_t) + msg_len > ringbuf_num_empty(buf)) { - self->read->failure++; + self->read_failure++; return; } @@ -120,7 +120,7 @@ static void recv_cb(const uint8_t *mac, const uint8_t *msg, int msg_len) { ringbuf_put_n(buf, mac, ESP_NOW_ETH_ALEN); ringbuf_put_n(buf, msg, msg_len); - self->read->success++; + self->read_success++; } bool common_hal_espnow_deinited(espnow_obj_t *self) { @@ -129,14 +129,9 @@ bool common_hal_espnow_deinited(espnow_obj_t *self) { // Construct the ESPNow object void common_hal_espnow_construct(espnow_obj_t *self, mp_int_t buffer_size, mp_int_t phy_rate) { - common_hal_espnow_set_buffer_size(self, buffer_size); common_hal_espnow_set_phy_rate(self, phy_rate); - - self->send = espnow_com_new(MP_QSTR_send); - self->read = espnow_com_new(MP_QSTR_read); - + self->recv_buffer_size = mp_arg_validate_int_min(buffer_size, MIN_PACKET_LEN, MP_QSTR_buffer_size); self->peers = espnow_peers_new(); - common_hal_espnow_init(self); } @@ -185,10 +180,6 @@ void espnow_reset(void) { MP_STATE_PORT(espnow_singleton) = NULL; } -void common_hal_espnow_set_buffer_size(espnow_obj_t *self, mp_int_t value) { - self->recv_buffer_size = mp_arg_validate_int_min(value, MIN_PACKET_LEN, MP_QSTR_buffer_size); -}; - void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value) { self->phy_rate = mp_arg_validate_int_range(value, 0, WIFI_PHY_RATE_MAX - 1, MP_QSTR_phy_rate); }; diff --git a/ports/espressif/common-hal/espnow/ESPNow.h b/ports/espressif/common-hal/espnow/ESPNow.h index 21f1646825..6240788603 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.h +++ b/ports/espressif/common-hal/espnow/ESPNow.h @@ -29,20 +29,20 @@ #include "py/obj.h" #include "py/ringbuf.h" -#include "bindings/espnow/Communicate.h" #include "bindings/espnow/Peers.h" #include "esp_wifi.h" -// The data structure for the espnow_singleton. typedef struct _espnow_obj_t { mp_obj_base_t base; - ringbuf_t *recv_buffer; // A buffer for received packets - size_t recv_buffer_size; // The size of the recv_buffer - wifi_phy_rate_t phy_rate; // The ESP-NOW physical layer rate. - espnow_com_obj_t *send; // For keeping tx stats - espnow_com_obj_t *read; // For keeping rx stats - espnow_peers_obj_t *peers; // The sequence of peers + ringbuf_t *recv_buffer; + size_t recv_buffer_size; + wifi_phy_rate_t phy_rate; + espnow_peers_obj_t *peers; + volatile size_t send_success; + volatile size_t send_failure; + volatile size_t read_success; + volatile size_t read_failure; } espnow_obj_t; extern void espnow_reset(void); @@ -52,7 +52,6 @@ extern void common_hal_espnow_init(espnow_obj_t *self); extern void common_hal_espnow_deinit(espnow_obj_t *self); extern bool common_hal_espnow_deinited(espnow_obj_t *self); -extern void common_hal_espnow_set_buffer_size(espnow_obj_t *self, mp_int_t value); extern void common_hal_espnow_set_phy_rate(espnow_obj_t *self, mp_int_t value); extern void common_hal_espnow_set_pmk(espnow_obj_t *self, const uint8_t *key); diff --git a/ports/espressif/common-hal/espnow/__init__.c b/ports/espressif/common-hal/espnow/__init__.c index 77196f3349..effc752f79 100644 --- a/ports/espressif/common-hal/espnow/__init__.c +++ b/ports/espressif/common-hal/espnow/__init__.c @@ -27,14 +27,6 @@ #include "common-hal/espnow/__init__.h" #include "py/runtime.h" -#include "shared-bindings/util.h" - -// Raise ValueError if the ESPNow object is deinited -void common_hal_espnow_check_for_deinit(espnow_obj_t *self) { - if (common_hal_espnow_deinited(self)) { - raise_deinited_error(); - } -} // Return C pointer to byte memory string/bytes/bytearray in obj. // Raise ValueError if the length does not match expected len. diff --git a/ports/espressif/common-hal/espnow/__init__.h b/ports/espressif/common-hal/espnow/__init__.h index 068da3507a..bb1950d98c 100644 --- a/ports/espressif/common-hal/espnow/__init__.h +++ b/ports/espressif/common-hal/espnow/__init__.h @@ -26,7 +26,5 @@ #pragma once -#include "common-hal/espnow/ESPNow.h" - -extern void common_hal_espnow_check_for_deinit(espnow_obj_t *self); +#include "py/obj.h" extern const uint8_t *common_hal_espnow_get_bytes_len(mp_obj_t obj, size_t len); From 005436278473f6326e41b79edbc612ab5d26b22a Mon Sep 17 00:00:00 2001 From: BrainBoardz <87398149+BrainBoardz@users.noreply.github.com> Date: Thu, 9 Mar 2023 10:26:54 -0500 Subject: [PATCH 21/29] Updated Pin Assignments (Add SPI definition) Changed incorrect i2C pins assignment in mpconfigboard.h (changed SDA/SCL to GPIO 8/GPIO 9. Rename SD_MOSI, SD_MISO and SD_SCK to MOSI, MISO and SCK Added SPI define in mpconfigboard.h for SPI --- ports/espressif/boards/brainboardz_neuron/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/brainboardz_neuron/pins.c b/ports/espressif/boards/brainboardz_neuron/pins.c index b436045b05..5c198c20a7 100755 --- a/ports/espressif/boards/brainboardz_neuron/pins.c +++ b/ports/espressif/boards/brainboardz_neuron/pins.c @@ -63,7 +63,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, - + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, }; From 58f28b98be93a25ebe1d75fbfff2b4a1ebff7009 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+microdev1@users.noreply.github.com> Date: Fri, 10 Mar 2023 00:01:44 +0530 Subject: [PATCH 22/29] minor doc fix Co-authored-by: Scott Shawcroft --- ports/espressif/bindings/espnow/ESPNow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index d2f5d2268f..513966e1e8 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -118,7 +118,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow___exit___obj, 4, 4, espnow_obj //| def send( //| self, //| message: ReadableBuffer, -//| peer: Peer, +//| peer: Optional[Peer] = None, //| ) -> None: //| """Send a message to the peer's mac address. //| From 64ba371f28c2f1a54e40183fa158e95331e128f3 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 10 Mar 2023 15:02:10 +0530 Subject: [PATCH 23/29] conditionally run jobs on push --- .github/workflows/build.yml | 18 ++++++++++++------ .github/workflows/create-website-pr.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bee5afdd6a..4383153fd1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,8 +9,6 @@ on: pull_request: release: types: [published] - check_suite: - types: [rerequested] concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} @@ -64,24 +62,32 @@ jobs: PULL: ${{ github.event.number }} GITHUB_TOKEN: ${{ github.token }} EXCLUDE_COMMIT: ${{ github.event.pull_request.head.sha }} - - name: Set head sha + - name: Set head sha (pull) if: github.event_name == 'pull_request' run: echo "HEAD_SHA=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV - - name: Set base sha + - name: Set base sha (pull) if: github.event_name == 'pull_request' run: | git fetch --no-tags --no-recurse-submodules --depth=$((DEPTH + 1)) origin $HEAD_SHA echo "BASE_SHA=$(git rev-list $HEAD_SHA --skip=$DEPTH --max-count=1)" >> $GITHUB_ENV env: DEPTH: ${{ steps.get-last-commit-with-checks.outputs.commit_depth || github.event.pull_request.commits }} + - name: Set head sha (push) + if: github.event_name == 'push' + run: echo "HEAD_SHA=${{ github.event.after }}" >> $GITHUB_ENV + - name: Set base sha (push) + if: github.event_name == 'push' + run: git cat-file -e $SHA && echo "BASE_SHA=$SHA" >> $GITHUB_ENV || true + env: + SHA: ${{ github.event.before }} - name: Get changes id: get-changes - if: github.event_name == 'pull_request' + if: env.BASE_SHA && env.HEAD_SHA run: echo $(git diff $BASE_SHA...$HEAD_SHA --name-only) | echo "changed_files=[\"$(sed "s/ /\", \"/g")\"]" >> $GITHUB_OUTPUT - name: Set matrix id: set-matrix - working-directory: tools run: python3 -u ci_set_matrix.py + working-directory: tools env: CHANGED_FILES: ${{ steps.get-changes.outputs.changed_files }} LAST_FAILED_JOBS: ${{ steps.get-last-commit-with-checks.outputs.check_runs }} diff --git a/.github/workflows/create-website-pr.yml b/.github/workflows/create-website-pr.yml index eeae8c8299..7f047d4b1e 100644 --- a/.github/workflows/create-website-pr.yml +++ b/.github/workflows/create-website-pr.yml @@ -6,7 +6,7 @@ name: Update CircuitPython.org on: release: - types: [published, rerequested] + types: [published] jobs: website: diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index c0dff33564..2a3fcf9439 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -5,8 +5,8 @@ name: pre-commit on: - pull_request: push: + pull_request: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} From 91d4fed01d80ee515ac50f19d98d9a0625131885 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Fri, 10 Mar 2023 16:41:13 +0530 Subject: [PATCH 24/29] explicitly check for failure of certain jobs --- tools/ci_changes_per_commit.py | 18 +++++++++--------- tools/ci_set_matrix.py | 3 --- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tools/ci_changes_per_commit.py b/tools/ci_changes_per_commit.py index e83a702b22..58e86148ed 100644 --- a/tools/ci_changes_per_commit.py +++ b/tools/ci_changes_per_commit.py @@ -171,8 +171,7 @@ def get_bad_check_runs(query_check_runs): more_pages = True run_types = ["failed", "incomplete"] - - regex_matrix = re.compile(r"^\S+ \/ (build|run) \(\S+\)$") + have_dependent_jobs = ["scheduler", "mpy-cross", "tests"] while more_pages: check_runs = query_check_runs.fetch()["data"]["node"] @@ -184,15 +183,16 @@ def get_bad_check_runs(query_check_runs): for check_run in check_runs[run_type]["nodes"]: name = check_run["name"] - if name.startswith("ports") or regex_matrix.search(name): - matrix = name.split(" ", 1)[0] - matrix_job = name.rsplit(" (", 1)[1][:-1] - bad_runs.setdefault(matrix, []).append(matrix_job) - elif name != "scheduler": - bad_runs[name] = True - else: + + if any([name.startswith(job) for job in have_dependent_jobs]): return {} + if name.startswith("ports"): + matrix_job = name.rsplit(" (", 1)[1][:-1] + bad_runs.setdefault("ports", []).append(matrix_job) + else: + bad_runs[name] = True + if query_check_runs.paginate( check_runs[run_type]["pageInfo"], "after" + run_type_camel ): diff --git a/tools/ci_set_matrix.py b/tools/ci_set_matrix.py index fe823ac030..b5618aec2f 100755 --- a/tools/ci_set_matrix.py +++ b/tools/ci_set_matrix.py @@ -98,9 +98,6 @@ def set_output(name: str, value): def set_boards(build_all: bool): - if last_failed_jobs.get("mpy-cross") or last_failed_jobs.get("tests"): - build_all = True - # Get boards in json format boards_info_json = build_board_info.get_board_mapping() all_board_ids = set() From 77ec3e4b76005d780a9868a1099f61b1b7da0bde Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Fri, 10 Mar 2023 18:22:08 +0100 Subject: [PATCH 25/29] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/ID.po | 30 +++++++++++++++--------------- locale/cs.po | 30 +++++++++++++++--------------- locale/de_DE.po | 30 +++++++++++++++--------------- locale/el.po | 30 +++++++++++++++--------------- locale/en_GB.po | 30 +++++++++++++++--------------- locale/es.po | 30 +++++++++++++++--------------- locale/fil.po | 30 +++++++++++++++--------------- locale/fr.po | 30 +++++++++++++++--------------- locale/hi.po | 30 +++++++++++++++--------------- locale/it_IT.po | 30 +++++++++++++++--------------- locale/ja.po | 30 +++++++++++++++--------------- locale/ko.po | 30 +++++++++++++++--------------- locale/nl.po | 30 +++++++++++++++--------------- locale/pl.po | 30 +++++++++++++++--------------- locale/pt_BR.po | 30 +++++++++++++++--------------- locale/ru.po | 30 +++++++++++++++--------------- locale/sv.po | 30 +++++++++++++++--------------- locale/tr.po | 30 +++++++++++++++--------------- locale/zh_Latn_pinyin.po | 30 +++++++++++++++--------------- 19 files changed, 285 insertions(+), 285 deletions(-) diff --git a/locale/ID.po b/locale/ID.po index b30c7d5d9c..f6960665b4 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -147,7 +147,7 @@ msgstr "%q indeks di luar batas" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -245,7 +245,7 @@ msgstr "%q, %q, dan %q semuanya harus memiliki panjang yang sama" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s kesalahan 0x%x" @@ -513,6 +513,7 @@ msgstr "Sudah disebarkan." msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -686,7 +687,7 @@ msgstr "Blok CBC harus merupakan kelipatan 16 byte" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1082,7 +1083,7 @@ msgstr "Fungsinya membutuhkan kunci" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1267,8 +1268,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Argumen tidak valid" @@ -1294,7 +1294,7 @@ msgstr "Ukuran potongan format tidak valid" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1303,7 +1303,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1335,7 +1335,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1696,11 +1696,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "Waktu habis" @@ -1708,7 +1708,7 @@ msgstr "Waktu habis" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Kehabisan memori" @@ -1891,7 +1891,7 @@ msgstr "Baca-saja" msgid "Read-only filesystem" msgstr "sistem file (filesystem) bersifat Read-only" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1911,7 +1911,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "Mode AES yang diminta tidak didukung" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2366,7 +2366,7 @@ msgstr "Panjang nilai != Panjang tetap yang dibutuhkan" msgid "Value length > max_length" msgstr "Panjang nilai > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/cs.po b/locale/cs.po index 164f9c42ad..0ffdbdcc67 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -148,7 +148,7 @@ msgstr "Index %q je mimo rozsah" msgid "%q init failed" msgstr "Inicializace %q selhala" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -246,7 +246,7 @@ msgstr "%q, %q, a %q musí mít všechny shodnou délku" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s chyba 0x%x" @@ -514,6 +514,7 @@ msgstr "Již propagujeme." msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -687,7 +688,7 @@ msgstr "Bloky CBC musí být násobky 16 bajtů" msgid "CIRCUITPY drive could not be found or created." msgstr "Disk CIRCUITPY nelze nalézt nebo vytvořit." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1082,7 +1083,7 @@ msgstr "Funkce vyžaduje zámek" msgid "GNSS init" msgstr "Inicializace GNSS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Základní chyba" @@ -1267,8 +1268,7 @@ msgstr "Chybné BSSID" msgid "Invalid MAC address" msgstr "Chybná MAC adresa" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Neplatný argument" @@ -1294,7 +1294,7 @@ msgstr "Neplatná velikost bloku" msgid "Invalid multicast MAC address" msgstr "Chybná multicastová MAC adresa" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Chybná velikost" @@ -1303,7 +1303,7 @@ msgstr "Chybná velikost" msgid "Invalid socket for TLS" msgstr "Chybný soket pro TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Chybný stav" @@ -1335,7 +1335,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC adresa byla chybná" @@ -1692,11 +1692,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1704,7 +1704,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1882,7 +1882,7 @@ msgstr "" msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1902,7 +1902,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2353,7 +2353,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index fd309dd287..9f2c83e8cc 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -155,7 +155,7 @@ msgstr "Der Index %q befindet sich außerhalb des Bereiches" msgid "%q init failed" msgstr "%q Initialisierung ist gescheitert" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%q ist %q" @@ -255,7 +255,7 @@ msgstr "%q, %q und %q müssen alle die gleiche Länge haben" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s Fehler 0x%x" @@ -523,6 +523,7 @@ msgstr "Bereits am Anbieten (advertising)." msgid "Already have all-matches listener" msgstr "All-Matchers-Listener bereits vorhanden" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -696,7 +697,7 @@ msgstr "CBC-Blöcke müssen ein Vielfaches von 16 Bytes sein" msgid "CIRCUITPY drive could not be found or created." msgstr "CIRCUITPY-Laufwerk konnte nicht gefunden oder erzeugt werden." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC oder Checksumme ungültig" @@ -1101,7 +1102,7 @@ msgstr "Die Funktion erwartet, dass der 'lock'-Befehl zuvor ausgeführt wurde" msgid "GNSS init" msgstr "GNSS-Initialisierung" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Generischer Fehler" @@ -1290,8 +1291,7 @@ msgstr "Ungültige BSSID" msgid "Invalid MAC address" msgstr "Ungültige MAC-Adresse" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Ungültiges Argument" @@ -1317,7 +1317,7 @@ msgstr "Ungültige format chunk size" msgid "Invalid multicast MAC address" msgstr "Ungültige Multicast-MAC-Adresse" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Ungültige Größe" @@ -1326,7 +1326,7 @@ msgstr "Ungültige Größe" msgid "Invalid socket for TLS" msgstr "Ungültiges Socket für TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Ungültiger Zustand" @@ -1358,7 +1358,7 @@ msgstr "Ebene ist bereits in der Gruppe" msgid "Layer must be a Group or TileGrid subclass" msgstr "Ebene muss eine Gruppe oder eine TileGrid Subklasse sein" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC Adresse war ungültig" @@ -1721,11 +1721,11 @@ msgstr "Nur eine Farbe kann transparent sein zu einer Zeit" msgid "Operation not permitted" msgstr "Operation nicht erlaubt" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "Vorgang oder Funktion wird nicht unterstützt" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "Zeit für Vorgang abgelaufen" @@ -1733,7 +1733,7 @@ msgstr "Zeit für Vorgang abgelaufen" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Kein Speicher mehr verfügbar" @@ -1915,7 +1915,7 @@ msgstr "Nur lesen möglich, da Schreibgeschützt" msgid "Read-only filesystem" msgstr "Schreibgeschützte Dateisystem" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "Erhaltene Antwort ist ungültig" @@ -1935,7 +1935,7 @@ msgstr "RemoteTransmissionRequests limitiert auf 8 Bytes" msgid "Requested AES mode is unsupported" msgstr "Der angeforderte AES-Modus wird nicht unterstützt" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "Angefragte Ressource nicht gefunden" @@ -2396,7 +2396,7 @@ msgstr "Wert Länge != Erforderliche feste Länge" msgid "Value length > max_length" msgstr "Länge des Wertes > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "Version ist ungültig" diff --git a/locale/el.po b/locale/el.po index b36d0a39b6..81118aa8fd 100644 --- a/locale/el.po +++ b/locale/el.po @@ -152,7 +152,7 @@ msgstr "%q δείκτης εκτός εμβέλειας" msgid "%q init failed" msgstr "%q εκκίνηση απέτυχε" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -250,7 +250,7 @@ msgstr "%q, %q, και %q πρέπει να είναι όλα του ιδίου msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s σφάλμα 0x%x" @@ -519,6 +519,7 @@ msgstr "Ήδη διαφημίζουμε." msgid "Already have all-matches listener" msgstr "Ύπάρχει ήδη all-matches ακροατής" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -692,7 +693,7 @@ msgstr "CBC blocks πρέπει να είναι πολλαπλάσια του 16 msgid "CIRCUITPY drive could not be found or created." msgstr "Ο CIRCUITPY δίσκος δεν μπόρεσε να βρεθεί ή να δημιουργηθεί." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC ή checksum ήταν άκυρο" @@ -1093,7 +1094,7 @@ msgstr "" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1276,8 +1277,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "" @@ -1303,7 +1303,7 @@ msgstr "" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1312,7 +1312,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1344,7 +1344,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1700,11 +1700,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1712,7 +1712,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1890,7 +1890,7 @@ msgstr "" msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1910,7 +1910,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2361,7 +2361,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/en_GB.po b/locale/en_GB.po index b1c1c46b50..9ced3137b9 100644 --- a/locale/en_GB.po +++ b/locale/en_GB.po @@ -151,7 +151,7 @@ msgstr "%q index out of range" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -249,7 +249,7 @@ msgstr "%q, %q, and %q must all be the same length" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s error 0x%x" @@ -517,6 +517,7 @@ msgstr "Already advertising." msgid "Already have all-matches listener" msgstr "Already have all-matches listener" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -690,7 +691,7 @@ msgstr "CBC blocks must be multiples of 16 bytes" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC or checksum was invalid" @@ -1083,7 +1084,7 @@ msgstr "Function requires lock" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Generic Failure" @@ -1268,8 +1269,7 @@ msgstr "Invalid BSSID" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Invalid argument" @@ -1295,7 +1295,7 @@ msgstr "Invalid format chunk size" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Invalid size" @@ -1304,7 +1304,7 @@ msgstr "Invalid size" msgid "Invalid socket for TLS" msgstr "Invalid socket for TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Invalid state" @@ -1336,7 +1336,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC address was invalid" @@ -1696,11 +1696,11 @@ msgstr "Only one colour can be transparent at a time" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "Operation or feature not supported" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "Operation timed out" @@ -1708,7 +1708,7 @@ msgstr "Operation timed out" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Out of memory" @@ -1888,7 +1888,7 @@ msgstr "Read-only" msgid "Read-only filesystem" msgstr "Read-only filesystem" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "Received response was invalid" @@ -1908,7 +1908,7 @@ msgstr "RemoteTransmissionRequests limited to 8 bytes" msgid "Requested AES mode is unsupported" msgstr "Requested AES mode is unsupported" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "Requested resource not found" @@ -2361,7 +2361,7 @@ msgstr "Value length != required fixed length" msgid "Value length > max_length" msgstr "Value length > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "Version was invalid" diff --git a/locale/es.po b/locale/es.po index ee2c98a23b..ee2af9d603 100644 --- a/locale/es.po +++ b/locale/es.po @@ -163,7 +163,7 @@ msgstr "%q índice fuera de rango" msgid "%q init failed" msgstr "%q inicializado fallido" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%q es %q" @@ -261,7 +261,7 @@ msgstr "%q, %q, y %q deben tener la misma longitud" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s error 0x%x" @@ -531,6 +531,7 @@ msgstr "Ya se encuentra publicando." msgid "Already have all-matches listener" msgstr "Ya se tiene un escucha de todas las coincidencias" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -706,7 +707,7 @@ msgstr "Los bloques CBC deben ser múltiplos de 16 bytes" msgid "CIRCUITPY drive could not be found or created." msgstr "El dispositivo CIRCUITPY no pudo ser encontrado o creado." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC o suma de comprobación inválida" @@ -1112,7 +1113,7 @@ msgstr "La función requiere lock" msgid "GNSS init" msgstr "Inicialización GNSS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Fallo Genérico" @@ -1305,8 +1306,7 @@ msgstr "BSSID inválido" msgid "Invalid MAC address" msgstr "Dirección MAC inválida" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Argumento inválido" @@ -1332,7 +1332,7 @@ msgstr "Formato de fragmento de formato no válido" msgid "Invalid multicast MAC address" msgstr "Dirección MAC de multidifusión inválida" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Tamaño incorrecto" @@ -1341,7 +1341,7 @@ msgstr "Tamaño incorrecto" msgid "Invalid socket for TLS" msgstr "socket invalido para TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Estado invalido" @@ -1373,7 +1373,7 @@ msgstr "El Layer ya esta en un grupo" msgid "Layer must be a Group or TileGrid subclass" msgstr "El Layer debe ser un grupo o una subclase de TileGrid" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "La dirección MAC es incorrecta" @@ -1739,11 +1739,11 @@ msgstr "Solo un color puede ser transparente a la vez" msgid "Operation not permitted" msgstr "La operación no es permitida" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "Operación no característica no soportada" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "Tiempo de espera agotado" @@ -1751,7 +1751,7 @@ msgstr "Tiempo de espera agotado" msgid "Out of MDNS service slots" msgstr "No hay slots MDNS de servicio" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Memoria agotada" @@ -1935,7 +1935,7 @@ msgstr "Solo-lectura" msgid "Read-only filesystem" msgstr "Sistema de archivos de solo-Lectura" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "La respuesta recibida es invalida" @@ -1955,7 +1955,7 @@ msgstr "RemoteTransmissionRequests limitado a 8 bytes" msgid "Requested AES mode is unsupported" msgstr "El modo AES solicitado no es compatible" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "Recurso solicitado no encontrado" @@ -2416,7 +2416,7 @@ msgstr "Tamaño del valor != del tamaño fijo requerido" msgid "Value length > max_length" msgstr "Tamaño de valor > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "La versión era invalida" diff --git a/locale/fil.po b/locale/fil.po index 02b8fda384..f943746a34 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -145,7 +145,7 @@ msgstr "%q indeks wala sa sakop" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -244,7 +244,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "" @@ -513,6 +513,7 @@ msgstr "" msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -687,7 +688,7 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1082,7 +1083,7 @@ msgstr "Function nangangailangan ng lock" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1267,8 +1268,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Maling argumento" @@ -1294,7 +1294,7 @@ msgstr "Mali ang format ng chunk size" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1303,7 +1303,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1335,7 +1335,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1694,11 +1694,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1706,7 +1706,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1883,7 +1883,7 @@ msgstr "Basahin-lamang" msgid "Read-only filesystem" msgstr "Basahin-lamang mode" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1903,7 +1903,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2356,7 +2356,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/fr.po b/locale/fr.po index 322314b018..424e16a1b5 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -160,7 +160,7 @@ msgstr "index %q hors de portée" msgid "%q init failed" msgstr "échec de l'initialisation %q" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -258,7 +258,7 @@ msgstr "%q, %q, et %q doivent tous être de la même longueur" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s erreur 0x%x" @@ -526,6 +526,7 @@ msgstr "S'annonce déjà." msgid "Already have all-matches listener" msgstr "Il y a déjà un auditeur all-matches" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -701,7 +702,7 @@ msgstr "Les blocs CBC doivent être des multiples de 16 octets" msgid "CIRCUITPY drive could not be found or created." msgstr "L'appareil CIRCUITPY ne peut pas être trouvé ou créé." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC ou somme de contrôle invalide" @@ -1115,7 +1116,7 @@ msgstr "La fonction nécessite un verrou ('lock')" msgid "GNSS init" msgstr "Initialisation GNSS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Échec génerique" @@ -1311,8 +1312,7 @@ msgstr "BSSID invalide" msgid "Invalid MAC address" msgstr "Adresse MAC invalide" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Paramètre invalide" @@ -1338,7 +1338,7 @@ msgstr "Taille de bloc de formatage invalide" msgid "Invalid multicast MAC address" msgstr "Adresse MAC multicast invalide" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Taille invalide" @@ -1347,7 +1347,7 @@ msgstr "Taille invalide" msgid "Invalid socket for TLS" msgstr "Socket non valide pour TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "État invalide" @@ -1379,7 +1379,7 @@ msgstr "Ce calque est déjà dans un groupe" msgid "Layer must be a Group or TileGrid subclass" msgstr "Le calque doit être une sous-classe de Group ou TileGrid" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "Adresse physique (MAC) invalide" @@ -1745,11 +1745,11 @@ msgstr "Une seule couleur peut être transparente à la fois" msgid "Operation not permitted" msgstr "Cette opération n'est pas permise" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "Opération ou fonction non supportée" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "Timeout de l'opération" @@ -1757,7 +1757,7 @@ msgstr "Timeout de l'opération" msgid "Out of MDNS service slots" msgstr "À cours de services MDNS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Mémoire insuffisante" @@ -1942,7 +1942,7 @@ msgstr "Lecture seule" msgid "Read-only filesystem" msgstr "Système de fichier en lecture seule" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "Réponse reçue invalide" @@ -1962,7 +1962,7 @@ msgstr "RemoteTransmissionRequests limité à 8 octets" msgid "Requested AES mode is unsupported" msgstr "Le mode AES demandé n'est pas supporté" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "Resource demandée non trouvée" @@ -2423,7 +2423,7 @@ msgstr "Longueur de valeur != Longueur fixe requise" msgid "Value length > max_length" msgstr "Longueur de la valeur > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "Version est invalide" diff --git a/locale/hi.po b/locale/hi.po index 649b98c521..94a42e19f8 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -144,7 +144,7 @@ msgstr "" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -242,7 +242,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "" @@ -510,6 +510,7 @@ msgstr "" msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -681,7 +682,7 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1072,7 +1073,7 @@ msgstr "" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1255,8 +1256,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "" @@ -1282,7 +1282,7 @@ msgstr "" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1291,7 +1291,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1323,7 +1323,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1679,11 +1679,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1691,7 +1691,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1867,7 +1867,7 @@ msgstr "" msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1887,7 +1887,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2338,7 +2338,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/it_IT.po b/locale/it_IT.po index a6ab324c58..5fb7e50d6b 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -148,7 +148,7 @@ msgstr "indice %q fuori intervallo" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -246,7 +246,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s errore 0x%x" @@ -516,6 +516,7 @@ msgstr "" msgid "Already have all-matches listener" msgstr "Già in possesso di tutti i listener abbinati" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -690,7 +691,7 @@ msgstr "I blocchi CBC devono essere multipli di 16 bytes" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC o controllo totale è risultato non valido" @@ -1084,7 +1085,7 @@ msgstr "" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1269,8 +1270,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Argomento non valido" @@ -1296,7 +1296,7 @@ msgstr "" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1305,7 +1305,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1337,7 +1337,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1698,11 +1698,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1710,7 +1710,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1890,7 +1890,7 @@ msgstr "Sola lettura" msgid "Read-only filesystem" msgstr "Filesystem in sola lettura" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1910,7 +1910,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2363,7 +2363,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/ja.po b/locale/ja.po index e8a70816c8..7e63cb55c3 100644 --- a/locale/ja.po +++ b/locale/ja.po @@ -151,7 +151,7 @@ msgstr "%q インデックスは範囲外" msgid "%q init failed" msgstr "%qは初期化には失敗" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%qは%q" @@ -249,7 +249,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "" @@ -517,6 +517,7 @@ msgstr "すでにアドバータイズ中" msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -690,7 +691,7 @@ msgstr "CBCブロックは16バイトの整数倍でなければなりません" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1083,7 +1084,7 @@ msgstr "" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1268,8 +1269,7 @@ msgstr "不正なBSSID" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "不正な引数" @@ -1295,7 +1295,7 @@ msgstr "フォーマットチャンクのサイズが不正" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1304,7 +1304,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1336,7 +1336,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1694,11 +1694,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1706,7 +1706,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1883,7 +1883,7 @@ msgstr "読み込み専用" msgid "Read-only filesystem" msgstr "読み込み専用のファイルシステム" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1903,7 +1903,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "要求のAESモードは非対応" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2355,7 +2355,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 6b09cf6e94..129c9b4bcd 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -145,7 +145,7 @@ msgstr "%q 인덱스 범위를 벗어났습니다" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -243,7 +243,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "" @@ -511,6 +511,7 @@ msgstr "" msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -684,7 +685,7 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1075,7 +1076,7 @@ msgstr "" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1258,8 +1259,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "" @@ -1285,7 +1285,7 @@ msgstr "형식 청크 크기가 잘못되었습니다" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1294,7 +1294,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1326,7 +1326,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1682,11 +1682,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1694,7 +1694,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1870,7 +1870,7 @@ msgstr "" msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1890,7 +1890,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2342,7 +2342,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/nl.po b/locale/nl.po index 90c3e8130e..87fdb61c60 100644 --- a/locale/nl.po +++ b/locale/nl.po @@ -144,7 +144,7 @@ msgstr "%q index buiten bereik" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -242,7 +242,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "" @@ -510,6 +510,7 @@ msgstr "Advertising is al bezig." msgid "Already have all-matches listener" msgstr "Heeft al een luisteraar voor 'all-matches'" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -683,7 +684,7 @@ msgstr "CBC blocks moeten meervouden van 16 bytes zijn" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1078,7 +1079,7 @@ msgstr "Functie vereist lock" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1263,8 +1264,7 @@ msgstr "Ongeldig BSSID" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Ongeldig argument" @@ -1290,7 +1290,7 @@ msgstr "Ongeldig formaat stuk grootte" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "" @@ -1299,7 +1299,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "" @@ -1331,7 +1331,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1693,11 +1693,11 @@ msgstr "Er kan maar één kleur per keer transparant zijn" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1705,7 +1705,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1888,7 +1888,7 @@ msgstr "Alleen-lezen" msgid "Read-only filesystem" msgstr "Alleen-lezen bestandssysteem" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1908,7 +1908,7 @@ msgstr "RemoteTransmissionRequests is beperkt tot 8 bytes" msgid "Requested AES mode is unsupported" msgstr "Gevraagde AES modus is niet ondersteund" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2361,7 +2361,7 @@ msgstr "Waarde lengte != vereist vaste lengte" msgid "Value length > max_length" msgstr "Waarde length > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/pl.po b/locale/pl.po index b48ca01b81..1348c0f321 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -146,7 +146,7 @@ msgstr "%q poza zakresem" msgid "%q init failed" msgstr "" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "" @@ -244,7 +244,7 @@ msgstr "" msgid "%q=%q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "" @@ -512,6 +512,7 @@ msgstr "" msgid "Already have all-matches listener" msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -685,7 +686,7 @@ msgstr "Bloki CBC muszą być wielokrotnościami 16 bajtów" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -1078,7 +1079,7 @@ msgstr "Funkcja wymaga blokady" msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1263,8 +1264,7 @@ msgstr "" msgid "Invalid MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Zły argument" @@ -1290,7 +1290,7 @@ msgstr "Zła wielkość fragmentu formatu" msgid "Invalid multicast MAC address" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Nieprawidłowy rozmiar" @@ -1299,7 +1299,7 @@ msgstr "Nieprawidłowy rozmiar" msgid "Invalid socket for TLS" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Nieprawidłowy stan" @@ -1331,7 +1331,7 @@ msgstr "" msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "" @@ -1687,11 +1687,11 @@ msgstr "W danym momencie przezroczysty może być tylko jeden kolor" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1699,7 +1699,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Brak pamięci" @@ -1875,7 +1875,7 @@ msgstr "Tylko do odczytu" msgid "Read-only filesystem" msgstr "System plików tylko do odczytu" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "Otrzymana odpowiedź była nieprawidłowa" @@ -1895,7 +1895,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "Żądany tryb AES nie jest obsługiwany" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "Nie znaleziono żądanego zasobu" @@ -2346,7 +2346,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 618f8c6379..fdf2eaaf31 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -161,7 +161,7 @@ msgstr "O índice %q está fora do intervalo" msgid "%q init failed" msgstr "a inicialização do %q falhou" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%q é %q" @@ -259,7 +259,7 @@ msgstr "todos os %q, %q, e %q devem ter mesmo comprimento" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s erro 0x%x" @@ -531,6 +531,7 @@ msgstr "Já está anunciando." msgid "Already have all-matches listener" msgstr "Já há um ouvinte com todas as correspondências" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -706,7 +707,7 @@ msgstr "Os blocos CBC devem ter múltiplos de 16 bytes" msgid "CIRCUITPY drive could not be found or created." msgstr "A unidade CIRCUITPY não pôde ser encontrada nem criada." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC ou checksum inválido" @@ -1108,7 +1109,7 @@ msgstr "A função requer bloqueio" msgid "GNSS init" msgstr "Inicialização do GNSS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Falha Genérica" @@ -1301,8 +1302,7 @@ msgstr "BSSID Inválido" msgid "Invalid MAC address" msgstr "Endereço MAC inválido" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Argumento inválido" @@ -1328,7 +1328,7 @@ msgstr "Tamanho do pedaço de formato inválido" msgid "Invalid multicast MAC address" msgstr "Endereço MAC multicast inválido" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Tamanho inválido" @@ -1337,7 +1337,7 @@ msgstr "Tamanho inválido" msgid "Invalid socket for TLS" msgstr "Soquete inválido para o TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Estado inválido" @@ -1369,7 +1369,7 @@ msgstr "Camada já está num grupo" msgid "Layer must be a Group or TileGrid subclass" msgstr "A camada deve ser uma subclasse Group ou TileGrid" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "Endereço MAC inválido" @@ -1732,11 +1732,11 @@ msgstr "Apenas uma cor pode ser transparente de cada vez" msgid "Operation not permitted" msgstr "A operação não é permitida" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "A operação ou o recurso não é suportado" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "A operação expirou" @@ -1744,7 +1744,7 @@ msgstr "A operação expirou" msgid "Out of MDNS service slots" msgstr "Sem slots do serviço MDNS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Sem memória" @@ -1930,7 +1930,7 @@ msgstr "Somente leitura" msgid "Read-only filesystem" msgstr "Sistema de arquivos somente leitura" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "A resposta recebida foi inválida" @@ -1950,7 +1950,7 @@ msgstr "As requisições de transmissões remotas é limitada a 8 bytes" msgid "Requested AES mode is unsupported" msgstr "O modo AES solicitado não é compatível" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "O recurso solicitado não foi encontrado" @@ -2410,7 +2410,7 @@ msgstr "Comprimento do valor != comprimento fixo necessário" msgid "Value length > max_length" msgstr "O comprimento do valor é > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "A versão era inválida" diff --git a/locale/ru.po b/locale/ru.po index 50249c621d..0fe6cfac97 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -151,7 +151,7 @@ msgstr "Индекс %q вне диапазона" msgid "%q init failed" msgstr "Инициализация %q не удалась" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%q является %q" @@ -249,7 +249,7 @@ msgstr "%q, %q, и %q должны быть одной длинны" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s ошибка 0x%x" @@ -517,6 +517,7 @@ msgstr "Уже объявляемся (advertising)." msgid "Already have all-matches listener" msgstr "Уже есть универсальный слушатель" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -694,7 +695,7 @@ msgstr "Блоки CBC должны быть кратны 16 байтам" msgid "CIRCUITPY drive could not be found or created." msgstr "Не удалось найти или создать диск CIRCUITPY." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC или контрольная сумма неправильная" @@ -1109,7 +1110,7 @@ msgstr "Функция требует блокировки" msgid "GNSS init" msgstr "Инициализация GNSS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Общий сбой" @@ -1300,8 +1301,7 @@ msgstr "Неверный BSSID" msgid "Invalid MAC address" msgstr "Неверный MAC-адрес" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Недопустимый аргумент" @@ -1327,7 +1327,7 @@ msgstr "Неверный размер блока формата" msgid "Invalid multicast MAC address" msgstr "Неверный MAC-адрес multicast" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Неверный размер" @@ -1336,7 +1336,7 @@ msgstr "Неверный размер" msgid "Invalid socket for TLS" msgstr "Неверный сокет для TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Неверное состояние" @@ -1370,7 +1370,7 @@ msgstr "Слой уже в группе (Group)" msgid "Layer must be a Group or TileGrid subclass" msgstr "Слой должен быть группой (Group) или субклассом TileGrid." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC адрес был недействительным" @@ -1735,11 +1735,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1747,7 +1747,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1928,7 +1928,7 @@ msgstr "" msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1948,7 +1948,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2401,7 +2401,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/sv.po b/locale/sv.po index 6ba1cdc1a2..84ce4b6ecb 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -160,7 +160,7 @@ msgstr "Index %q ligger utanför intervallet" msgid "%q init failed" msgstr "%q init misslyckades" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%q är %q" @@ -260,7 +260,7 @@ msgstr "%q, %q och %q måste vara lika långa" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s fel 0x%x" @@ -528,6 +528,7 @@ msgstr "Annonserar redan." msgid "Already have all-matches listener" msgstr "Har redan lyssnare för all-matchningar" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -701,7 +702,7 @@ msgstr "CBC-block måste vara multiplar om 16 byte" msgid "CIRCUITPY drive could not be found or created." msgstr "CIRCUITPY-enheten kunde inte hittas eller skapas." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC eller checksumma var ogiltig" @@ -1099,7 +1100,7 @@ msgstr "Funktionen kräver lås" msgid "GNSS init" msgstr "GNSS start" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "Allmänt fel" @@ -1286,8 +1287,7 @@ msgstr "Ogiltig BSSID" msgid "Invalid MAC address" msgstr "Ogiltig MAC-adress" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Ogiltigt argument" @@ -1313,7 +1313,7 @@ msgstr "Ogiltig formatsegmentstorlek" msgid "Invalid multicast MAC address" msgstr "Ogiltig MAC-adress för multicast" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Ogiltig storlek" @@ -1322,7 +1322,7 @@ msgstr "Ogiltig storlek" msgid "Invalid socket for TLS" msgstr "Ogiltig socket för TLS" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Ogiltigt tillstånd" @@ -1354,7 +1354,7 @@ msgstr "Layer är redan med i en grupp" msgid "Layer must be a Group or TileGrid subclass" msgstr "Layer måste vara en underklass av Group eller TileGrid" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC-adressen var ogiltig" @@ -1716,11 +1716,11 @@ msgstr "Bara en färg kan vara genomskinlig i taget" msgid "Operation not permitted" msgstr "Åtgärden inte tillåten" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "Operation eller funktion stöds inte" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "Åtgärden orsakade timeout" @@ -1728,7 +1728,7 @@ msgstr "Åtgärden orsakade timeout" msgid "Out of MDNS service slots" msgstr "Slut på MDNS-serviceplatser" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "Slut på minne" @@ -1911,7 +1911,7 @@ msgstr "Skrivskyddad" msgid "Read-only filesystem" msgstr "Skrivskyddat filsystem" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "Mottaget svar var ogiltigt" @@ -1931,7 +1931,7 @@ msgstr "RemoteTransmissionRequests begränsad till 8 byte" msgid "Requested AES mode is unsupported" msgstr "Det begärda AES-läget stöds inte" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "Begärd resurs hittades inte" @@ -2386,7 +2386,7 @@ msgstr "Värdets längde ! = krävd fast längd" msgid "Value length > max_length" msgstr "Värdets längd > max_length" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "Versionen var ogiltig" diff --git a/locale/tr.po b/locale/tr.po index 74e44c2d8d..67a73375ea 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -152,7 +152,7 @@ msgstr "%q indeksi aralık dışında" msgid "%q init failed" msgstr "%q init başarısız oldu" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%q %q dir" @@ -250,7 +250,7 @@ msgstr "%q, %q ve %q aynı uzunlukta olmalıdır" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s hatası 0x%x" @@ -519,6 +519,7 @@ msgstr "Halihazırda duyuruluyor." msgid "Already have all-matches listener" msgstr "Tüm eşleşmelerle eşleşen dinleyiciniz var" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -692,7 +693,7 @@ msgstr "CBC blokları 16 baytın katları şeklinde olmalı" msgid "CIRCUITPY drive could not be found or created." msgstr "CIRCUITPY sürücüsü bulunamadı veya oluşturulamadı." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC yada checksum geçersiz" @@ -1088,7 +1089,7 @@ msgstr "Fonksiyon kilit gerektirir" msgid "GNSS init" msgstr "GNSS init" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "" @@ -1273,8 +1274,7 @@ msgstr "Geçersiz BSSID" msgid "Invalid MAC address" msgstr "Geçersiz MAC adresi" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Geçersiz argüman" @@ -1301,7 +1301,7 @@ msgstr "Geçersiz biçim yığın boyutu" msgid "Invalid multicast MAC address" msgstr "Geçersiz multicast MAC adresi" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "Geçersiz boyut" @@ -1310,7 +1310,7 @@ msgstr "Geçersiz boyut" msgid "Invalid socket for TLS" msgstr "TLS için geçersiz soket" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "Geçersiz durum" @@ -1342,7 +1342,7 @@ msgstr "Katman zaten bir grupta" msgid "Layer must be a Group or TileGrid subclass" msgstr "Katman, bir Grup ya da TileGrid alt sınıfı olmalıdır" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC adresi geçersiz" @@ -1698,11 +1698,11 @@ msgstr "" msgid "Operation not permitted" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "" @@ -1710,7 +1710,7 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "" @@ -1889,7 +1889,7 @@ msgstr "" msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "" @@ -1909,7 +1909,7 @@ msgstr "" msgid "Requested AES mode is unsupported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "" @@ -2360,7 +2360,7 @@ msgstr "" msgid "Value length > max_length" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index ea9fa2fc68..485c30353d 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -163,7 +163,7 @@ msgstr "%q suǒyǐn chāochū fànwéi" msgid "%q init failed" msgstr "%q chūshǐhuà shībài" -#: shared-bindings/dualbank/__init__.c +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c msgid "%q is %q" msgstr "%q shì %q" @@ -262,7 +262,7 @@ msgstr "%q, %q, hé %q bì xū cháng dù xiāng tóng" msgid "%q=%q" msgstr "%q=%q" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format msgid "%s error 0x%x" msgstr "%s cuò wù 0x%x" @@ -530,6 +530,7 @@ msgstr "Mùqián zhèngzài guǎngbō." msgid "Already have all-matches listener" msgstr "yǐjīng yǒu all-matches jiāntīng qì" +#: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c #: shared-module/memorymonitor/AllocationAlarm.c #: shared-module/memorymonitor/AllocationSize.c @@ -703,7 +704,7 @@ msgstr "CBC kuài bìxū shì 16 zìjié de bèishù" msgid "CIRCUITPY drive could not be found or created." msgstr "zhǎo bú dào huò chuàng jiàn CIRCUITPY qū dòng qì." -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "CRC huò jiàoyàn hé wúxiào" @@ -1103,7 +1104,7 @@ msgstr "Hánshù xūyào suǒdìng" msgid "GNSS init" msgstr "GNSS chūshǐhuà" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" msgstr "tōng yòng gù zhàng" @@ -1293,8 +1294,7 @@ msgstr "Wúxiào de BSSID" msgid "Invalid MAC address" msgstr "wú xiào de MAC dì zhǐ" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c -#: py/moduerrno.c +#: ports/espressif/common-hal/espidf/__init__.c py/moduerrno.c msgid "Invalid argument" msgstr "Wúxiào de cānshù" @@ -1320,7 +1320,7 @@ msgstr "Géshì kuài dàxiǎo wúxiào" msgid "Invalid multicast MAC address" msgstr "wú xiào de duō bō MAC dì zhǐ" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" msgstr "dà xiǎo wú xiào" @@ -1329,7 +1329,7 @@ msgstr "dà xiǎo wú xiào" msgid "Invalid socket for TLS" msgstr "TLS de chā zuò wú xiào" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid state" msgstr "wú xiào zhuàng tài" @@ -1361,7 +1361,7 @@ msgstr "tú céng yǐ zài zǔ zhōng" msgid "Layer must be a Group or TileGrid subclass" msgstr "tú céng bìxū shì zǔ huò píng pū wǎng gé zi lèi" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" msgstr "MAC dì zhǐ wú xiào" @@ -1723,11 +1723,11 @@ msgstr "Yīcì zhǐ néng yǒuyī zhǒng yánsè shì tòumíng de" msgid "Operation not permitted" msgstr "bù yǔnxǔ cāozuò" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" msgstr "bù zhī chí cāo zuò huò gōng néng" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" msgstr "cāo zuò yǐ fēn shí" @@ -1735,7 +1735,7 @@ msgstr "cāo zuò yǐ fēn shí" msgid "Out of MDNS service slots" msgstr "chāo chū MDNS fú wù chā cáo" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" msgstr "nèi cún bù zú" @@ -1916,7 +1916,7 @@ msgstr "Zhǐ dú" msgid "Read-only filesystem" msgstr "Zhǐ dú wénjiàn xìtǒng" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Received response was invalid" msgstr "shōu dào de xiǎng yìng wú xiào" @@ -1936,7 +1936,7 @@ msgstr "RemoteTransmissionRequests xiànzhì wèi 8 gè zì jié" msgid "Requested AES mode is unsupported" msgstr "Qǐngqiú de AES móshì bù shòu zhīchí" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Requested resource not found" msgstr "wèi zhǎo dào qǐng qiú de zī yuán" @@ -2391,7 +2391,7 @@ msgstr "Zhí chángdù != Suǒ xū de gùdìng chángdù" msgid "Value length > max_length" msgstr "Zhí chángdù > zuìdà chángdù" -#: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c +#: ports/espressif/common-hal/espidf/__init__.c msgid "Version was invalid" msgstr "bǎn běn wú xiào" From 5f0aa4a608c1e38533bc057227609961d255ef28 Mon Sep 17 00:00:00 2001 From: MicroDev <70126934+MicroDev1@users.noreply.github.com> Date: Sat, 11 Mar 2023 08:49:17 +0530 Subject: [PATCH 26/29] change board config of some esp32s3 boards - remove unnecessary optimization flags - shrink adafruit_feather_esp32s3_reverse_tft --- .../adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk | 1 - .../adafruit_feather_esp32s3_reverse_tft/mpconfigboard.mk | 2 ++ .../boards/adafruit_feather_esp32s3_tft/mpconfigboard.mk | 1 - ports/espressif/boards/lolin_s3/mpconfigboard.mk | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk index a8d02f082c..6d78999532 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk @@ -9,5 +9,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 40m CIRCUITPY_ESP_FLASH_SIZE = 4MB -OPTIMIZATION_FLAGS = -Os CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/mpconfigboard.mk index 3fdb028f5e..d027443f56 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/mpconfigboard.mk @@ -9,3 +9,5 @@ IDF_TARGET = esp32s3 CIRCUITPY_ESP_FLASH_MODE = dio CIRCUITPY_ESP_FLASH_FREQ = 40m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_tft/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s3_tft/mpconfigboard.mk index 858d0b1859..d801afd493 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_tft/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32s3_tft/mpconfigboard.mk @@ -10,5 +10,4 @@ CIRCUITPY_ESP_FLASH_MODE = dio CIRCUITPY_ESP_FLASH_FREQ = 40m CIRCUITPY_ESP_FLASH_SIZE = 4MB -OPTIMIZATION_FLAGS = -Os CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/lolin_s3/mpconfigboard.mk b/ports/espressif/boards/lolin_s3/mpconfigboard.mk index c81e3e6fb9..56b42a419c 100644 --- a/ports/espressif/boards/lolin_s3/mpconfigboard.mk +++ b/ports/espressif/boards/lolin_s3/mpconfigboard.mk @@ -9,5 +9,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 16MB -OPTIMIZATION_FLAGS = -Os CIRCUITPY_ESPCAMERA = 0 From 76e83a432c64014e8e630227f9b268a32c378223 Mon Sep 17 00:00:00 2001 From: Bill Sideris Date: Sat, 11 Mar 2023 14:05:45 +0200 Subject: [PATCH 27/29] Debug uart, default spi/i2c --- .../boards/waveshare_esp32s2_pico/mpconfigboard.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h index 6a10db6061..4b47fb2984 100644 --- a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h @@ -30,3 +30,13 @@ #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_LED_STATUS (&pin_GPIO9) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO41) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO40) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO10) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO11) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO12) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) From bfc551c158c17bceefd81e82f0955f982b493d37 Mon Sep 17 00:00:00 2001 From: Bill Sideris Date: Sat, 11 Mar 2023 14:14:47 +0200 Subject: [PATCH 28/29] Invert led --- ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h index 4b47fb2984..bb8b00f327 100644 --- a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h @@ -30,6 +30,7 @@ #define MICROPY_HW_MCU_NAME "ESP32S2" #define MICROPY_HW_LED_STATUS (&pin_GPIO9) +#define MICROPY_HW_LED_STATUS_INVERTED (1) #define DEFAULT_I2C_BUS_SCL (&pin_GPIO41) #define DEFAULT_I2C_BUS_SDA (&pin_GPIO40) From e95099fe48658f35b3a4b25cf9fabc0452848d31 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 11 Mar 2023 08:13:30 -0600 Subject: [PATCH 29/29] uncrustify 0.75 is not OK --- BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index 4793824cf1..f108675b7c 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -109,7 +109,7 @@ Pre-commit also requires some additional programs to be installed through your p * Standard Unix tools such as make, find, etc * The gettext package, any modern version - * uncrustify version 0.71 (0.72 is also tested) + * uncrustify version 0.71 (0.72 is also tested and OK; 0.75 is not OK) Each time you create a git commit, the pre-commit quality checks will be run. You can also run them e.g., with `pre-commit run foo.c` or `pre-commit run --all` to run on all files whether modified or not.