Недавно наткнулся на неприметную струтуру в драйвере WiFi, на которую раньше не обращал внимания. Но сегодня у меня был выходной и я сел с утра и вот к пяти часам расколупал.
Это счетчик. Статисика WiFi, которую просто и легко можно использовать у себя в скетче. На ESP32 не проверял, но уверен, что заработает: там тот-же драйвер. Счетчик принятых и отправленных фреймов, счетчики по типам фреймов, кое-какие индикаторы ошибок, то-сё.
Удобно использовать для отладки WiFi, когда соединение не устанавливается или сбрасывается.
Кот:
// Этот код демонстрирует доступ к счётчикам драйвера WiFi на ESP32 / ESP32-S3
// в среде Arduino Framework.
//
#include <Arduino.h>
// Счётчики увеличиваются драйвером WiFi. Я не нашёл в коде Espressif места,
// где эти счётчики очищаются, поэтому при необходимости пользователь должен
// сбрасывать их самостоятельно.
// Счётчики обнуляются при запуске системы, но не сбрасываются при
// включении или выключении интерфейса. Наверно стоит использовать __attribute__((packed)),
// но вроде работает и так.
// Если расползутся значения при очередном апдейте компилятора - допишите packed.
typedef struct {
// Статистика RX для STA
uint32_t sta_total_rx; // Общее количество WiFi-фреймов, принятых STA
uint32_t sta_data; // Общее количество data-фреймов, принятых STA
uint16_t sta_ctl; // Control-фреймы
uint16_t sta_mgmt; // Management-фреймы
uint16_t sta_bcn_probe; // Beacon / Probe фреймы
// Не совсем понятно, почему следующие счётчики 8-битные.
// Возможно, Espressif экономит память, предполагая, что такие события
// происходят относительно редко. В любом случае все счётчики в этой
// структуре могут (и будут) переполняться и начинать отсчёт заново.
uint8_t sta_assoc; // Количество ASSOC-запросов?
uint8_t sta_auth; // Количество успешных попыток аутентификации?
uint8_t sta_deauth; // Количество deauth-фреймов?
uint8_t sta_action; // Количество action-фреймов?
uint16_t sta_amsdu; // AMSDU-фреймы
// Статистика RX для AP
uint32_t ap_total_rx; // То же самое, но для интерфейса AP
uint32_t ap_data;
uint16_t ap_ctl;
uint16_t ap_mgmt;
uint16_t ap_bcn_probe;
uint8_t ap_assoc;
uint8_t ap_auth;
uint8_t ap_deauth;
uint8_t ap_action;
uint16_t ap_amsdu;
// Статистика TX
uint32_t ap_total_tx; // AP: общее количество переданных фреймов
uint32_t sta_total_tx; // STA: общее количество переданных фреймов
// Очередь Power Save? Точное назначение этого блока неизвестно.
// Названия полей структуры взяты из кода Espressif.
//
uint16_t psq_tx; // Фреймы в очереди?
uint16_t psq_mc; // Multicast-фреймы в очереди?
uint16_t psq_uc; // Unicast-фреймы в очереди?
uint16_t reorder; // События AMPDU reorder? <-- увеличивается при некоторых ошибках
uint16_t oos; // Out-of-sequence события? <-- увеличивается при некоторых ошибках
uint16_t ps_uc1; // Назначение неизвестно
uint16_t tx_amsdu; // TX AMSDU
} hmac_cnt_t;
// Объявляем переменную со счётчиками. Остальное сделает линкер.
//
#ifdef __cplusplus
extern "C" {
#endif
extern hmac_cnt_t g_hmac_cnt;
#ifdef __cplusplus
};
#endif
void setup() {
Serial.begin(115200);
}
void loop() {
delay(1000);
Serial.printf("STA total frames received=%lu, data frames=%lu, ctrl=%u, mgmt=%u\r\n"
"STA total frames sent %lu\r\n",
g_hmac_cnt.sta_total_rx,
g_hmac_cnt.sta_data,
g_hmac_cnt.sta_ctl,
g_hmac_cnt.sta_mgmt,
g_hmac_cnt.sta_total_tx
);
}