walker2048 发表于 2024-6-5 23:52

【FireBeetle 2 ESP32 C6开发板】3、ESPNOW性能测试--响应时间测试

<div class='showpostmsg'>### 前言
ESP-NOW 是乐鑫定义的一种无线通信协议,能够在无路由器的情况下直接、快速、低功耗地控制智能设备。它能够与 Wi-Fi 和 Bluetooth LE 共存,支持乐鑫 ESP8266、ESP32、ESP32-S 和 ESP32-C 等多系列 SoC。ESP-NOW 广泛应用于智能家电、远程控制和传感器等领域。

我们在使用ESP-NOW的时候,都非常想知道它的性能指标,例如带宽、延迟之类的。在查看espnow仓库源码的时候,正好发现了相关的测试代码,我们可以来看一下。

#### 用于测试ESP-NOW性能指标的源码
在ESPNOW仓库源码里,可以找到测试相关的代码(components/esp-now/src/debug/src/commands/cmd_iperf.c)
上一个章节里,我们测试了ESP-NOW的带宽性能,现在测试一下响应时间。同样的,发起者的代码如下
```c
static void espnow_iperf_ping_task(void *arg)
{
    esp_err_t ret   = ESP_OK;
    espnow_iperf_data_t *iperf_data = ESP_CALLOC(1, g_iperf_cfg.packet_len);
    size_t send_count = 0;
    size_t recv_count = 0;
    uint32_t spend_time_ms = 0;
    int64_t s_time = esp_timer_get_time();

    size_t recv_size      = 0;
    uint32_t max_time_ms= 0;
    uint32_t min_time_ms= UINT32_MAX;
    uint32_t res_time_ms= 0;
    wifi_pkt_rx_ctrl_t rx_ctrl = {0};

    if (!g_iperf_cfg.frame_head.broadcast) {
      espnow_add_peer(g_iperf_cfg.addr, NULL);
    }

    for (; send_count < g_iperf_cfg.ping_count && !g_iperf_cfg.finish; send_count ++) {
      iperf_data->seq = send_count;
      iperf_data->type = IPERF_PING;

      if (g_iperf_cfg.gpio_num >= 0) {
            gpio_set_level(g_iperf_cfg.gpio_num, 0);
      }

      int64_t start_time = esp_timer_get_time();
      ret = espnow_send(g_iperf_cfg.type, g_iperf_cfg.addr, iperf_data,
                        g_iperf_cfg.packet_len, &g_iperf_cfg.frame_head, portMAX_DELAY);
      ESP_ERROR_CONTINUE(ret != ESP_OK, "<%s> espnow_send", esp_err_to_name(ret));

      do {
            iperf_recv_data_t recv_data = { 0 };
            if (g_iperf_queue && xQueueReceive(g_iperf_queue, &recv_data, pdMS_TO_TICKS(3000)) == pdPASS) {
                ret = ESP_OK;
                memcpy(iperf_data, recv_data.data, recv_data.size);
                memcpy(g_iperf_cfg.addr, recv_data.src_addr, 6);
                memcpy(&rx_ctrl, &recv_data.rx_ctrl, sizeof(wifi_pkt_rx_ctrl_t));
                recv_size = recv_data.size;
                ESP_FREE(recv_data.data);
            } else {
                ret = ESP_FAIL;
            }

            if (ret == ESP_OK && (iperf_data->type != IPERF_PING_ACK || iperf_data->seq != send_count)) {
                ESP_LOGW(TAG, "data_size: %d, send_seq: %d, recv_seq: %d", recv_size, send_count, iperf_data->seq);
            }
      } while (ret == ESP_OK && (iperf_data->type != IPERF_PING_ACK || iperf_data->seq != send_count));

      if (ret != ESP_OK) {
            ESP_LOGW(TAG, "seq=%d Destination Host Unreachable", iperf_data->seq);
            continue;
      }

      if (g_iperf_cfg.gpio_num >= 0) {
            gpio_set_level(g_iperf_cfg.gpio_num, 1);
      }

      res_time_ms = (uint32_t)((esp_timer_get_time() - start_time) / 1000);
      spend_time_ms += res_time_ms;

      max_time_ms = MAX(max_time_ms, res_time_ms);
      min_time_ms = MIN(min_time_ms, res_time_ms);

      recv_count++;
      ESP_LOGI(TAG, "%d bytes from " MACSTR ": seq=%d rssi=%d time=%d ms",
               recv_size, MAC2STR(g_iperf_cfg.addr), iperf_data->seq, rx_ctrl.rssi, res_time_ms);

      ESP_ERROR_CONTINUE(ret != ESP_OK, "<%s> espnow_recv", esp_err_to_name(ret));
    }

    ESP_LOGI(TAG, "initiator ping report:");
    ESP_LOGI(TAG, "ping statistics for " MACSTR, MAC2STR(g_iperf_cfg.addr));
    ESP_LOGI(TAG, "%d packets transmitted, %d received, %0.2f%% packet loss, time: total %d ms, max: %d, min: %d, average %0.2f ms",
             send_count, recv_count, (send_count - recv_count) * 100.0 / send_count,
             (int)((esp_timer_get_time() - s_time) / 1000), max_time_ms, min_time_ms, spend_time_ms * 1.0 / recv_count);

    g_iperf_cfg.finish = true;

    if (!g_iperf_cfg.frame_head.broadcast) {
      espnow_del_peer(g_iperf_cfg.addr);
    }

    espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_RESERVED, 0, NULL);
    if (g_iperf_queue) {
      iperf_recv_data_t tmp_data ={ 0 };

      while (xQueueReceive(g_iperf_queue, &tmp_data, 0)) {
            ESP_FREE(tmp_data.data);
      }

      vQueueDelete(g_iperf_queue);
      g_iperf_queue = NULL;
    }

    ESP_FREE(iperf_data);
    vTaskDelete(NULL);
}
```
而响应代码和上次测试iperf的响应代码是一样的,其实从代码里,我们可以看出,发起和响应两方,都是通过iperf_data->type这个数据结构来判断数据包类型和应该执行什么操作的,只是发起方是作为主导方,发起相关的测试,响应方根据iperf_data->type的类型做出对应的操作。

测试结果如图:


在我这边测试的结果,即使是PCB天线,在穿透1堵墙,距离约12米的情况下,响应时间还是可以保持在6ms,最差14ms,平均8.55ms的一个性能指标(这里的响应时间,指的是发起方发出ping消息开始,到响应方返回ack数据包并到达发起方的时间,也就是一来一回的总时间)。这样的一个性能指标,个人觉得是非常不错的了。
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                               
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>
页: [1]
查看完整版本: 【FireBeetle 2 ESP32 C6开发板】3、ESPNOW性能测试--响应时间测试