diff --git a/src/drivers/ninaw10/src/nina.c b/src/drivers/ninaw10/src/nina.c index 8c1aae8a7..8f66a1f51 100644 --- a/src/drivers/ninaw10/src/nina.c +++ b/src/drivers/ninaw10/src/nina.c @@ -41,15 +41,21 @@ #define NINA_SSELECT_TIMEOUT (10000) #define NINA_RESP_TIMEOUT (1000) -#define NINA_CONNECT_TIMEOUT (1000) +#define NINA_CONNECT_TIMEOUT (10000) + +#if NINA_DEBUG +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#else +#define debug_printf(...) +#endif typedef struct { - uint32_t size; + uint16_t size; const void *data; } nina_args_t; typedef struct { - uint32_t *size; + uint16_t *size; void *data; } nina_vals_t; @@ -181,6 +187,8 @@ static int nina_send_command(uint32_t cmd, uint32_t nargs, uint32_t width, nina_ int ret = -1; uint32_t length = 4; // 3 bytes header + 1 end byte + debug_printf("nina_send_command (cmd 0x%x nargs %d width %d): ", cmd, nargs, width); + if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) { return -1; } @@ -193,8 +201,11 @@ static int nina_send_command(uint32_t cmd, uint32_t nargs, uint32_t width, nina_ // Send command arg(s). for (uint32_t i=0; i= timeout) { + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { // Timeout, no networks. return NINA_ERROR_TIMEOUT; } @@ -516,10 +530,10 @@ int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout) } for (int i=0; i= timeout) { + if (state == -1) { + return -1; + } + + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { return NINA_ERROR_TIMEOUT; } } @@ -703,18 +721,18 @@ int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout) int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout) { - uint32_t size = 2; + uint16_t size = 2; uint16_t bytes = 0; if (nina_send_command_read_vals(SEND_DATA_TCP_CMD, - 2, ARG_16BITS, NINA_ARGS(ARG_SHORT(fd), {len, buf}), + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf}), 1, ARG_8BITS, NINA_VALS({&size, &bytes})) != 0 || bytes <= 0) { return -1; } for (mp_uint_t start = mp_hal_ticks_ms(); ;) { int resp = nina_send_command_read_ack(DATA_SENT_TCP_CMD, - 1, ARG_8BITS, NINA_ARGS(ARG_SHORT(fd))); + 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))); if (resp == -1) { return -1; @@ -724,7 +742,7 @@ int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout) break; } - if ((mp_hal_ticks_ms() - start) >= timeout) { + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { return NINA_ERROR_TIMEOUT; } mp_hal_delay_ms(1); @@ -735,19 +753,24 @@ int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout) int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout) { - uint32_t size = 2; uint16_t bytes = 0; - if (nina_send_command_read_vals(GET_DATABUF_TCP_CMD, - 2, ARG_16BITS, NINA_ARGS(ARG_SHORT(fd), {len, buf}), - 1, ARG_16BITS, NINA_VALS({&size, &bytes})) != 0 || bytes <= 0) { - return -1; - } + for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) { + bytes = len; + if (nina_send_command_read_vals(GET_DATABUF_TCP_CMD, + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)), + 1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) { + return -1; + } + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + return NINA_ERROR_TIMEOUT; + } + } return bytes; } -// Check from the upper layer if the socket is bound, if not then auto-bind it 32768->60999 first. +// Check from the upper layer if the socket is bound, if not then auto-bind it first. int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout) { // TODO do we need to split the packet somewhere? @@ -755,7 +778,7 @@ int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, ui 4, ARG_8BITS, NINA_ARGS( ARG_WORD((*(uint32_t*)ip)), - ARG_SHORT(port), + ARG_SHORT(__REVSH(port)), ARG_BYTE(fd), ARG_BYTE(NINA_SOCKET_TYPE_UDP))) != SPI_ACK) { return -1; @@ -763,7 +786,7 @@ int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, ui // Buffer length and socket number are passed as 16bits. if (nina_send_command_read_ack(INSERT_DATABUF_CMD, - 2, ARG_16BITS, NINA_ARGS(ARG_SHORT(fd), {len, buf})) != SPI_ACK) { + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf})) != SPI_ACK) { return -1; } @@ -775,21 +798,25 @@ int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, ui return 0; } -// Check from the upper layer if the socket is bound, if not then auto-bind it 32768->60999 first. +// Check from the upper layer if the socket is bound, if not then auto-bind it first. int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout) { - uint32_t size = 2; uint16_t bytes = 0; + uint16_t port_len = 2; + uint16_t ip_len = NINA_IPV4_ADDR_LEN; - uint32_t ip_len = NINA_IPV4_ADDR_LEN; - uint32_t port_len = 2; + for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) { + bytes = len; + if (nina_send_command_read_vals(GET_DATABUF_TCP_CMD, + 2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)), + 1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) { + return -1; + } - if (nina_send_command_read_vals(GET_DATABUF_TCP_CMD, - 2, ARG_16BITS, NINA_ARGS(ARG_SHORT(fd), {len, buf}), - 1, ARG_16BITS, NINA_VALS({&size, &bytes})) != 0 || bytes <= 0) { - return -1; + if (timeout && (mp_hal_ticks_ms() - start) >= timeout) { + return NINA_ERROR_TIMEOUT; + } } - if (nina_send_command_read_vals(GET_REMOTE_DATA_CMD, 1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)), 2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) { diff --git a/src/micropython b/src/micropython index a114de90b..467c25f82 160000 --- a/src/micropython +++ b/src/micropython @@ -1 +1 @@ -Subproject commit a114de90b8523e1e2c31580caf6483e36da4b75a +Subproject commit 467c25f827aef5bb5df90613577a385001afcc59 diff --git a/src/omv/ports/rp2/main.c b/src/omv/ports/rp2/main.c index a8af8b8a9..42e9d7235 100644 --- a/src/omv/ports/rp2/main.c +++ b/src/omv/ports/rp2/main.c @@ -47,6 +47,10 @@ #include "mpbthciport.h" #endif +#if MICROPY_PY_NETWORK +#include "modnetwork.h" +#endif + #include "pico/stdlib.h" #include "pico/binary_info.h" #include "hardware/rtc.h" @@ -182,6 +186,9 @@ soft_reset: #if MICROPY_PY_BLUETOOTH mp_bluetooth_hci_init(); #endif + #if MICROPY_PY_NETWORK + mod_network_init(); + #endif pendsv_init(); usbdbg_init(); @@ -257,6 +264,9 @@ soft_reset: #if MICROPY_PY_BLUETOOTH mp_bluetooth_deinit(); #endif + #if MICROPY_PY_NETWORK + mod_network_deinit(); + #endif rp2_pio_deinit(); machine_pin_deinit(); gc_sweep_all(); diff --git a/src/omv/ports/rp2/modules/py_nina.c b/src/omv/ports/rp2/modules/py_nina.c index d13cf9034..1bf62b52e 100644 --- a/src/omv/ports/rp2/modules/py_nina.c +++ b/src/omv/ports/rp2/modules/py_nina.c @@ -27,10 +27,31 @@ #include "nina.h" +#define NINA_MIN(a,b) \ +({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; \ +}) + + +#define NINA_MAX(a,b) \ +({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; \ +}) + + typedef struct _nina_obj_t { mp_obj_base_t base; } nina_obj_t; +// For auto-binding UDP sockets +#define BIND_PORT_RANGE_MIN (65000) +#define BIND_PORT_RANGE_MAX (65535) +static uint16_t bind_port = BIND_PORT_RANGE_MIN; + static const nina_obj_t nina_obj = {{(mp_obj_type_t*) &mod_network_nic_type_nina}}; // Initialise the module using the given SPI bus and pins and return a nina object. @@ -41,6 +62,12 @@ static mp_obj_t py_nina_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp if (error != 0) { mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("Failed to initialize Nina-W10 module: %d\n"), error); } + + // Register with network module + mod_network_register_nic((mp_obj_t)&nina_obj); + + bind_port = BIND_PORT_RANGE_MIN; + return (mp_obj_t)&nina_obj; } @@ -250,7 +277,7 @@ static mp_obj_t py_nina_scan(mp_obj_t self_in) static mp_obj_t py_nina_get_rssi(mp_obj_t self_in) { - return mp_obj_new_int(nina_get_rssi()); + return mp_obj_new_int(nina_get_rssi()); } static mp_obj_t py_nina_fw_version(mp_obj_t self_in) @@ -258,10 +285,10 @@ static mp_obj_t py_nina_fw_version(mp_obj_t self_in) uint8_t fwver[NINA_FW_VER_LEN]; nina_fw_version(fwver); - // We don't know how the fw version looks like, assume ints. - mp_obj_tuple_t *t_fwver = mp_obj_new_tuple(NINA_FW_VER_LEN, NULL); - for (int i=0; iitems[i] = mp_obj_new_int(fwver[i]); + // Firmware version is a string like "1.4.7" + mp_obj_tuple_t *t_fwver = mp_obj_new_tuple(3, NULL); + for (int i=0; i<3; i++) { + t_fwver->items[i] = mp_obj_new_int(fwver[i*2] - 48); } return t_fwver; } @@ -275,12 +302,12 @@ static int py_nina_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { uint8_t type; - if (socket->u_param.domain != MOD_NETWORK_AF_INET) { + if (socket->domain != MOD_NETWORK_AF_INET) { *_errno = MP_EAFNOSUPPORT; return -1; } - switch (socket->u_param.type) { + switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: type = NINA_SOCKET_TYPE_TCP; break; @@ -304,6 +331,8 @@ static int py_nina_socket_socket(mod_network_socket_obj_t *socket, int *_errno) // store state of this socket socket->fd = fd; socket->timeout = 0; // blocking + socket->port = 0; + socket->bound = false; return 0; } @@ -318,7 +347,7 @@ static void py_nina_socket_close(mod_network_socket_obj_t *socket) static int py_nina_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { uint8_t type; - switch (socket->u_param.type) { + switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: type = NINA_SOCKET_TYPE_TCP; break; @@ -338,6 +367,10 @@ static int py_nina_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_ui py_nina_socket_close(socket); return -1; } + + // Set bound port and mark socket as bound to avoid auto-binding. + socket->port = port; + socket->bound = true; return 0; } @@ -413,9 +446,27 @@ static mp_uint_t py_nina_socket_recv(mod_network_socket_obj_t *socket, byte *buf return ret; } +static mp_uint_t py_nina_socket_auto_bind(mod_network_socket_obj_t *socket, int *_errno) +{ + if (socket->bound == false) { + if (py_nina_socket_bind(socket, NULL, bind_port, _errno) != 0) { + return -1; + } + socket->bound = true; + socket->port = bind_port++; + bind_port = NINA_MIN(NINA_MAX(bind_port, BIND_PORT_RANGE_MIN), BIND_PORT_RANGE_MAX); + } + return 0; +} + static mp_uint_t py_nina_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + // Auto-bind the socket first if the socket is unbound. + if (py_nina_socket_auto_bind(socket, _errno) != 0) { + return -1; + } + int ret = nina_socket_sendto(socket->fd, buf, len, ip, port, socket->timeout); if (ret == NINA_ERROR_TIMEOUT) { // The socket is Not closed on timeout when calling functions that accept a timeout. @@ -432,6 +483,11 @@ static mp_uint_t py_nina_socket_sendto(mod_network_socket_obj_t *socket, static mp_uint_t py_nina_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + // Auto-bind the socket first if the socket is unbound. + if (py_nina_socket_auto_bind(socket, _errno) != 0) { + return -1; + } + int ret = nina_socket_recvfrom(socket->fd, buf, len, ip, (uint16_t *) port, socket->timeout); if (ret == NINA_ERROR_TIMEOUT) { // The socket is Not closed on timeout when calling functions that accept a timeout. diff --git a/src/omv/ports/rp2/nina_bsp.c b/src/omv/ports/rp2/nina_bsp.c index 7be706e59..c4cbd7822 100644 --- a/src/omv/ports/rp2/nina_bsp.c +++ b/src/omv/ports/rp2/nina_bsp.c @@ -20,6 +20,8 @@ #include "nina.h" #include "nina_bsp.h" +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__) + int nina_bsp_init() { gpio_init(WIFI_CS_PIN); @@ -27,6 +29,7 @@ int nina_bsp_init() gpio_init(WIFI_ACK_PIN); gpio_set_dir(WIFI_ACK_PIN, GPIO_IN); + gpio_set_pulls(WIFI_ACK_PIN, true, false); gpio_init(WIFI_RST_PIN); gpio_set_dir(WIFI_RST_PIN, GPIO_OUT); @@ -53,10 +56,13 @@ int nina_bsp_init() gpio_put(WIFI_RST_PIN, 1); mp_hal_delay_ms(750); - gpio_put(WIFI_GPIO0_PIN, 1); + gpio_put(WIFI_GPIO0_PIN, 0); + gpio_set_dir(WIFI_GPIO0_PIN, GPIO_IN); + gpio_set_pulls(WIFI_GPIO0_PIN, true, false); // Initialize SPI. spi_init(WIFI_SPI, 8 * 1000 * 1000); + spi_set_slave(WIFI_SPI, false); spi_set_format(WIFI_SPI, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); return 0; } @@ -98,8 +104,6 @@ int nina_bsp_spi_slave_deselect() int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) { int rsize = 0; - - gpio_put(WIFI_CS_PIN, 0); if (tx_buf && rx_buf) { rsize = spi_write_read_blocking(WIFI_SPI, tx_buf, rx_buf, size); } else if (tx_buf) { @@ -107,7 +111,15 @@ int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) } else if (rx_buf) { rsize = spi_read_blocking(WIFI_SPI, 0xFF, rx_buf, size); } - gpio_put(WIFI_CS_PIN, 1); + #if NINA_DEBUG + for (int i=0; i