Skip to content

Commit 827e41a

Browse files
authored
Merge pull request #9350 from dhalbert/fix-espressif-ping
espressif: fix returning ping time and pinging too often
2 parents ac598a3 + a004c16 commit 827e41a

File tree

3 files changed

+45
-15
lines changed

3 files changed

+45
-15
lines changed

ports/espressif/common-hal/wifi/Radio.c

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
536541
mp_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

564588
void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self) {

ports/espressif/common-hal/wifi/Radio.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,16 @@ typedef struct {
3232
esp_netif_ip_info_t ip_info;
3333
esp_netif_dns_info_t dns_info;
3434
esp_netif_t *netif;
35+
uint32_t ping_elapsed_time;
36+
wifi_config_t ap_config;
37+
esp_netif_ip_info_t ap_ip_info;
38+
esp_netif_t *ap_netif;
3539
bool started;
3640
bool ap_mode;
3741
bool sta_mode;
3842
uint8_t retries_left;
3943
uint8_t starting_retries;
4044
uint8_t last_disconnect_reason;
41-
wifi_config_t ap_config;
42-
esp_netif_ip_info_t ap_ip_info;
43-
esp_netif_t *ap_netif;
4445
} wifi_radio_obj_t;
4546

4647
extern void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self);

shared-bindings/wifi/Radio.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,12 @@ MP_PROPERTY_GETTER(wifi_radio_ap_info_obj,
698698
//| self, ip: ipaddress.IPv4Address, *, timeout: Optional[float] = 0.5
699699
//| ) -> Optional[float]:
700700
//| """Ping an IP to test connectivity. Returns echo time in seconds.
701-
//| Returns None when it times out."""
701+
//| Returns None when it times out.
702+
//|
703+
//| **Limitations:** On Espressif, calling `ping()` multiple times rapidly
704+
//| exhausts available resources after several calls. Rather than failing at that point, `ping()`
705+
//| will wait two seconds for enough resources to be freed up before proceeding.
706+
//| """
702707
//| ...
703708
//|
704709
static mp_obj_t wifi_radio_ping(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {

0 commit comments

Comments
 (0)