4242#include "py/misc.h"
4343#include "py/mperrno.h"
4444#include "shared/netutils/netutils.h"
45+ #include "shared/runtime/softtimer.h"
4546#include "extmod/modnetwork.h"
4647#include "modmachine.h"
4748
5051typedef struct _nina_obj_t {
5152 mp_obj_base_t base ;
5253 bool active ;
54+ bool poll_enable ;
5355 uint32_t itf ;
5456 mp_uint_t security ;
5557 char ssid [NINA_MAX_SSID_LEN + 1 ];
@@ -71,30 +73,64 @@ typedef struct _nina_obj_t {
7173#define SO_ERROR (0x1007)
7274#define SO_TYPE (0x1008)
7375#define SO_NO_CHECK (0x100a)
76+ #define NINAW10_POLL_INTERVAL (100)
7477
7578#define is_nonblocking_error (errno ) ((errno) == MP_EAGAIN || (errno) == MP_EWOULDBLOCK || (errno) == MP_EINPROGRESS)
7679
7780#define debug_printf (...) // mp_printf(&mp_plat_print, __VA_ARGS__)
7881
7982static uint16_t bind_port = BIND_PORT_RANGE_MIN ;
8083const mp_obj_type_t mod_network_nic_type_nina ;
81- static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t * )& mod_network_nic_type_nina }, false, MOD_NETWORK_STA_IF };
82- static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t * )& mod_network_nic_type_nina }, false, MOD_NETWORK_AP_IF };
83- static mp_sched_node_t mp_wifi_sockpoll_node ;
84- static mp_sched_node_t mp_wifi_connpoll_node ;
84+ static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t * )& mod_network_nic_type_nina }, false, false, MOD_NETWORK_STA_IF };
85+ static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t * )& mod_network_nic_type_nina }, false, false, MOD_NETWORK_AP_IF };
86+ static mp_sched_node_t mp_wifi_poll_node ;
87+ static soft_timer_entry_t mp_wifi_poll_timer ;
88+ STATIC void network_ninaw10_deinit (void );
89+
90+ STATIC bool network_ninaw10_poll_list_is_empty (void ) {
91+ return MP_STATE_PORT (mp_wifi_poll_list ) == NULL ||
92+ MP_STATE_PORT (mp_wifi_poll_list )-> len == 0 ;
93+ }
94+
95+ STATIC void network_ninaw10_poll_list_insert (mp_obj_t socket ) {
96+ if (MP_STATE_PORT (mp_wifi_poll_list ) == NULL ) {
97+ MP_STATE_PORT (mp_wifi_poll_list ) = mp_obj_new_list (0 , NULL );
98+ }
99+ mp_obj_list_append (MP_STATE_PORT (mp_wifi_poll_list ), socket );
100+ }
101+
102+ STATIC void network_ninaw10_poll_list_remove (mp_obj_t socket ) {
103+ if (MP_STATE_PORT (mp_wifi_poll_list ) == NULL ) {
104+ return ;
105+ }
106+ mp_obj_list_remove (MP_STATE_PORT (mp_wifi_poll_list ), socket );
107+ if (MP_STATE_PORT (mp_wifi_poll_list )-> len == 0 ) {
108+ MP_STATE_PORT (mp_wifi_poll_list ) = NULL ;
109+ }
110+ }
85111
86112STATIC void network_ninaw10_poll_sockets (mp_sched_node_t * node ) {
87113 (void )node ;
88- for (mp_uint_t i = 0 ; i < MP_STATE_PORT (mp_wifi_sockpoll_list )-> len ; i ++ ) {
89- mod_network_socket_obj_t * socket = MP_STATE_PORT (mp_wifi_sockpoll_list )-> items [i ];
114+ for (mp_uint_t i = 0 ; MP_STATE_PORT ( mp_wifi_poll_list ) && i < MP_STATE_PORT (mp_wifi_poll_list )-> len ;) {
115+ mod_network_socket_obj_t * socket = MP_STATE_PORT (mp_wifi_poll_list )-> items [i ];
90116 uint8_t flags = 0 ;
91117 if (socket -> callback == MP_OBJ_NULL || nina_socket_poll (socket -> fileno , & flags ) < 0 ) {
92- // remove from poll list on error.
118+ // Remove socket from poll list on error.
93119 socket -> callback = MP_OBJ_NULL ;
94- mp_obj_list_remove (MP_STATE_PORT (mp_wifi_sockpoll_list ), socket );
95- } else if (flags & SOCKET_POLL_RD ) {
120+ network_ninaw10_poll_list_remove (socket );
121+ // Check the same index on the next iteration.
122+ continue ;
123+ }
124+ if (flags & SOCKET_POLL_RD ) {
96125 mp_call_function_1 (socket -> callback , MP_OBJ_FROM_PTR (socket ));
97126 }
127+ i ++ ;
128+ debug_printf ("poll_sockets(%d) -> flags %d\n" , socket -> fileno , flags );
129+ }
130+
131+ if (!network_ninaw10_poll_list_is_empty ()) {
132+ // Reschedule the sockets polling code.
133+ soft_timer_reinsert (& mp_wifi_poll_timer , NINAW10_POLL_INTERVAL );
98134 }
99135}
100136
@@ -104,10 +140,8 @@ STATIC void network_ninaw10_poll_connect(mp_sched_node_t *node) {
104140 int status = nina_connection_status ();
105141 if (status == NINA_STATUS_CONNECTED ) {
106142 // Connected to AP, nothing else to do.
107- return ;
108- }
109-
110- if (status != NINA_STATUS_NO_SSID_AVAIL ) {
143+ self -> poll_enable = false;
144+ } else if (status != NINA_STATUS_NO_SSID_AVAIL ) {
111145 // If not connected, and no connection in progress, the connection attempt has failed.
112146 // Read the ESP failure reason, reconnect and reschedule the connection polling code.
113147 int reason = nina_connection_reason ();
@@ -124,21 +158,23 @@ STATIC void network_ninaw10_poll_connect(mp_sched_node_t *node) {
124158 }
125159 } else {
126160 // Will not attempt to reconnect if there's another error code set.
127- return ;
161+ self -> poll_enable = false ;
128162 }
129163 }
130164
131- // Reschedule the connection polling code.
132- mp_sched_schedule_node ( & mp_wifi_connpoll_node , network_ninaw10_poll_connect );
165+ // Reinsert the timer to schedule the polling code.
166+ soft_timer_reinsert ( & mp_wifi_poll_timer , NINAW10_POLL_INTERVAL );
133167}
134168
135- STATIC mp_obj_t network_ninaw10_timer_callback (mp_obj_t none_in ) {
136- if (MP_STATE_PORT (mp_wifi_sockpoll_list ) != MP_OBJ_NULL && MP_STATE_PORT (mp_wifi_sockpoll_list )-> len ) {
137- mp_sched_schedule_node (& mp_wifi_sockpoll_node , network_ninaw10_poll_sockets );
169+ STATIC void network_ninaw10_timer_callback (soft_timer_entry_t * self ) {
170+ debug_printf ("timer_callback() poll status STA: %d AP: %d SOCKETS: %d\n" ,
171+ network_nina_wl_sta .poll_enable , network_nina_wl_ap .poll_enable , !network_ninaw10_poll_list_is_empty ());
172+ if (network_nina_wl_sta .poll_enable ) {
173+ mp_sched_schedule_node (& mp_wifi_poll_node , network_ninaw10_poll_connect );
174+ } else if (!network_ninaw10_poll_list_is_empty ()) {
175+ mp_sched_schedule_node (& mp_wifi_poll_node , network_ninaw10_poll_sockets );
138176 }
139- return mp_const_none ;
140177}
141- STATIC MP_DEFINE_CONST_FUN_OBJ_1 (network_ninaw10_timer_callback_obj , network_ninaw10_timer_callback );
142178
143179STATIC mp_obj_t network_ninaw10_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
144180 mp_arg_check_num (n_args , n_kw , 0 , 1 , false);
@@ -157,6 +193,7 @@ STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {
157193 nina_obj_t * self = MP_OBJ_TO_PTR (args [0 ]);
158194 if (n_args == 2 ) {
159195 bool active = mp_obj_is_true (args [1 ]);
196+ network_ninaw10_deinit ();
160197 if (active ) {
161198 int error = 0 ;
162199 if ((error = nina_init ()) != 0 ) {
@@ -185,19 +222,9 @@ STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {
185222 NINA_FW_VER_MIN_MAJOR , NINA_FW_VER_MIN_MINOR , NINA_FW_VER_MIN_PATCH , semver [NINA_FW_VER_MAJOR_OFFS ] - 48 ,
186223 semver [NINA_FW_VER_MINOR_OFFS ] - 48 , semver [NINA_FW_VER_PATCH_OFFS ] - 48 );
187224 }
188- MP_STATE_PORT (mp_wifi_sockpoll_list ) = mp_obj_new_list (0 , NULL );
189- if (MP_STATE_PORT (mp_wifi_timer ) == MP_OBJ_NULL ) {
190- // Start sockets poll timer
191- mp_obj_t timer_args [] = {
192- MP_OBJ_NEW_QSTR (MP_QSTR_freq ), MP_OBJ_NEW_SMALL_INT (10 ),
193- MP_OBJ_NEW_QSTR (MP_QSTR_callback ), MP_OBJ_FROM_PTR (& network_ninaw10_timer_callback_obj ),
194- };
195- MP_STATE_PORT (mp_wifi_timer ) = MP_OBJ_TYPE_GET_SLOT (& machine_timer_type , make_new )((mp_obj_t )& machine_timer_type , 0 , 2 , timer_args );
196- }
225+ soft_timer_static_init (& mp_wifi_poll_timer , SOFT_TIMER_MODE_ONE_SHOT , 0 , network_ninaw10_timer_callback );
197226 } else {
198227 nina_deinit ();
199- MP_STATE_PORT (mp_wifi_timer ) = MP_OBJ_NULL ;
200- MP_STATE_PORT (mp_wifi_sockpoll_list ) = MP_OBJ_NULL ;
201228 }
202229 self -> active = active ;
203230 return mp_const_none ;
@@ -278,7 +305,8 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
278305 self -> security = security ;
279306 strncpy (self -> key , key , NINA_MAX_WPA_LEN );
280307 strncpy (self -> ssid , ssid , NINA_MAX_SSID_LEN );
281- mp_sched_schedule_node (& mp_wifi_connpoll_node , network_ninaw10_poll_connect );
308+ self -> poll_enable = true;
309+ soft_timer_reinsert (& mp_wifi_poll_timer , NINAW10_POLL_INTERVAL );
282310 } else {
283311 mp_uint_t channel = args [ARG_channel ].u_int ;
284312
@@ -528,10 +556,8 @@ STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *
528556STATIC void network_ninaw10_socket_close (mod_network_socket_obj_t * socket ) {
529557 debug_printf ("socket_close(%d)\n" , socket -> fileno );
530558 if (socket -> callback != MP_OBJ_NULL ) {
531- mp_sched_lock ();
532559 socket -> callback = MP_OBJ_NULL ;
533- mp_obj_list_remove (MP_STATE_PORT (mp_wifi_sockpoll_list ), socket );
534- mp_sched_unlock ();
560+ network_ninaw10_poll_list_remove (socket );
535561 }
536562 if (socket -> fileno >= 0 ) {
537563 nina_socket_close (socket -> fileno );
@@ -739,7 +765,8 @@ STATIC int network_ninaw10_socket_setsockopt(mod_network_socket_obj_t *socket, m
739765 mp_sched_lock ();
740766 socket -> callback = (void * )optval ;
741767 if (socket -> callback != MP_OBJ_NULL ) {
742- mp_obj_list_append (MP_STATE_PORT (mp_wifi_sockpoll_list ), socket );
768+ network_ninaw10_poll_list_insert (socket );
769+ soft_timer_reinsert (& mp_wifi_poll_timer , NINAW10_POLL_INTERVAL );
743770 }
744771 mp_sched_unlock ();
745772 return 0 ;
@@ -803,6 +830,14 @@ STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uin
803830 return ret ;
804831}
805832
833+ STATIC void network_ninaw10_deinit (void ) {
834+ // On soft-reboot, gc_sweep_all is called and all open sockets are closed
835+ // and collected. Make sure that the driver is not keeping any references
836+ // to collected sockets in the poll list.
837+ soft_timer_remove (& mp_wifi_poll_timer );
838+ MP_STATE_PORT (mp_wifi_poll_list ) = NULL ;
839+ }
840+
806841STATIC const mp_rom_map_elem_t nina_locals_dict_table [] = {
807842 { MP_ROM_QSTR (MP_QSTR_active ), MP_ROM_PTR (& network_ninaw10_active_obj ) },
808843 { MP_ROM_QSTR (MP_QSTR_scan ), MP_ROM_PTR (& network_ninaw10_scan_obj ) },
@@ -826,6 +861,7 @@ STATIC MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
826861
827862STATIC const mod_network_nic_protocol_t mod_network_nic_protocol_nina = {
828863 .gethostbyname = network_ninaw10_gethostbyname ,
864+ .deinit = network_ninaw10_deinit ,
829865 .socket = network_ninaw10_socket_socket ,
830866 .close = network_ninaw10_socket_close ,
831867 .bind = network_ninaw10_socket_bind ,
@@ -851,7 +887,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
851887 );
852888
853889MP_REGISTER_ROOT_POINTER (struct _machine_spi_obj_t * mp_wifi_spi );
854- MP_REGISTER_ROOT_POINTER (struct _machine_timer_obj_t * mp_wifi_timer );
855- MP_REGISTER_ROOT_POINTER (struct _mp_obj_list_t * mp_wifi_sockpoll_list );
890+ MP_REGISTER_ROOT_POINTER (struct _mp_obj_list_t * mp_wifi_poll_list );
856891
857892#endif // #if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10
0 commit comments