drivers/ninaw10: Connect to WiFi asynchronously.

Before this patch, WiFi connection was blocking, and could raise exceptions
if the connection failed for any reason (including timeouts).  This doesn't
match the behavior of other WiFi modules, which connect asynchronously, and
requires handling of exceptions on connect.  This change makes `connect()`
work asynchronously by scheduling code to poll connection status, and
handle reconnects (if needed), and return immediately without blocking.
pull/9696/head
iabdalkader 2022-10-21 20:51:42 +02:00 zatwierdzone przez Damien George
rodzic 8a91c71966
commit b9c1e4c205
3 zmienionych plików z 79 dodań i 29 usunięć

Wyświetl plik

@ -108,6 +108,7 @@ typedef enum {
// Disonnect/status commands.
NINA_CMD_DISCONNECT = 0x30,
NINA_CMD_CONN_STATUS = 0x20,
NINA_CMD_CONN_REASON = 0x1F,
// Interface config commands.
NINA_CMD_SET_IF_CONFIG = 0x14,
@ -173,19 +174,6 @@ typedef enum {
NINA_CMD_CMD_DOWNLOAD_OTA = 0x67,
} nina_cmd_t;
typedef enum {
NINA_STATUS_IDLE = 0,
NINA_STATUS_NO_SSID_AVAIL,
NINA_STATUS_SCAN_COMPLETED,
NINA_STATUS_CONNECTED,
NINA_STATUS_CONNECT_FAILED,
NINA_STATUS_CONNECTION_LOST,
NINA_STATUS_DISCONNECTED,
NINA_STATUS_AP_LISTENING,
NINA_STATUS_AP_CONNECTED,
NINA_STATUS_AP_FAILED
} nina_status_t;
typedef enum {
SOCKET_STATE_CLOSED = 0,
SOCKET_STATE_LISTEN,
@ -364,13 +352,15 @@ int nina_deinit(void) {
return nina_bsp_deinit();
}
static int nina_connection_status() {
int nina_connection_status(void) {
return nina_send_command_read_ack(NINA_CMD_CONN_STATUS, 0, ARG_8BITS, NULL);
}
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
uint8_t status = NINA_STATUS_CONNECT_FAILED;
int nina_connection_reason(void) {
return nina_send_command_read_ack(NINA_CMD_CONN_REASON, 0, ARG_8BITS, NULL);
}
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
if (key == NULL && security != NINA_SEC_OPEN) {
return -1;
}
@ -398,18 +388,7 @@ int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t c
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
status = nina_connection_status();
if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
break;
}
if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
break;
}
}
return (status == NINA_STATUS_CONNECTED) ? 0 : -1;
return 0;
}
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
@ -439,7 +418,7 @@ int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
status = nina_connection_status();
if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL)) {
break;
}

Wyświetl plik

@ -46,6 +46,17 @@
#define NINA_FW_VER_MINOR_OFFS (2)
#define NINA_FW_VER_PATCH_OFFS (4)
#define NINA_ESP_REASON_AUTH_EXPIRE (2)
#define NINA_ESP_REASON_ASSOC_EXPIRE (4)
#define NINA_ESP_REASON_NOT_AUTHED (6)
#define NINA_ESP_REASON_4WAY_HANDSHAKE_TIMEOUT (15)
#define NINA_ESP_REASON_BEACON_TIMEOUT (200)
#define NINA_ESP_REASON_NO_AP_FOUND (201)
#define NINA_ESP_REASON_AUTH_FAIL (202)
#define NINA_ESP_REASON_ASSOC_FAIL (203)
#define NINA_ESP_REASON_HANDSHAKE_TIMEOUT (204)
#define NINA_ESP_REASON_CONNECTION_FAIL (205)
typedef enum {
NINA_SEC_INVALID = 0,
NINA_SEC_OPEN,
@ -59,6 +70,19 @@ typedef enum {
NINA_SOCKET_TYPE_RAW = 3,
} nina_socket_type_t;
typedef enum {
NINA_STATUS_IDLE = 0,
NINA_STATUS_NO_SSID_AVAIL = 1,
NINA_STATUS_SCAN_COMPLETED = 2,
NINA_STATUS_CONNECTED = 3,
NINA_STATUS_CONNECT_FAILED = 4,
NINA_STATUS_CONNECTION_LOST = 5,
NINA_STATUS_DISCONNECTED = 6,
NINA_STATUS_AP_LISTENING = 7,
NINA_STATUS_AP_CONNECTED = 8,
NINA_STATUS_AP_FAILED = 9
} nina_status_t;
typedef struct {
uint8_t ip_addr[NINA_IPV4_ADDR_LEN];
uint8_t subnet_addr[NINA_IPV4_ADDR_LEN];
@ -85,6 +109,8 @@ typedef int (*nina_scan_callback_t)(nina_scan_result_t *, void *);
int nina_init(void);
int nina_deinit(void);
int nina_connection_status(void);
int nina_connection_reason(void);
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel);
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel);
int nina_disconnect(void);

Wyświetl plik

@ -51,6 +51,9 @@ typedef struct _nina_obj_t {
mp_obj_base_t base;
bool active;
uint32_t itf;
mp_uint_t security;
char ssid[NINA_MAX_SSID_LEN + 1];
char key[NINA_MAX_WPA_LEN + 1];
} nina_obj_t;
// For auto-binding UDP sockets
@ -78,6 +81,7 @@ const mod_network_nic_type_t mod_network_nic_type_nina;
static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_AP_IF};
static mp_sched_node_t mp_wifi_sockpoll_node;
static mp_sched_node_t mp_wifi_connpoll_node;
STATIC void network_ninaw10_poll_sockets(mp_sched_node_t *node) {
(void)node;
@ -99,6 +103,40 @@ STATIC void network_ninaw10_poll_sockets(mp_sched_node_t *node) {
}
}
STATIC void network_ninaw10_poll_connect(mp_sched_node_t *node) {
nina_obj_t *self = &network_nina_wl_sta;
int status = nina_connection_status();
if (status == NINA_STATUS_CONNECTED) {
// Connected to AP, nothing else to do.
return;
}
if (status != NINA_STATUS_NO_SSID_AVAIL) {
// If not connected, and no connection in progress, the connection attempt has failed.
// Read the ESP failure reason, reconnect and reschedule the connection polling code.
int reason = nina_connection_reason();
if (reason == NINA_ESP_REASON_AUTH_EXPIRE ||
reason == NINA_ESP_REASON_ASSOC_EXPIRE ||
reason == NINA_ESP_REASON_NOT_AUTHED ||
reason == NINA_ESP_REASON_4WAY_HANDSHAKE_TIMEOUT ||
reason >= NINA_ESP_REASON_BEACON_TIMEOUT) {
debug_printf(&mp_plat_print, "poll_connect() status: %d reason %d\n", status, reason);
if (nina_connect(self->ssid, self->security, self->key, 0) != 0) {
mp_raise_msg_varg(&mp_type_OSError,
MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"),
self->ssid, self->security, self->key);
}
} else {
// Will not attempt to reconnect if there's another error code set.
return;
}
}
// Reschedule the connection polling code.
mp_sched_schedule_node(&mp_wifi_connpoll_node, network_ninaw10_poll_connect);
}
STATIC mp_obj_t network_ninaw10_timer_callback(mp_obj_t none_in) {
if (MP_STATE_PORT(mp_wifi_sockpoll_list) != MP_OBJ_NULL && MP_STATE_PORT(mp_wifi_sockpoll_list)->len) {
mp_sched_schedule_node(&mp_wifi_sockpoll_node, network_ninaw10_poll_sockets);
@ -240,6 +278,12 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
mp_raise_msg_varg(&mp_type_OSError,
MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key);
}
// Save connection info to re-connect if needed.
self->security = security;
strncpy(self->key, key, NINA_MAX_WPA_LEN);
strncpy(self->ssid, ssid, NINA_MAX_SSID_LEN);
mp_sched_schedule_node(&mp_wifi_connpoll_node, network_ninaw10_poll_connect);
} else {
mp_uint_t channel = args[ARG_channel].u_int;
@ -252,6 +296,7 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed to start in AP mode"));
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_connect_obj, 1, network_ninaw10_connect);