@@ -533,32 +533,56 @@ void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t
533533 common_hal_wifi_radio_start_dhcp_server (self ); // restart access point DHCP
534534}
535535
536+ static void ping_success_cb (esp_ping_handle_t hdl , void * args ) {
537+ wifi_radio_obj_t * self = (wifi_radio_obj_t * )args ;
538+ esp_ping_get_profile (hdl , ESP_PING_PROF_TIMEGAP , & self -> ping_elapsed_time , sizeof (self -> ping_elapsed_time ));
539+ }
540+
536541mp_int_t common_hal_wifi_radio_ping (wifi_radio_obj_t * self , mp_obj_t ip_address , mp_float_t timeout ) {
537542 esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG ();
538543 ipaddress_ipaddress_to_esp_idf (ip_address , & ping_config .target_addr );
539544 ping_config .count = 1 ;
540545
546+ // We must fetch ping information using the callback mechanism, because the session storage is freed when
547+ // the ping session is done, even before esp_ping_delete_session().
548+ esp_ping_callbacks_t ping_callbacks = {
549+ .on_ping_success = ping_success_cb ,
550+ .cb_args = (void * )self ,
551+ };
552+
541553 size_t timeout_ms = timeout * 1000 ;
542554
555+ // ESP-IDF creates a task to do the ping session. It shuts down when done, but only after a one second delay.
556+ // Calling common_hal_wifi_radio_ping() too fast will cause resource exhaustion.
543557 esp_ping_handle_t ping ;
544- CHECK_ESP_RESULT (esp_ping_new_session (& ping_config , NULL , & ping ));
558+ if (esp_ping_new_session (& ping_config , & ping_callbacks , & ping ) != ESP_OK ) {
559+ // Wait for old task to go away and then try again.
560+ // Empirical testing shows we have to wait at least two seconds, despite the task
561+ // having a one-second timeout.
562+ common_hal_time_delay_ms (2000 );
563+ // Return if interrupted now, to show the interruption as KeyboardInterrupt instead of the
564+ // IDF error.
565+ if (mp_hal_is_interrupted ()) {
566+ return (uint32_t )(-1 );
567+ }
568+ CHECK_ESP_RESULT (esp_ping_new_session (& ping_config , & ping_callbacks , & ping ));
569+ }
570+
545571 esp_ping_start (ping );
546572
547- uint32_t received = 0 ;
548- uint32_t total_time_ms = 0 ;
573+ // Use all ones as a flag that the elapsed time was not set (ping failed or timed out).
574+ self -> ping_elapsed_time = (uint32_t )(-1 );
575+
549576 uint32_t start_time = common_hal_time_monotonic_ms ();
550- while (received == 0 && (common_hal_time_monotonic_ms () - start_time < timeout_ms ) && !mp_hal_is_interrupted ()) {
577+ while ((self -> ping_elapsed_time == (uint32_t )(-1 )) &&
578+ (common_hal_time_monotonic_ms () - start_time < timeout_ms ) &&
579+ !mp_hal_is_interrupted ()) {
551580 RUN_BACKGROUND_TASKS ;
552- esp_ping_get_profile (ping , ESP_PING_PROF_DURATION , & total_time_ms , sizeof (total_time_ms ));
553- esp_ping_get_profile (ping , ESP_PING_PROF_REPLY , & received , sizeof (received ));
554- }
555- uint32_t elapsed_time = 0xffffffff ;
556- if (received > 0 ) {
557- esp_ping_get_profile (ping , ESP_PING_PROF_TIMEGAP , & elapsed_time , sizeof (elapsed_time ));
558581 }
582+ esp_ping_stop (ping );
559583 esp_ping_delete_session (ping );
560584
561- return elapsed_time ;
585+ return ( mp_int_t ) self -> ping_elapsed_time ;
562586}
563587
564588void common_hal_wifi_radio_gc_collect (wifi_radio_obj_t * self ) {
0 commit comments