wiznet5k: Support running DHCP in background and renewing address.

Signed-off-by: Jared Hancock <jared@greezybacon.me>
Jared Hancock 2024-04-07 14:23:45 -05:00
rodzic 35763b3970
commit 9d4ab88f93
1 zmienionych plików z 106 dodań i 20 usunięć

Wyświetl plik

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