@@ -532,32 +532,59 @@ void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t
532532 common_hal_wifi_radio_start_dhcp_server (self ); // restart access point DHCP
533533}
534534
535+ static void ping_success_cb (esp_ping_handle_t hdl , void * args ) {
536+ wifi_radio_obj_t * self = (wifi_radio_obj_t * )args ;
537+ esp_ping_get_profile (hdl , ESP_PING_PROF_TIMEGAP , & self -> ping_elapsed_time , sizeof (self -> ping_elapsed_time ));
538+ }
539+
535540mp_int_t common_hal_wifi_radio_ping (wifi_radio_obj_t * self , mp_obj_t ip_address , mp_float_t timeout ) {
536541 esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG ();
537542 ipaddress_ipaddress_to_esp_idf (ip_address , & ping_config .target_addr );
538543 ping_config .count = 1 ;
539544
545+ // We must fetch ping information using the callback mechanism, because the session storage is freed when
546+ // the ping session is done, even before esp_ping_delete_session().
547+ esp_ping_callbacks_t ping_callbacks = {
548+ .on_ping_success = ping_success_cb ,
549+ .cb_args = (void * )self ,
550+ };
551+
540552 size_t timeout_ms = timeout * 1000 ;
541553
554+ // ESP-IDF creates a task to do the ping session. It shuts down when done, but only after a one second delay.
555+ // Calling common_hal_wifi_radio_ping() too fast will cause resource exhaustion.
542556 esp_ping_handle_t ping ;
543- CHECK_ESP_RESULT (esp_ping_new_session (& ping_config , NULL , & ping ));
557+ esp_err_t ret ;
558+ for (size_t tries = 1 ; tries <= 5 ; tries ++ ) {
559+ ret = esp_ping_new_session (& ping_config , & ping_callbacks , & ping );
560+ if (ret == ESP_OK ) {
561+ break ;
562+ }
563+ // Wait for old task to go away and then try again.
564+ // Empirical testing shows we have to wait at least two seconds, despite the task
565+ // having a one-second timeout.
566+ common_hal_time_delay_ms (2000 );
567+ if (mp_hal_is_interrupted ()) {
568+ return -1 ;
569+ }
570+ }
571+ CHECK_ESP_RESULT (ret );
572+
544573 esp_ping_start (ping );
545574
546- uint32_t received = 0 ;
547- uint32_t total_time_ms = 0 ;
575+ // Use all ones as a flag that the elapsed time was not set (ping failed or timed out).
576+ self -> ping_elapsed_time = (uint32_t )(-1 );
577+
548578 uint32_t start_time = common_hal_time_monotonic_ms ();
549- while (received == 0 && (common_hal_time_monotonic_ms () - start_time < timeout_ms ) && !mp_hal_is_interrupted ()) {
579+ while ((self -> ping_elapsed_time == (uint32_t )(-1 )) &&
580+ (common_hal_time_monotonic_ms () - start_time < timeout_ms ) &&
581+ !mp_hal_is_interrupted ()) {
550582 RUN_BACKGROUND_TASKS ;
551- esp_ping_get_profile (ping , ESP_PING_PROF_DURATION , & total_time_ms , sizeof (total_time_ms ));
552- esp_ping_get_profile (ping , ESP_PING_PROF_REPLY , & received , sizeof (received ));
553- }
554- uint32_t elapsed_time = 0xffffffff ;
555- if (received > 0 ) {
556- esp_ping_get_profile (ping , ESP_PING_PROF_TIMEGAP , & elapsed_time , sizeof (elapsed_time ));
557583 }
584+ esp_ping_stop (ping );
558585 esp_ping_delete_session (ping );
559586
560- return elapsed_time ;
587+ return ( mp_int_t ) self -> ping_elapsed_time ;
561588}
562589
563590void common_hal_wifi_radio_gc_collect (wifi_radio_obj_t * self ) {
0 commit comments