@@ -532,32 +532,59 @@ void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t
532
532
common_hal_wifi_radio_start_dhcp_server (self ); // restart access point DHCP
533
533
}
534
534
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
+
535
540
mp_int_t common_hal_wifi_radio_ping (wifi_radio_obj_t * self , mp_obj_t ip_address , mp_float_t timeout ) {
536
541
esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG ();
537
542
ipaddress_ipaddress_to_esp_idf (ip_address , & ping_config .target_addr );
538
543
ping_config .count = 1 ;
539
544
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
+
540
552
size_t timeout_ms = timeout * 1000 ;
541
553
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.
542
556
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
+
544
573
esp_ping_start (ping );
545
574
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
+
548
578
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 ()) {
550
582
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 ));
557
583
}
584
+ esp_ping_stop (ping );
558
585
esp_ping_delete_session (ping );
559
586
560
- return elapsed_time ;
587
+ return ( mp_int_t ) self -> ping_elapsed_time ;
561
588
}
562
589
563
590
void common_hal_wifi_radio_gc_collect (wifi_radio_obj_t * self ) {
0 commit comments