diff --git a/drivers/ninaw10/nina_wifi_drv.c b/drivers/ninaw10/nina_wifi_drv.c index 7a1167b2c9..22ad0aae70 100644 --- a/drivers/ninaw10/nina_wifi_drv.c +++ b/drivers/ninaw10/nina_wifi_drv.c @@ -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; } diff --git a/drivers/ninaw10/nina_wifi_drv.h b/drivers/ninaw10/nina_wifi_drv.h index 22163c7286..4b09ac8bd2 100644 --- a/drivers/ninaw10/nina_wifi_drv.h +++ b/drivers/ninaw10/nina_wifi_drv.h @@ -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); diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c index f4cc0b2224..0852deabe9 100644 --- a/extmod/network_ninaw10.c +++ b/extmod/network_ninaw10.c @@ -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);