From 2e371503d61101b2005ef129b99a73a09c4a8550 Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Wed, 20 Mar 2024 21:22:42 -0500 Subject: [PATCH 1/8] wiznet5k: Add support for nonblocking and settimeout. Signed-off-by: Jared Hancock --- extmod/network_wiznet5k.c | 67 ++++++++++++++++++++++++++++++++------- ports/rp2/mpconfigport.h | 4 +++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index b550f8c1f4..e4597fcc32 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -465,8 +465,15 @@ static void wiznet5k_socket_close(mod_network_socket_obj_t *socket) { } static int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + uint8_t flag = 0; + if (socket->timeout == 0) { + // Setup non-blocking mode + flag |= SOCK_IO_NONBLOCK; + } + // open the socket in server mode (if port != 0) - mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->fileno, socket->type, port, 0); + mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->fileno, socket->type, port, flag); + if (ret < 0) { wiznet5k_socket_close(socket); *_errno = -ret; @@ -541,6 +548,10 @@ static int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, m *_errno = -ret; return -1; } + else if (ret == SOCK_BUSY) { + *_errno = MP_EAGAIN; + return -1; + } // success return 0; @@ -557,6 +568,10 @@ static mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const by *_errno = -ret; return -1; } + else if (ret == SOCK_BUSY) { + *_errno = MP_EAGAIN; + return -1; + } return ret; } @@ -571,6 +586,10 @@ static mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *bu *_errno = -ret; return -1; } + else if (ret == SOCK_BUSY) { + *_errno = MP_EAGAIN; + return -1; + } return ret; } @@ -591,6 +610,10 @@ static mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const *_errno = -ret; return -1; } + else if (ret == SOCK_BUSY) { + *_errno = MP_EAGAIN; + return -1; + } return ret; } @@ -605,27 +628,47 @@ static mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *_errno = -ret; return -1; } + else if (ret == SOCK_BUSY) { + *_errno = MP_EAGAIN; + return -1; + } return ret; } static int wiznet5k_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { - // TODO - *_errno = MP_EINVAL; - return -1; + switch (opt) { + // level: SOL_SOCKET + case MOD_NETWORK_SO_REUSEADDR: + case MOD_NETWORK_SO_BROADCAST: + // Implied/not-required in Wiznet sockets + break; + + default: + *_errno = MP_EINVAL; + return -1; + } + + return 0; } static int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) { - // TODO - *_errno = MP_EINVAL; - return -1; - - /* + uint8_t arg; if (timeout_ms == 0) { // set non-blocking mode - uint8_t arg = SOCK_IO_NONBLOCK; - WIZCHIP_EXPORT(ctlsocket)(socket->fileno, CS_SET_IOMODE, &arg); + arg = SOCK_IO_NONBLOCK; } - */ + else { + arg = SOCK_IO_BLOCK; + } + + mp_int_t ret = WIZCHIP_EXPORT(ctlsocket)(socket->fileno, CS_SET_IOMODE, &arg); + if (ret < 0) { + *_errno = -ret; + return -1; + } + + socket->timeout = timeout_ms; + return 0; } static int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { diff --git a/ports/rp2/mpconfigport.h b/ports/rp2/mpconfigport.h index a29692d0be..1f01a75058 100644 --- a/ports/rp2/mpconfigport.h +++ b/ports/rp2/mpconfigport.h @@ -218,6 +218,10 @@ extern const struct _mp_obj_type_t mod_network_nic_type_nina; #if MICROPY_PY_NETWORK_WIZNET5K extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k; #define MICROPY_HW_NIC_WIZNET5K { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) }, +// This Network interface requires the extended socket state for timeouts and non-blocking +#ifndef MICROPY_PY_SOCKET_EXTENDED_STATE +#define MICROPY_PY_SOCKET_EXTENDED_STATE (1) +#endif #else #define MICROPY_HW_NIC_WIZNET5K #endif From 26d0ea4006522fe61cb94fc9fae2c91e0eb86616 Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Wed, 20 Mar 2024 21:24:24 -0500 Subject: [PATCH 2/8] wiznet5k: Add support for read timeouts. Signed-off-by: Jared Hancock --- extmod/network_wiznet5k.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index e4597fcc32..8000dfdc44 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -576,6 +576,17 @@ static mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const by } static mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { + if (socket->timeout > 0) { + mp_uint_t start = mp_hal_ticks_ms(); + while (getSn_SR(socket->fileno) == SOCK_ESTABLISHED && getSn_RX_RSR(socket->fileno) == 0) { + if (mp_hal_ticks_ms() - start > socket->timeout) { + *_errno = MP_ETIMEDOUT; + return -1; + } + mp_event_wait_ms(1); + } + } + MP_THREAD_GIL_EXIT(); mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->fileno, buf, len); MP_THREAD_GIL_ENTER(); @@ -619,6 +630,18 @@ static mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const static mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { uint16_t port2; + + if (socket->timeout > 0) { + mp_uint_t start = mp_hal_ticks_ms(); + while (getSn_SR(socket->fileno) != SOCK_CLOSED && getSn_RX_RSR(socket->fileno) == 0) { + if (mp_hal_ticks_ms() - start > socket->timeout) { + *_errno = MP_ETIMEDOUT; + return -1; + } + mp_event_wait_ms(1); + } + } + MP_THREAD_GIL_EXIT(); mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->fileno, buf, len, ip, &port2); MP_THREAD_GIL_ENTER(); From 4364ad74ae9818a9d3332999b0b878016dc3986a Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Fri, 22 Mar 2024 11:44:56 -0500 Subject: [PATCH 3/8] wiznet5k: Add support for ::send on UDP sockets. Signed-off-by: Jared Hancock --- extmod/network_wiznet5k.c | 56 +++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index 8000dfdc44..121aafc9cf 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -113,6 +113,13 @@ typedef struct _wiznet5k_obj_t { #endif } wiznet5k_obj_t; +#if WIZNET5K_PROVIDED_STACK +typedef struct _wiznet5k_socket_extra_t { + byte remote_ip[4]; + mp_uint_t remote_port; +} wiznet5k_socket_extra_t; +#endif + #if WIZNET5K_WITH_LWIP_STACK #define IS_ACTIVE(self) (self->netif.flags & NETIF_FLAG_UP) #else // WIZNET5K_PROVIDED_STACK @@ -444,6 +451,8 @@ static int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) *_errno = MP_EMFILE; return -1; } + + socket->_private = NULL; } // WIZNET does not have a concept of pure "open socket". You need to know @@ -538,26 +547,51 @@ static int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, m return -1; } - // now connect - MP_THREAD_GIL_EXIT(); - mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->fileno, ip, port); - MP_THREAD_GIL_ENTER(); + // WIZnet doesn't support connect on UDP sockets. TODO: Stash the remote + // information for use with the ::send method, if used on this UDP socket. + if (socket->type == Sn_MR_TCP) { + // now connect + MP_THREAD_GIL_EXIT(); + mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->fileno, ip, port); + MP_THREAD_GIL_ENTER(); - if (ret < 0) { - wiznet5k_socket_close(socket); - *_errno = -ret; - return -1; + if (ret < 0) { + wiznet5k_socket_close(socket); + *_errno = -ret; + return -1; + } + else if (ret == SOCK_BUSY) { + *_errno = MP_EAGAIN; + return -1; + } } - else if (ret == SOCK_BUSY) { - *_errno = MP_EAGAIN; - return -1; + else if (socket->type == Sn_MR_UDP) { + // For POSIX usage of ::send later, stash the remote IP and port + wiznet5k_socket_extra_t *extra = (wiznet5k_socket_extra_t *)m_malloc(sizeof(wiznet5k_socket_extra_t)); + if (extra == NULL) { + *_errno = MP_ENOMEM; + return -1; + } + memcpy(extra->remote_ip, ip, 4); + extra->remote_port = port; + socket->_private = extra; } // success return 0; } +static mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno); static mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { + if (socket->type == Sn_MR_UDP) { + if (socket->_private != NULL) { + wiznet5k_socket_extra_t *extra = (wiznet5k_socket_extra_t*) socket->_private; + return wiznet5k_socket_sendto(socket, buf, len, extra->remote_ip, extra->remote_port, _errno); + } + *_errno = MP_ENOTCONN; + return -1; + } + MP_THREAD_GIL_EXIT(); mp_int_t ret = WIZCHIP_EXPORT(send)(socket->fileno, (byte *)buf, len); MP_THREAD_GIL_ENTER(); From c1b0c7eca312c82b78213d5c44a8ff5c56b8e63c Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Thu, 28 Mar 2024 22:04:18 -0500 Subject: [PATCH 4/8] wiznet5k: stm32: Add support for nonblocking and settimeout. Signed-off-by: Jared Hancock --- ports/stm32/mpconfigport.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 9e1e24cf23..4043ecdd2a 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -202,6 +202,10 @@ extern const struct _mp_obj_type_t mp_network_cyw43_type; #if MICROPY_PY_NETWORK_WIZNET5K extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k; #define MICROPY_HW_NIC_WIZNET5K { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) }, +// This Network interface requires the extended socket state for timeouts and non-blocking +#ifndef MICROPY_PY_SOCKET_EXTENDED_STATE +#define MICROPY_PY_SOCKET_EXTENDED_STATE (1) +#endif #else #define MICROPY_HW_NIC_WIZNET5K #endif From e9de433ecf4feecbfb611ffce66f239788197da8 Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Sat, 6 Apr 2024 12:14:43 -0500 Subject: [PATCH 5/8] wiznet5k: Add support for using interrupt without lwIP. Signed-off-by: Jared Hancock --- extmod/network_wiznet5k.c | 84 ++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 19 deletions(-) diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index 121aafc9cf..b96fdc3514 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -99,9 +99,9 @@ typedef struct _wiznet5k_obj_t { void (*spi_transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest); mp_hal_pin_obj_t cs; mp_hal_pin_obj_t rst; - #if WIZNET5K_WITH_LWIP_STACK mp_hal_pin_obj_t pin_intn; bool use_interrupt; + #if WIZNET5K_WITH_LWIP_STACK uint8_t eth_frame[1514]; uint32_t trace_flags; struct netif netif; @@ -177,11 +177,7 @@ static void wiznet5k_get_mac_address(wiznet5k_obj_t *self, uint8_t mac[6]) { getSHAR(mac); } -#if WIZNET5K_WITH_LWIP_STACK - void wiznet5k_try_poll(void); -static void wiznet5k_lwip_init(wiznet5k_obj_t *self); - static mp_obj_t mpy_wiznet_read_int(mp_obj_t none_in) { (void)none_in; // Handle incoming data, unless the SPI bus is busy @@ -204,6 +200,9 @@ static void wiznet5k_config_interrupt(bool enabled) { ); } +#if WIZNET5K_WITH_LWIP_STACK +static void wiznet5k_lwip_init(wiznet5k_obj_t *self); + void wiznet5k_deinit(void) { for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) { if (netif == &wiznet5k_obj.netif) { @@ -357,6 +356,14 @@ void wiznet5k_poll(void) { #if WIZNET5K_PROVIDED_STACK +void wiznet5k_try_poll(void) { + // There's really nothing to do here. The interrupt that triggered this will + // release a WFE() wait and will trigger a poll() loop which will + // wiznet5k_socket_ioctl will detect the readable or writeable state of the + // respective socket. + (void)0; +} + static void wiz_dhcp_assign(void) { getIPfromDHCP(wiznet5k_obj.netinfo.ip); getGWfromDHCP(wiznet5k_obj.netinfo.gw); @@ -395,6 +402,17 @@ static void wiznet5k_init(void) { }; wiznet5k_obj.netinfo = netinfo; + if (wiznet5k_obj.use_interrupt) { + mp_hal_pin_input(wiznet5k_obj.pin_intn); + wiznet5k_config_interrupt(true); + wizchip_setinterruptmask(IK_SOCK_ALL); + + #if _WIZCHIP_ == W5100S + // Enable interrupt pin + setMR2(getMR2() | MR2_G_IEN); + #endif + } + // register with network module mod_network_register_nic(&wiznet5k_obj); @@ -453,6 +471,11 @@ static int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) } socket->_private = NULL; + + // Enable data receive interrupt + if (wiznet5k_obj.use_interrupt) { + setSn_IMR(socket->fileno, (Sn_IR_RECV | Sn_IR_CON | Sn_IR_DISCON)); + } } // WIZNET does not have a concept of pure "open socket". You need to know @@ -470,7 +493,14 @@ static void wiznet5k_socket_close(mod_network_socket_obj_t *socket) { if (sn < _WIZCHIP_SOCK_NUM_) { wiznet5k_obj.socket_used &= ~(1 << sn); WIZCHIP_EXPORT(close)(sn); + + // Disable receive interrupts + if (wiznet5k_obj.use_interrupt) { + setSn_IMR(sn, 0); + } } + + socket->_private = NULL; } static int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { @@ -729,14 +759,35 @@ static int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_ } static int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { + uint8_t sn = (uint8_t)socket->fileno; + if (request == MP_STREAM_POLL) { int ret = 0; - if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(socket->fileno) != 0) { - ret |= MP_STREAM_POLL_RD; + if (sn < _WIZCHIP_SOCK_NUM_) { + if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(sn) != 0) { + ret |= MP_STREAM_POLL_RD; + } + if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(sn) != 0) { + ret |= MP_STREAM_POLL_WR; + } + + uint8_t status = getSn_SR(sn); + if (status == SOCK_CLOSE_WAIT || getSn_IR(sn) & Sn_IR_DISCON) { + // Peer-closed socket is both readable and writable: read will + // return EOF, write - error. Without this poll will hang on a + // socket which was closed by peer. + ret |= arg & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR); + } else if (status == SOCK_CLOSED) { + ret |= MP_STREAM_POLL_ERR; + } + } else { + ret |= MP_STREAM_POLL_NVAL; } - if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(socket->fileno) != 0) { - ret |= MP_STREAM_POLL_WR; + + if (wiznet5k_obj.use_interrupt) { + setSn_IR(sn, (Sn_IR_RECV | Sn_IR_CON | Sn_IR_DISCON)); } + return ret; } else { *_errno = MP_EINVAL; @@ -773,6 +824,8 @@ static void wiznet5k_dhcp_init(wiznet5k_obj_t *self) { if (ret == DHCP_IP_LEASED) { ctlnetwork(CN_GET_NETINFO, &self->netinfo); } + + wizchip_clrinterrupt(IK_SOCK_1); } #endif // WIZNET5K_PROVIDED_STACK @@ -786,11 +839,10 @@ static mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size mp_obj_base_t *spi; mp_hal_pin_obj_t cs; mp_hal_pin_obj_t rst; - - #if WIZNET5K_WITH_LWIP_STACK mp_hal_pin_obj_t pin_intn = (mp_hal_pin_obj_t)NULL; bool use_interrupt = false; + #if WIZNET5K_WITH_LWIP_STACK // Bring down interface while configuring wiznet5k_obj.netif.flags = 0; #endif @@ -813,7 +865,7 @@ static mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size cs = mp_hal_get_pin_obj(mp_pin_make_new(NULL, 1, 0, (mp_obj_t[]) {MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIZNET_PIN_CS)})); rst = mp_hal_get_pin_obj(mp_pin_make_new(NULL, 1, 0, (mp_obj_t[]) {MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIZNET_PIN_RST)})); - #if WIZNET5K_WITH_LWIP_STACK && defined(MICROPY_HW_WIZNET_PIN_INTN) + #ifdef MICROPY_HW_WIZNET_PIN_INTN pin_intn = mp_hal_get_pin_obj(mp_pin_make_new(NULL, 1, 0, (mp_obj_t[]) {MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIZNET_PIN_INTN)})); use_interrupt = true; #endif @@ -822,20 +874,14 @@ static mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size #endif { // If passing in args, must supply spi, pin_cs, pin_rst and optionally pin_intn - #if WIZNET5K_WITH_LWIP_STACK mp_arg_check_num(n_args, n_kw, 3, 4, false); - #else - mp_arg_check_num(n_args, n_kw, 3, 3, false); - #endif spi = mp_hal_get_spi_obj(args[0]); cs = mp_hal_get_pin_obj(args[1]); rst = mp_hal_get_pin_obj(args[2]); - #if WIZNET5K_WITH_LWIP_STACK if (n_args > 3) { pin_intn = mp_hal_get_pin_obj(args[3]); use_interrupt = true; } - #endif } mp_hal_pin_output(cs); @@ -848,9 +894,9 @@ static mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size wiznet5k_obj.spi_transfer = ((mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(spi->type, protocol))->transfer; wiznet5k_obj.cs = cs; wiznet5k_obj.rst = rst; - #if WIZNET5K_WITH_LWIP_STACK wiznet5k_obj.pin_intn = pin_intn; wiznet5k_obj.use_interrupt = use_interrupt; + #if WIZNET5K_WITH_LWIP_STACK wiznet5k_obj.trace_flags = 0; #else // WIZNET5K_PROVIDED_STACK wiznet5k_obj.active = false; From 35763b39702da59da4b17115ed6514b906e3aa23 Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Sat, 6 Apr 2024 12:20:32 -0500 Subject: [PATCH 6/8] wiznet5k: Fix ambiguity with SOCK_BUSY return value. Signed-off-by: Jared Hancock --- extmod/network_wiznet5k.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index b96fdc3514..e5b59825e1 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -632,7 +632,7 @@ static mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const by *_errno = -ret; return -1; } - else if (ret == SOCK_BUSY) { + else if (ret == SOCK_BUSY && getSn_SR(socket->fileno) == SOCK_ESTABLISHED) { *_errno = MP_EAGAIN; return -1; } @@ -661,7 +661,9 @@ static mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *bu *_errno = -ret; return -1; } - else if (ret == SOCK_BUSY) { + // NOTE: SOCK_BUSY is zero (0) which is confusing if the socket is closed + // and at EOF + else if (ret == SOCK_BUSY && getSn_SR(socket->fileno) == SOCK_ESTABLISHED) { *_errno = MP_EAGAIN; return -1; } From 9d4ab88f937b21b64807ea66b1bc8b9e04d18f1e Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Sun, 7 Apr 2024 14:23:45 -0500 Subject: [PATCH 7/8] wiznet5k: Support running DHCP in background and renewing address. Signed-off-by: Jared Hancock --- extmod/network_wiznet5k.c | 126 ++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 20 deletions(-) diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index e5b59825e1..8cc4fbab7e 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -37,6 +37,7 @@ #if MICROPY_PY_NETWORK_WIZNET5K #include "shared/netutils/netutils.h" +#include "shared/runtime/softtimer.h" #include "extmod/modnetwork.h" #include "extmod/modmachine.h" #include "extmod/virtpin.h" @@ -74,6 +75,14 @@ #include "lib/wiznet5k/Internet/DNS/dns.h" #include "lib/wiznet5k/Internet/DHCP/dhcp.h" +// Poll WIZnet every 64ms by default (if not using interrupt pin) +#define WIZNET5K_TICK_RATE_MS 64 +// In DHCP.c, RIP_MSG max size is defined as 312 + 256 (sadly, not in the header) +#define MAX_DHCP_BUF_SIZE 568 + +// Soft timer for polling and running DHCP in the background. +static soft_timer_entry_t mp_network_soft_timer; + #endif #ifndef printf @@ -110,6 +119,11 @@ typedef struct _wiznet5k_obj_t { wiz_NetInfo netinfo; uint8_t socket_used; bool active; + uint8_t *dhcp_buf; + uint8_t dhcp_retry; + uint8_t dhcp_state; + mp_int_t dhcp_socket; + uint32_t dhcp_timeout; #endif } wiznet5k_obj_t; @@ -356,12 +370,57 @@ void wiznet5k_poll(void) { #if WIZNET5K_PROVIDED_STACK +static mp_int_t wiznet5k_allocate_socket(void) { + // get first unused socket number + for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) { + if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) { + wiznet5k_obj.socket_used |= (1 << sn); + return sn; + } + } + + return -1; +} + +extern uint8_t DHCP_SOCKET; +static void wiznet5k_dhcp_poll(void) { + if (wiznet5k_obj.dhcp_socket != -1) { + wiznet5k_obj.dhcp_state = DHCP_run(); + } + + if (wiznet5k_obj.dhcp_state == DHCP_IP_LEASED) { + // Every few seconds, check in about renewing the IP + if (wiznet5k_obj.dhcp_socket != -1) { + // Release socket and reset timeout + wiznet5k_obj.socket_used &= ~(1 << wiznet5k_obj.dhcp_socket); + wiznet5k_obj.dhcp_socket = -1; + + // Run about once per minute + wiznet5k_obj.dhcp_timeout = mp_hal_ticks_ms() + 60000; + } else if (mp_hal_ticks_ms() > wiznet5k_obj.dhcp_timeout) { + mp_uint_t sn = wiznet5k_allocate_socket(); + if (sn != -1) { + DHCP_SOCKET = sn; + wiznet5k_obj.dhcp_socket = sn; + wiznet5k_obj.dhcp_state = DHCP_run(); + } + } + } else if (wiznet5k_obj.dhcp_state == DHCP_FAILED || wiznet5k_obj.dhcp_state == DHCP_STOPPED) { + if (wiznet5k_obj.dhcp_socket != -1) { + wiznet5k_obj.socket_used &= ~(1 << wiznet5k_obj.dhcp_socket); + wiznet5k_obj.dhcp_socket = -1; + } + } +} + void wiznet5k_try_poll(void) { + // If using DHCP for the interface, periodically renew/update the address + wiznet5k_dhcp_poll(); + // There's really nothing to do here. The interrupt that triggered this will // release a WFE() wait and will trigger a poll() loop which will // wiznet5k_socket_ioctl will detect the readable or writeable state of the - // respective socket. - (void)0; + // respective socket(s). } static void wiz_dhcp_assign(void) { @@ -373,7 +432,7 @@ static void wiz_dhcp_assign(void) { } static void wiz_dhcp_update(void) { - ; + wiz_dhcp_assign(); } @@ -381,6 +440,22 @@ static void wiz_dhcp_conflict(void) { ; } +// This is called by soft_timer and executes at PendSV level. +static void mp_network_soft_timer_callback(soft_timer_entry_t *self) { + wiznet5k_try_poll(); +} + +static void mod_network_wiznet5k_poll_init(void) { + soft_timer_static_init( + &mp_network_soft_timer, + SOFT_TIMER_MODE_PERIODIC, + WIZNET5K_TICK_RATE_MS, + mp_network_soft_timer_callback + ); + + soft_timer_reinsert(&mp_network_soft_timer, WIZNET5K_TICK_RATE_MS); +} + static void wiznet5k_init(void) { // Configure wiznet provided TCP / socket interface @@ -415,8 +490,11 @@ static void wiznet5k_init(void) { // register with network module mod_network_register_nic(&wiznet5k_obj); + mod_network_wiznet5k_poll_init(); wiznet5k_obj.active = true; + wiznet5k_obj.dhcp_socket = -1; + wiznet5k_obj.dhcp_state = DHCP_STOPPED; } static int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { @@ -457,13 +535,7 @@ static int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) if (socket->fileno == -1) { // get first unused socket number - for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) { - if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) { - wiznet5k_obj.socket_used |= (1 << sn); - socket->fileno = sn; - break; - } - } + socket->fileno = wiznet5k_allocate_socket(); if (socket->fileno == -1) { // too many open sockets *_errno = MP_EMFILE; @@ -500,6 +572,7 @@ static void wiznet5k_socket_close(mod_network_socket_obj_t *socket) { } } + m_del(wiznet5k_socket_extra_t, socket->_private, 1); socket->_private = NULL; } @@ -597,7 +670,7 @@ static int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, m } else if (socket->type == Sn_MR_UDP) { // For POSIX usage of ::send later, stash the remote IP and port - wiznet5k_socket_extra_t *extra = (wiznet5k_socket_extra_t *)m_malloc(sizeof(wiznet5k_socket_extra_t)); + wiznet5k_socket_extra_t *extra = m_new_maybe(wiznet5k_socket_extra_t, 1); if (extra == NULL) { *_errno = MP_ENOMEM; return -1; @@ -798,23 +871,31 @@ static int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t req } static void wiznet5k_dhcp_init(wiznet5k_obj_t *self) { - uint8_t test_buf[2048]; - uint8_t ret = 0; uint8_t dhcp_retry = 0; + self->dhcp_state = DHCP_STOPPED; + self->dhcp_buf = m_new_maybe(uint8_t, MAX_DHCP_BUF_SIZE); + if (self->dhcp_buf == NULL) { + return; + } - while (ret != DHCP_IP_LEASED) { + self->dhcp_socket = wiznet5k_allocate_socket(); + if (self->dhcp_socket == -1) { + return; + } + + + while (self->dhcp_state != DHCP_IP_LEASED) { mp_uint_t timeout = mp_hal_ticks_ms() + 3000; - DHCP_init(1, test_buf); + DHCP_init(self->dhcp_socket, self->dhcp_buf); while (1) { - ret = DHCP_run(); - if (ret == DHCP_IP_LEASED) { + mpy_wiznet_yield(); + if (self->dhcp_state == DHCP_IP_LEASED) { break; - } else if (ret == DHCP_FAILED || mp_hal_ticks_ms() > timeout) { + } else if (self->dhcp_state == DHCP_FAILED || mp_hal_ticks_ms() > timeout) { dhcp_retry++; break; } - mpy_wiznet_yield(); } if (dhcp_retry > 3) { @@ -827,7 +908,7 @@ static void wiznet5k_dhcp_init(wiznet5k_obj_t *self) { ctlnetwork(CN_GET_NETINFO, &self->netinfo); } - wizchip_clrinterrupt(IK_SOCK_1); + wizchip_clrinterrupt(IK_SOCK_0 << self->dhcp_socket); } #endif // WIZNET5K_PROVIDED_STACK @@ -1042,6 +1123,11 @@ static mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) { } else { // Set static IP addresses self->netinfo.dhcp = NETINFO_STATIC; + self->dhcp_state = DHCP_STOPPED; + if (self->dhcp_buf) { + m_del(uint8_t, self->dhcp_buf, MAX_DHCP_BUF_SIZE); + self->dhcp_buf = NULL; + } mp_obj_t *items; mp_obj_get_array_fixed_n(args[1], 4, &items); netutils_parse_ipv4_addr(items[0], netinfo.ip, NETUTILS_BIG); From 710bf834cf9337ed4a0eb8c2e3051de877ee4096 Mon Sep 17 00:00:00 2001 From: Jared Hancock Date: Sun, 7 Apr 2024 14:41:45 -0500 Subject: [PATCH 8/8] wiznet5k: dns: Support using dynamic socket number. Signed-off-by: Jared Hancock --- extmod/network_wiznet5k.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c index 8cc4fbab7e..dd09f5b514 100644 --- a/extmod/network_wiznet5k.c +++ b/extmod/network_wiznet5k.c @@ -500,12 +500,23 @@ static void wiznet5k_init(void) { static int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { uint8_t dns_ip[MOD_NETWORK_IPADDR_BUF_SIZE] = {8, 8, 8, 8}; uint8_t *buf = m_new(uint8_t, MAX_DNS_BUF_SIZE); - DNS_init(2, buf); + mp_int_t sn = wiznet5k_allocate_socket(); + if (sn == -1) { + return -2; + } + + DNS_init(sn, buf); if (wiznet5k_obj.netinfo.dns[0]) { memcpy(dns_ip, wiznet5k_obj.netinfo.dns, MOD_NETWORK_IPADDR_BUF_SIZE); } mp_int_t ret = DNS_run(dns_ip, (uint8_t *)name, out_ip); m_del(uint8_t, buf, MAX_DNS_BUF_SIZE); + + // NOTE: DNS_run will close the socket, so it just needs to be marked as + // unused here and clear any interrupts. + wiznet5k_obj.socket_used &= ~(1 << sn); + wizchip_clrinterrupt(IK_SOCK_0 << sn); + if (ret == 1) { // success return 0;