wifi_stats.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /*
  2. * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include "esp_log.h"
  9. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS || CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  10. #include "esp_console.h"
  11. #include "argtable3/argtable3.h"
  12. #include "esp_event.h"
  13. #include "esp_wifi.h"
  14. #include "esp_wifi_types.h"
  15. #include "wifi_stats.h"
  16. #include "esp_private/esp_wifi_he_private.h"
  17. /*******************************************************
  18. * Macros
  19. *******************************************************/
  20. /*
  21. * enable/disable rx/tx statistics after Wi-Fi started:
  22. * (1) esp_wifi_enable_rx_statistics(true, true); //rx_stats=true, rx_mu_stats=true
  23. * (2) esp_wifi_enable_tx_statistics(ESP_WIFI_ACI_BE, true); //aci=ESP_WIFI_ACI_BE, tx_stats=true
  24. */
  25. /*******************************************************
  26. * Constants
  27. *******************************************************/
  28. static const char *TAG = "stats";
  29. /*******************************************************
  30. * Structures
  31. *******************************************************/
  32. /*******************************************************
  33. * Variable Definitions
  34. *******************************************************/
  35. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
  36. esp_test_rx_mu_statistics_t rx_mu_stats = { 0, }; //10932 bytes
  37. #endif
  38. /*******************************************************
  39. * Function Declarations
  40. *******************************************************/
  41. /*******************************************************
  42. * Function Definitions
  43. *******************************************************/
  44. const char *tx_fail_error2str(esp_test_tx_fail_error_t error)
  45. {
  46. switch (error) {
  47. case TEST_TX_FAIL_ERROR_H00:
  48. return "0x00";
  49. case TEST_TX_FAIL_ERROR_H53:
  50. return "0x53";
  51. case TEST_TX_FAIL_ERROR_H63:
  52. return "0x63";
  53. case TEST_TX_FAIL_ERROR_H75:
  54. return "0x75";
  55. case TEST_TX_FAIL_ERROR_H41:
  56. return "0x41";
  57. case TEST_TX_FAIL_ERROR_H42:
  58. return "0x42";
  59. case TEST_TX_FAIL_ERROR_H47:
  60. return "0x47";
  61. case TEST_TX_FAIL_ERROR_H80:
  62. return "0x80";
  63. case TEST_TX_FAIL_ERROR_H5A:
  64. return "0x5A";
  65. case TEST_TX_FAIL_ERROR_HXX:
  66. return "Others";
  67. case TEST_TX_FAIL_ERROR_MAX:
  68. return "Undefined";
  69. }
  70. return "Undefined";
  71. }
  72. const char *tx_fail_match2str(esp_test_tx_fail_match_t match)
  73. {
  74. switch (match) {
  75. case TEST_TX_WAIT_MATCH:
  76. return "MATCH";
  77. case TEST_TX_WAIT_NOT2SELF:
  78. return "NOT2SELF";
  79. case TEST_TX_MISMATCH:
  80. return "MISMATCH";
  81. case TEST_TX_WAIT_TIMEOUT:
  82. return "TIMEOUT";
  83. case TEST_TX_WAIT_MAX:
  84. return "Undefined";
  85. }
  86. return "Undefined";
  87. }
  88. const char *tx_fail_state2str(esp_test_tx_fail_state_t state)
  89. {
  90. switch (state) {
  91. case TEST_TX_SUCCESS:
  92. return "TX Success";
  93. case TEST_TX_FAIL_RTS:
  94. return "TX RTS";
  95. case TEST_TX_WAIT_CTS: //RX
  96. return "Wait CTS";
  97. case TEST_TX_FAIL_CTS:
  98. return "TX RTS";
  99. case TEST_TX_FAIL_DATA:
  100. return "TX DATA";
  101. case TEST_TX_WAIT_ACK: //RX
  102. return "Wait ACK/BA";
  103. case TEST_TX_FAIL_MAX:
  104. return "Undefined";
  105. }
  106. return "Undefined";
  107. }
  108. int wifi_cmd_clr_tx_statistics(int argc, char **argv)
  109. {
  110. ESP_LOGW(TAG, "Clear tx statistics");
  111. int i;
  112. for (i = 0; i < 3; i++) {
  113. esp_wifi_clr_tx_statistics(i); //BE
  114. esp_wifi_clr_tx_tb_statistics(i);
  115. }
  116. esp_test_clr_hw_statistics();
  117. return 0;
  118. }
  119. void print_hw_tb_statistics(void)
  120. {
  121. esp_test_hw_tb_statistics_t hw_tb_stats = { 0, };
  122. esp_test_get_hw_tb_statistics(&hw_tb_stats);
  123. printf("(test)rx_trig:%d, tx_bfrpt:%d, tb_times:%d, tb_qos_null:%d, tb_qos_data:%d, tb_cca_cancel:%d, tb_sifs_abort:%d, tb_pwr_outof_range:%d\n",
  124. hw_tb_stats.rx_trig,
  125. hw_tb_stats.tx_bfrpt, //including TB and Non-TB
  126. hw_tb_stats.tb_times,
  127. hw_tb_stats.tb_qos_null,
  128. hw_tb_stats.tb_times - hw_tb_stats.tb_qos_null,
  129. hw_tb_stats.tb_cca_cancel,
  130. hw_tb_stats.tb_sifs_abort,
  131. hw_tb_stats.tb_pwr_outof_range);
  132. }
  133. int wifi_cmd_get_tx_statistics(int argc, char **argv)
  134. {
  135. uint8_t i, h, j, k;
  136. ESP_LOGW(TAG, "Get tx statistics");
  137. esp_test_tx_tb_statistics_t tb_stats = { 0, }; //32 bytes
  138. esp_test_tx_statistics_t tx_stats = { 0, }; //136 bytes
  139. esp_test_tx_fail_statistics_t tx_fail[TEST_TX_FAIL_MAX] = { 0, }; //TEST_TX_FAIL_MAX * 164 bytes
  140. print_hw_tb_statistics();
  141. //only check BE
  142. for (i = 2; i < 3; i++) {
  143. esp_wifi_get_tx_tb_statistics(i, &tb_stats);
  144. /* TB */
  145. printf("(test)aci:%" PRIu8 ", tb(suc:%" PRIu32 ", ack:%" PRIu32 ", err:%" PRIu32 "), "
  146. "count(suc:%" PRIu32 ", ack:%" PRIu32 ", err:%" PRIu32 ", tot:%" PRIu32 ", max_sent:%" PRIu32 ")\n",
  147. i,
  148. tb_stats.complete_suc_tb,
  149. tb_stats.complete_ack_tb,
  150. tb_stats.complete_err_tb,
  151. tb_stats.complete_tb_suc_count,
  152. tb_stats.complete_tb_ack_count,
  153. tb_stats.complete_tb_err_count,
  154. tb_stats.complete_tb_tot_count,
  155. tb_stats.complete_tb_pack_sent);
  156. esp_wifi_get_tx_statistics(i, &tx_stats, (esp_test_tx_fail_statistics_t *) &tx_fail);
  157. int tot_tx_times = tx_stats.tb_times + (tx_stats.tx_enable - tx_stats.tb_last); //TB + EDCA
  158. int tot_fail = tx_fail[1].count + tx_fail[2].count + tx_fail[3].count + tx_fail[4].count + tx_fail[5].count;
  159. printf("(test)aci:%" PRIu8 ", enable:%" PRIu32 ", complete:%" PRIu32 ", tb_times:%" PRIu32 ", tb_last:%" PRIu32 ", edca:%" PRIu32 ", "
  160. "succ:%" PRIu32 ", fail(%" PRIu32 ",%" PRIu32 ",%" PRIu32 ", cts:%" PRIu32 "/%2.2f%%, ack:%" PRIu32 "/%2.2f%%, tot:%d, %.2f%%), "
  161. "edca(ack:%" PRIu32 ", ba:%" PRIu32 "), tb(hw-ba:%" PRIu32 ", sw-ba:%" PRIu32 ")\n",
  162. i, tx_stats.tx_enable,
  163. tx_stats.tx_complete,
  164. tx_stats.tb_times,
  165. tx_stats.tb_last,
  166. tx_stats.tx_enable - tx_stats.tb_last,
  167. tx_fail[0].count,
  168. tx_fail[1].count,
  169. tx_fail[3].count,
  170. tx_fail[4].count,
  171. tx_fail[2].count,
  172. (float) ((float) tx_fail[2].count / (float) tot_tx_times) * 100, //rx cts
  173. tx_fail[5].count, (float) ((float) tx_fail[5].count / (float) tot_tx_times) * 100, //rx ack
  174. tot_fail,
  175. (float) ((float) tot_fail / (float) tot_tx_times) * 100,
  176. tx_stats.rx_ack,
  177. tx_stats.rx_ba,
  178. tx_stats.tb_rx_ba, //including ACKs
  179. tx_stats.rx_dump_ba);
  180. printf("(test)aci:%" PRIu8 ", txFrames:%" PRIu32 ", s-mpdu:%" PRIu32 "(%.2f%%), "
  181. "bitmap(max:%d, min:%d, tot:%" PRIu32 ", avg:%.2f), "
  182. "retry(edca:%" PRIu32 ", tb:%" PRIu32 ", %.2f%%), collision:%" PRIu32 ", timeout:%" PRIu32 "\n",
  183. i,
  184. tx_stats.tx_succ,
  185. tx_stats.rx_ack,
  186. ((float) (tx_stats.rx_ack) / (float) tot_tx_times) * 100,
  187. tx_stats.rx_max_bitmap,
  188. tx_stats.rx_min_bitmap,
  189. tx_stats.rx_tot_bitmap,
  190. (float) tx_stats.rx_tot_bitmap / (float) (tx_stats.tb_rx_ba + tx_stats.rx_ba),
  191. tx_stats.retry_edca, tx_stats.retry_tb, (float) (tx_stats.retry_edca + tx_stats.retry_tb) / (float) tx_stats.tx_succ * 100,
  192. tx_stats.collision, tx_stats.timeout);
  193. float tot_rtt_ms = (float) tx_stats.tx_tot_rtt / (float) 1000;
  194. printf("(test)aci:%" PRIu8 ", seqno_rtt[%" PRIu32 ",%" PRIu32 "], hw_rtt[%" PRIu32 ", %" PRIu32 "], muedca[enable:%" PRIu32 ", times:%" PRIu32 ", %.2f, %.2f, tot:%.2f], avg:%.3f ms, tot:%.3f secs\n",
  195. i,
  196. tx_stats.tx_seq_min_rtt,
  197. tx_stats.tx_seq_max_rtt,
  198. tx_stats.tx_min_rtt,
  199. tx_stats.tx_max_rtt,
  200. tx_stats.tx_muedca_enable,
  201. tx_stats.muedca_times,
  202. (float) tx_stats.tx_min_muedca_time / (float) 1000,
  203. (float) tx_stats.tx_max_muedca_time / (float) 1000,
  204. (float) tx_stats.tx_tot_muedca_time / (float) 1000, //ms
  205. (float) tot_rtt_ms / (float) tot_tx_times, //ms
  206. (float) tot_rtt_ms / (float) 1000); //seconds
  207. /* fail state */
  208. for (h = 1; h < TEST_TX_FAIL_MAX; h++) { //state
  209. for (j = 0; j < TEST_TX_WAIT_MAX; j++) { //match
  210. for (k = 0; k < TEST_TX_FAIL_ERROR_MAX; k++) { //error
  211. if (tx_fail[h].match[j][k]) {
  212. printf("(test)[%d][%d][%d](%16s + %16s + %16s)%3" PRIu32 "/%3" PRIu32 "(%.2f%%)\n", h, j, k, tx_fail_state2str(h),
  213. tx_fail_match2str(j), tx_fail_error2str(k),
  214. tx_fail[h].match[j][k], tx_fail[h].count,
  215. ((float) tx_fail[h].match[j][k] / (float) tx_fail[h].count) * 100);
  216. }
  217. }
  218. }
  219. }
  220. printf("\n");
  221. }
  222. wifi_cmd_clr_tx_statistics(0, 0);
  223. return 0;
  224. }
  225. void print_rx_statistics_nonmimo(const esp_test_rx_mu_statistics_t *mu_stats)
  226. {
  227. if (!mu_stats->nonmimo_rx) {
  228. return;
  229. }
  230. int i, j;
  231. int tot_rx_nonmimo = 0;
  232. ESP_LOGW(TAG, "(nonmimo)dut rx:%" PRIu32, mu_stats->nonmimo_rx);
  233. ESP_LOGW(TAG, "(nonmimo)ru_alloc_96_num_2046:%" PRIu32 ", ru_alloc_112_num_2046:%" PRIu32, mu_stats->ru_alloc_96_num_2046, mu_stats->ru_alloc_112_num_2046);
  234. ESP_LOGW(TAG, "(nonmimo)sigb, mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), mcs5:%" PRIu32 "(%2.2f%%)",
  235. mu_stats->nonmimo_sigb_mcs[0], ((float) mu_stats->nonmimo_sigb_mcs[0] / (float) mu_stats->nonmimo_rx) * 100,
  236. mu_stats->nonmimo_sigb_mcs[1], ((float) mu_stats->nonmimo_sigb_mcs[1] / (float) mu_stats->nonmimo_rx) * 100,
  237. mu_stats->nonmimo_sigb_mcs[2], ((float) mu_stats->nonmimo_sigb_mcs[2] / (float) mu_stats->nonmimo_rx) * 100,
  238. mu_stats->nonmimo_sigb_mcs[3], ((float) mu_stats->nonmimo_sigb_mcs[3] / (float) mu_stats->nonmimo_rx) * 100,
  239. mu_stats->nonmimo_sigb_mcs[4], ((float) mu_stats->nonmimo_sigb_mcs[4] / (float) mu_stats->nonmimo_rx) * 100,
  240. mu_stats->nonmimo_sigb_mcs[5], ((float) mu_stats->nonmimo_sigb_mcs[5] / (float) mu_stats->nonmimo_rx) * 100);
  241. ESP_LOGW(TAG, "(nonmimo)users, num1:%" PRIu32 "(%2.2f%%), num2:%" PRIu32 "(%2.2f%%), num3:%" PRIu32 "(%2.2f%%), num4:%" PRIu32 "(%2.2f%%), num5:%" PRIu32 "(%2.2f%%), num6:%" PRIu32 "(%2.2f%%), num7:%" PRIu32 "(%2.2f%%), num8:%" PRIu32 "(%2.2f%%), num9:%" PRIu32 "(%2.2f%%)",
  242. mu_stats->nonmimo_user_num_occu[0], ((float) mu_stats->nonmimo_user_num_occu[0] / (float) mu_stats->nonmimo_rx) * 100,
  243. mu_stats->nonmimo_user_num_occu[1], ((float) mu_stats->nonmimo_user_num_occu[1] / (float) mu_stats->nonmimo_rx) * 100,
  244. mu_stats->nonmimo_user_num_occu[2], ((float) mu_stats->nonmimo_user_num_occu[2] / (float) mu_stats->nonmimo_rx) * 100,
  245. mu_stats->nonmimo_user_num_occu[3], ((float) mu_stats->nonmimo_user_num_occu[3] / (float) mu_stats->nonmimo_rx) * 100,
  246. mu_stats->nonmimo_user_num_occu[4], ((float) mu_stats->nonmimo_user_num_occu[4] / (float) mu_stats->nonmimo_rx) * 100,
  247. mu_stats->nonmimo_user_num_occu[5], ((float) mu_stats->nonmimo_user_num_occu[5] / (float) mu_stats->nonmimo_rx) * 100,
  248. mu_stats->nonmimo_user_num_occu[6], ((float) mu_stats->nonmimo_user_num_occu[6] / (float) mu_stats->nonmimo_rx) * 100,
  249. mu_stats->nonmimo_user_num_occu[7], ((float) mu_stats->nonmimo_user_num_occu[7] / (float) mu_stats->nonmimo_rx) * 100,
  250. mu_stats->nonmimo_user_num_occu[8], ((float) mu_stats->nonmimo_user_num_occu[8] / (float) mu_stats->nonmimo_rx) * 100);
  251. for (i = 0; i < 256; i++) {
  252. for (j = 0; j < 9; j++) {
  253. if (!mu_stats->nonmimo_ru_alloc[i][j]) {
  254. continue;
  255. }
  256. ESP_LOGI(TAG, "(nonmimo)ru_allocation:0x%2x(%3" PRIu8 "), position:%" PRIu8 ", %5" PRIu32 "(%2.2f%%)", i, i, j + 1, mu_stats->nonmimo_ru_alloc[i][j],
  257. ((float) mu_stats->nonmimo_ru_alloc[i][j] / (float) mu_stats->nonmimo_rx) * 100);
  258. }
  259. }
  260. for (i = 0; i < ESP_TEST_RX_MU_USER_NUM; i++) {
  261. if (!mu_stats->nonmimo[i].aid) {
  262. continue;
  263. }
  264. if (mu_stats->aid != mu_stats->nonmimo[i].aid) {
  265. continue;
  266. }
  267. tot_rx_nonmimo = mu_stats->nonmimo[i].occu_nsts[0] + mu_stats->nonmimo[i].occu_nsts[1] + mu_stats->nonmimo[i].occu_nsts[2] + mu_stats->nonmimo[i].occu_nsts[3];
  268. printf("[%" PRIu8 "]%said:0x%x, txbf:%" PRIu32 ", dcm:%" PRIu32 "\n", i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
  269. mu_stats->nonmimo[i].txbf, mu_stats->nonmimo[i].dcm);
  270. printf("[%d]%said:0x%x, "
  271. "mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), "
  272. "mcs5:%" PRIu32 "(%2.2f%%), mcs6:%" PRIu32 "(%2.2f%%), mcs7:%" PRIu32 "(%2.2f%%), mcs8:%" PRIu32 "(%2.2f%%), mcs9:%" PRIu32 "(%2.2f%%), "
  273. "mcs10:%" PRIu32 "(%2.2f%%), mcs11:%" PRIu32 "(%2.2f%%)\n",
  274. i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
  275. mu_stats->nonmimo[i].occu_mcs[0], ((float) mu_stats->nonmimo[i].occu_mcs[0] / (float) tot_rx_nonmimo) * 100,
  276. mu_stats->nonmimo[i].occu_mcs[1], ((float) mu_stats->nonmimo[i].occu_mcs[1] / (float) tot_rx_nonmimo) * 100,
  277. mu_stats->nonmimo[i].occu_mcs[2], ((float) mu_stats->nonmimo[i].occu_mcs[2] / (float) tot_rx_nonmimo) * 100,
  278. mu_stats->nonmimo[i].occu_mcs[3], ((float) mu_stats->nonmimo[i].occu_mcs[3] / (float) tot_rx_nonmimo) * 100,
  279. mu_stats->nonmimo[i].occu_mcs[4], ((float) mu_stats->nonmimo[i].occu_mcs[4] / (float) tot_rx_nonmimo) * 100,
  280. mu_stats->nonmimo[i].occu_mcs[5], ((float) mu_stats->nonmimo[i].occu_mcs[5] / (float) tot_rx_nonmimo) * 100,
  281. mu_stats->nonmimo[i].occu_mcs[6], ((float) mu_stats->nonmimo[i].occu_mcs[6] / (float) tot_rx_nonmimo) * 100,
  282. mu_stats->nonmimo[i].occu_mcs[7], ((float) mu_stats->nonmimo[i].occu_mcs[7] / (float) tot_rx_nonmimo) * 100,
  283. mu_stats->nonmimo[i].occu_mcs[8], ((float) mu_stats->nonmimo[i].occu_mcs[8] / (float) tot_rx_nonmimo) * 100,
  284. mu_stats->nonmimo[i].occu_mcs[9], ((float) mu_stats->nonmimo[i].occu_mcs[9] / (float) tot_rx_nonmimo) * 100,
  285. mu_stats->nonmimo[i].occu_mcs[10], ((float) mu_stats->nonmimo[i].occu_mcs[10] / (float) tot_rx_nonmimo) * 100,
  286. mu_stats->nonmimo[i].occu_mcs[11], ((float) mu_stats->nonmimo[i].occu_mcs[11] / (float) tot_rx_nonmimo) * 100);
  287. printf("[%" PRIu8 "]%said:0x%x, "
  288. "nsts0:%" PRIu32 "(%2.2f%%), nsts1:%" PRIu32 "(%2.2f%%), nsts2:%" PRIu32 "(%2.2f%%), nsts3:%" PRIu32 "(%2.2f%%)\n",
  289. i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
  290. mu_stats->nonmimo[i].occu_nsts[0], ((float) mu_stats->nonmimo[i].occu_nsts[0] / (float) tot_rx_nonmimo) * 100,
  291. mu_stats->nonmimo[i].occu_nsts[1], ((float) mu_stats->nonmimo[i].occu_nsts[1] / (float) tot_rx_nonmimo) * 100,
  292. mu_stats->nonmimo[i].occu_nsts[2], ((float) mu_stats->nonmimo[i].occu_nsts[2] / (float) tot_rx_nonmimo) * 100,
  293. mu_stats->nonmimo[i].occu_nsts[3], ((float) mu_stats->nonmimo[i].occu_nsts[3] / (float) tot_rx_nonmimo) * 100);
  294. printf("[%" PRIu8 "]%said:0x%x, "
  295. "tot_rx_nonmimo:%8d, sta/dut:%2.2f%%\n",
  296. i, (mu_stats->aid == mu_stats->nonmimo[i].aid) ? "#" : " ", mu_stats->nonmimo[i].aid,
  297. tot_rx_nonmimo, ((float) tot_rx_nonmimo / (float) mu_stats->nonmimo_rx) * 100);
  298. }
  299. }
  300. void print_rx_statistics_mimo(const esp_test_rx_mu_statistics_t *mu_stats)
  301. {
  302. if (!mu_stats->mimo_rx) {
  303. return;
  304. }
  305. int i;
  306. int tot_rx_mimo = 0;
  307. ESP_LOGW(TAG, "(mimo)dut rx:%" PRIu32 "", mu_stats->mimo_rx);
  308. ESP_LOGW(TAG, "(mimo)sigb, mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), mcs5:%" PRIu32 "(%2.2f%%)",
  309. mu_stats->mimo_sigb_mcs[0], ((float) mu_stats->mimo_sigb_mcs[0] / (float) mu_stats->mimo_rx) * 100,
  310. mu_stats->mimo_sigb_mcs[1], ((float) mu_stats->mimo_sigb_mcs[1] / (float) mu_stats->mimo_rx) * 100,
  311. mu_stats->mimo_sigb_mcs[2], ((float) mu_stats->mimo_sigb_mcs[2] / (float) mu_stats->mimo_rx) * 100,
  312. mu_stats->mimo_sigb_mcs[3], ((float) mu_stats->mimo_sigb_mcs[3] / (float) mu_stats->mimo_rx) * 100,
  313. mu_stats->mimo_sigb_mcs[4], ((float) mu_stats->mimo_sigb_mcs[4] / (float) mu_stats->mimo_rx) * 100,
  314. mu_stats->mimo_sigb_mcs[5], ((float) mu_stats->mimo_sigb_mcs[5] / (float) mu_stats->mimo_rx) * 100);
  315. ESP_LOGW(TAG, "(mimo)users num2:%" PRIu32 "(%2.2f%%), num3:%" PRIu32 "(%2.2f%%), num4:%" PRIu32 "(%2.2f%%), num5:%" PRIu32 "(%2.2f%%), num6:%" PRIu32 "(%2.2f%%), num7:%" PRIu32 "(%2.2f%%), num8:%" PRIu32 "(%2.2f%%)",
  316. mu_stats->mimo_user_num_occu[0], ((float) mu_stats->mimo_user_num_occu[0] / (float) mu_stats->mimo_rx) * 100,
  317. mu_stats->mimo_user_num_occu[1], ((float) mu_stats->mimo_user_num_occu[1] / (float) mu_stats->mimo_rx) * 100,
  318. mu_stats->mimo_user_num_occu[2], ((float) mu_stats->mimo_user_num_occu[2] / (float) mu_stats->mimo_rx) * 100,
  319. mu_stats->mimo_user_num_occu[3], ((float) mu_stats->mimo_user_num_occu[3] / (float) mu_stats->mimo_rx) * 100,
  320. mu_stats->mimo_user_num_occu[4], ((float) mu_stats->mimo_user_num_occu[4] / (float) mu_stats->mimo_rx) * 100,
  321. mu_stats->mimo_user_num_occu[5], ((float) mu_stats->mimo_user_num_occu[5] / (float) mu_stats->mimo_rx) * 100,
  322. mu_stats->mimo_user_num_occu[6], ((float) mu_stats->mimo_user_num_occu[6] / (float) mu_stats->mimo_rx) * 100);
  323. for (i = 0; i < ESP_TEST_RX_MU_USER_NUM; i++) {
  324. if (!mu_stats->mimo[i].aid) {
  325. continue;
  326. }
  327. tot_rx_mimo = mu_stats->mimo[i].occu_ss[0] + mu_stats->mimo[i].occu_ss[1] + mu_stats->mimo[i].occu_ss[2] + mu_stats->mimo[i].occu_ss[3];
  328. printf("[%" PRIu8 "]%said:0x%x, "
  329. "mcs0:%" PRIu32 "(%2.2f%%), mcs1:%" PRIu32 "(%2.2f%%), mcs2:%" PRIu32 "(%2.2f%%), mcs3:%" PRIu32 "(%2.2f%%), mcs4:%" PRIu32 "(%2.2f%%), "
  330. "mcs5:%" PRIu32 "(%2.2f%%), mcs6:%" PRIu32 "(%2.2f%%), mcs7:%" PRIu32 "(%2.2f%%), mcs8:%" PRIu32 "(%2.2f%%), mcs9:%" PRIu32 "(%2.2f%%), "
  331. "mcs10:%" PRIu32 "(%2.2f%%), mcs11:%" PRIu32 "(%2.2f%%)\n",
  332. i, (mu_stats->aid == mu_stats->mimo[i].aid) ? "#" : " ", mu_stats->mimo[i].aid,
  333. mu_stats->mimo[i].occu_mcs[0], ((float) mu_stats->mimo[i].occu_mcs[0] / (float) tot_rx_mimo) * 100,
  334. mu_stats->mimo[i].occu_mcs[1], ((float) mu_stats->mimo[i].occu_mcs[1] / (float) tot_rx_mimo) * 100,
  335. mu_stats->mimo[i].occu_mcs[2], ((float) mu_stats->mimo[i].occu_mcs[2] / (float) tot_rx_mimo) * 100,
  336. mu_stats->mimo[i].occu_mcs[3], ((float) mu_stats->mimo[i].occu_mcs[3] / (float) tot_rx_mimo) * 100,
  337. mu_stats->mimo[i].occu_mcs[4], ((float) mu_stats->mimo[i].occu_mcs[4] / (float) tot_rx_mimo) * 100,
  338. mu_stats->mimo[i].occu_mcs[5], ((float) mu_stats->mimo[i].occu_mcs[5] / (float) tot_rx_mimo) * 100,
  339. mu_stats->mimo[i].occu_mcs[6], ((float) mu_stats->mimo[i].occu_mcs[6] / (float) tot_rx_mimo) * 100,
  340. mu_stats->mimo[i].occu_mcs[7], ((float) mu_stats->mimo[i].occu_mcs[7] / (float) tot_rx_mimo) * 100,
  341. mu_stats->mimo[i].occu_mcs[8], ((float) mu_stats->mimo[i].occu_mcs[8] / (float) tot_rx_mimo) * 100,
  342. mu_stats->mimo[i].occu_mcs[9], ((float) mu_stats->mimo[i].occu_mcs[9] / (float) tot_rx_mimo) * 100,
  343. mu_stats->mimo[i].occu_mcs[10], ((float) mu_stats->mimo[i].occu_mcs[10] / (float) tot_rx_mimo) * 100,
  344. mu_stats->mimo[i].occu_mcs[11], ((float) mu_stats->mimo[i].occu_mcs[11] / (float) tot_rx_mimo) * 100);
  345. printf("[%" PRIu8 "]%said:0x%x, "
  346. "ss0:%" PRIu32 "(%2.2f%%), ss1:%" PRIu32 "(%2.2f%%), ss2:%" PRIu32 "(%2.2f%%), ss3:%" PRIu32 "(%2.2f%%)\n",
  347. i, (mu_stats->aid == mu_stats->mimo[i].aid) ? "#" : " ", mu_stats->mimo[i].aid,
  348. mu_stats->mimo[i].occu_ss[0], ((float) mu_stats->mimo[i].occu_ss[0] / (float) tot_rx_mimo) * 100,
  349. mu_stats->mimo[i].occu_ss[1], ((float) mu_stats->mimo[i].occu_ss[1] / (float) tot_rx_mimo) * 100,
  350. mu_stats->mimo[i].occu_ss[2], ((float) mu_stats->mimo[i].occu_ss[2] / (float) tot_rx_mimo) * 100,
  351. mu_stats->mimo[i].occu_ss[3], ((float) mu_stats->mimo[i].occu_ss[3] / (float) tot_rx_mimo) * 100);
  352. printf("[%" PRIu8 "]%said:0x%x, "
  353. "tot_rx_mimo:%8d, sta/dut:%2.2f%%\n",
  354. i, (mu_stats->aid == mu_stats->mimo[i].aid) ? "#" : " ", mu_stats->mimo[i].aid,
  355. tot_rx_mimo, ((float) tot_rx_mimo / (float) mu_stats->mimo_rx) * 100);
  356. }
  357. }
  358. void print_hw_rx_statistics(void)
  359. {
  360. esp_test_hw_rx_statistics_t hw_rx_stats = { 0, };
  361. esp_test_get_hw_rx_statistics(&hw_rx_stats);
  362. printf(
  363. "WDEVRX_FCS_ERR :%d\n"
  364. "WDEVRX_ABORT :%d\n"
  365. "WDEVRX_ABORT_FCS_PASS :%d\n"
  366. "NRX_ERR_PWRDROP :%d\n"
  367. "NRX_HESIGB_ERR :%d\n"
  368. "WDEVRX_SAMEBM_ERRCNT :%d\n"
  369. "WDEVRX_MPDU :%d\n"
  370. "WDEVRX_END_CNT :%d\n"
  371. "WDEVRX_DATASUC :%d\n"
  372. "WDEVRX_LASTUNMATCH_ERR :%d\n"
  373. "RXHUNG_STATIS :%d\n"
  374. "TXHUNG_STATIS :%d\n"
  375. "RXTXHUNG :%" PRIu32 "\n"
  376. "WDEVRX_CFO :%d\n"
  377. "WDEVRX_SF :%d\n"
  378. "WDEVRX_OTHER_UCAST :%d\n"
  379. "WDEVRX_BUF_FULLCNT :%d\n"
  380. "WDEVRX_FIFO_OVFCNT :%d\n"
  381. "WDEVRX_TKIP_ERRCNT :%d\n"
  382. "WDEVRX_BTBLOCK_ERR :%d\n"
  383. "WDEVRX_FREQHOP_ERR :%d\n"
  384. "WDEVRX_ACK_INT_CNT :%d\n"
  385. "WDEVRX_RTS_INT_CNT :%d\n"
  386. "BRX_ERR_AGC :%d\n"
  387. "BRX_ERR :%d\n"
  388. "NRX_ERR :%d\n"
  389. "NRX_ERR_ABORT :%d\n"
  390. "NRX_ERR_AGCEXIT :%d\n"
  391. "NRX_ERR_BBOFF :%d\n"
  392. "NRX_ERR_FDM_WDG :%d\n"
  393. "NRX_ERR_RESTART :%d\n"
  394. "NRX_ERR_SERV :%d\n"
  395. "NRX_ERR_TXOVER :%d\n"
  396. "NRX_HE_UNSUPPORT :%d\n"
  397. "NRX_HTSIG_ERR :%d\n"
  398. "NRX_HEUNSUPPORT :%d\n"
  399. "NRX_HESIGA_CRC :%d\n",
  400. hw_rx_stats.rx_fcs_err,
  401. hw_rx_stats.rx_abort,
  402. hw_rx_stats.rx_abort_fcs_pass,
  403. hw_rx_stats.nrx_err_pwrdrop,
  404. hw_rx_stats.nrx_hesigb_err,
  405. hw_rx_stats.rx_samebm_errcnt,
  406. hw_rx_stats.rx_mpdu,
  407. hw_rx_stats.rx_end_cnt,
  408. hw_rx_stats.rx_datasuc,
  409. hw_rx_stats.rx_lastunmatch_err,
  410. hw_rx_stats.rxhung_statis,
  411. hw_rx_stats.txhung_statis,
  412. hw_rx_stats.rxtxhung,
  413. hw_rx_stats.rx_cfo_hz,
  414. hw_rx_stats.rx_sf,
  415. hw_rx_stats.rx_other_ucast,
  416. hw_rx_stats.rx_buf_fullcnt,
  417. hw_rx_stats.rx_fifo_ovfcnt,
  418. hw_rx_stats.rx_tkip_errcnt,
  419. hw_rx_stats.rx_btblock_err,
  420. hw_rx_stats.rx_freqhop_err,
  421. hw_rx_stats.rx_ack_int_cnt,
  422. hw_rx_stats.rx_rts_int_cnt,
  423. hw_rx_stats.brx_err_agc,
  424. hw_rx_stats.brx_err,
  425. hw_rx_stats.nrx_err,
  426. hw_rx_stats.nrx_err_abort,
  427. hw_rx_stats.nrx_err_agcexit,
  428. hw_rx_stats.nrx_err_bboff,
  429. hw_rx_stats.nrx_err_fdm_wdg,
  430. hw_rx_stats.nrx_err_restart,
  431. hw_rx_stats.nrx_err_serv,
  432. hw_rx_stats.nrx_err_txover,
  433. hw_rx_stats.nrx_err_unsupport,
  434. hw_rx_stats.nrx_htsig_err,
  435. hw_rx_stats.nrx_heunsupport,
  436. hw_rx_stats.nrx_hesiga_crc
  437. );
  438. }
  439. int wifi_cmd_clr_rx_statistics(int argc, char **argv)
  440. {
  441. ESP_LOGW(TAG, "Clear rx statistics");
  442. esp_wifi_clr_rx_statistics(0);
  443. esp_wifi_clr_rx_statistics(7);
  444. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
  445. esp_test_clr_rx_error_occurs();
  446. esp_wifi_clr_rx_mu_statistics();
  447. #endif
  448. esp_test_clr_hw_statistics();
  449. return 0;
  450. }
  451. void print_rx_mu_statistics(void)
  452. {
  453. /* mu */
  454. esp_wifi_get_rx_mu_statistics(&rx_mu_stats);
  455. /* MIMO */
  456. print_rx_statistics_mimo(&rx_mu_stats);
  457. /* non-MIMO */
  458. print_rx_statistics_nonmimo(&rx_mu_stats);
  459. }
  460. int wifi_cmd_get_rx_statistics(int argc, char **argv)
  461. {
  462. ESP_LOGW(TAG, "Get rx statistics");
  463. esp_test_rx_statistics_t rx_stats = { 0, };
  464. esp_test_rx_error_occurs_t rx_error_occurs = { 0, };
  465. esp_wifi_get_rx_statistics(0, &rx_stats); //tid=0
  466. print_hw_tb_statistics();
  467. ESP_LOGW(TAG, "(0)legacy:%" PRIu32 ", ht(ht:%" PRIu32 ", ht_retry:%" PRIu32 "/%2.2f%%, ht_noeb:%" PRIu32 "/%2.2f%%)",
  468. rx_stats.legacy,
  469. rx_stats.ht, rx_stats.ht_retry,
  470. rx_stats.ht_retry ? ((float) ((float) rx_stats.ht_retry / (float) rx_stats.ht) * 100) : 0,
  471. rx_stats.ht_noeb, rx_stats.ht_noeb ? ((float) ((float) rx_stats.ht_noeb / (float) rx_stats.ht) * 100) : 0);
  472. ESP_LOGW(TAG, "(0)su(su:%" PRIu32 ", su_txbf:%" PRIu32 ", su_stbc:%" PRIu32 ", su_retry:%" PRIu32 "/%2.2f%%, ersu:%" PRIu32 ", ersu_dcm:%" PRIu32 ", su_noeb:%" PRIu32 "/%2.2f%%)",
  473. rx_stats.su,
  474. rx_stats.su_txbf, rx_stats.su_stbc,
  475. rx_stats.su_retry,
  476. rx_stats.su_retry ? ((float) ((float) rx_stats.su_retry / (float) rx_stats.su) * 100) : 0,
  477. rx_stats.ersu,
  478. rx_stats.ersu_dcm,
  479. rx_stats.su_noeb, rx_stats.su_noeb ? ((float) ((float) rx_stats.su_noeb / (float) rx_stats.su) * 100) : 0);
  480. ESP_LOGW(TAG, "(0)mu(mu:%" PRIu32 ", mimo:%" PRIu32 ", non-mimo:%" PRIu32 ", txbf:%" PRIu32 ", stbc:%" PRIu32 ", mu_retry:%" PRIu32 "/%2.2f%%, mu_noeb:%" PRIu32 "/%2.2f%%)",
  481. rx_stats.mu,
  482. rx_stats.mu_mimo,
  483. rx_stats.mu_ofdma, rx_stats.mu_txbf, rx_stats.mu_stbc,
  484. rx_stats.mu_retry,
  485. rx_stats.mu_retry ? ((float) ((float) rx_stats.mu_retry / (float) rx_stats.mu) * 100) : 0,
  486. rx_stats.mu_noeb, rx_stats.mu_noeb ? ((float) ((float) rx_stats.mu_noeb / (float) rx_stats.mu) * 100) : 0);
  487. memset(&rx_stats, 0, sizeof(rx_stats));
  488. esp_wifi_get_rx_statistics(7, &rx_stats); //tid=7
  489. ESP_LOGW(TAG, "(7)legacy:%" PRIu32 ", ht:%" PRIu32 ", su:%" PRIu32 ", su_txbf:%" PRIu32 ", ersu:%" PRIu32 ", mu:%" PRIu32, rx_stats.legacy,
  490. rx_stats.ht, rx_stats.su, rx_stats.su_txbf, rx_stats.ersu, rx_stats.mu);
  491. ESP_LOGW(TAG, "(hw)isr:%" PRIu32 ", nblks:%" PRIu32, rx_stats.rx_isr, rx_stats.rx_nblks);
  492. /* hw rx statistics */
  493. print_hw_rx_statistics();
  494. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
  495. print_rx_mu_statistics();
  496. #endif
  497. esp_test_get_rx_error_occurs(&rx_error_occurs);
  498. ESP_LOGW(TAG, "(rx)tot_errors:%" PRIu32, rx_error_occurs.tot);
  499. int known_errors = 0; //rx error: 0x40-0xff
  500. int i;
  501. for (i = 0; i < 2; i++) {
  502. if (rx_error_occurs.occurs[i]) {
  503. known_errors += rx_error_occurs.occurs[i];
  504. printf("[%3d] 0x%x, %8" PRIu32 ", %2.2f%%\n", i, (i ? 0xf5 : 0xc6), rx_error_occurs.occurs[i], ((float) rx_error_occurs.occurs[i] / (float) rx_error_occurs.tot) * 100);
  505. }
  506. }
  507. if (rx_error_occurs.tot - known_errors) {
  508. printf("[%3d]others, %8" PRIu32 ", %2.2f%%\n\n", i, rx_error_occurs.tot - known_errors, ((float) known_errors / (float) rx_error_occurs.tot) * 100);
  509. }
  510. wifi_cmd_clr_rx_statistics(0, 0);
  511. return 0;
  512. }
  513. #endif /* CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS || CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS */
  514. void register_wifi_stats(void)
  515. {
  516. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
  517. /* get tx statistics */
  518. const esp_console_cmd_t tx_stats_cmd = {
  519. .command = "tx",
  520. .help = "get tx statistics",
  521. .hint = NULL,
  522. .func = &wifi_cmd_get_tx_statistics,
  523. };
  524. ESP_ERROR_CHECK(esp_console_cmd_register(&tx_stats_cmd));
  525. /* clear tx statistics */
  526. const esp_console_cmd_t clr_cmd = {
  527. .command = "clrtx",
  528. .help = "clear tx statistics",
  529. .hint = NULL,
  530. .func = &wifi_cmd_clr_tx_statistics,
  531. };
  532. ESP_ERROR_CHECK(esp_console_cmd_register(&clr_cmd));
  533. #endif
  534. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  535. /* get rx statistics */
  536. const esp_console_cmd_t rx_stats_cmd = {
  537. .command = "rx",
  538. .help = "get rx statistics",
  539. .hint = NULL,
  540. .func = &wifi_cmd_get_rx_statistics,
  541. };
  542. ESP_ERROR_CHECK(esp_console_cmd_register(&rx_stats_cmd));
  543. /* clear rx statistics */
  544. const esp_console_cmd_t clr_rx_cmd = {
  545. .command = "clrrx",
  546. .help = "clear rx statistics",
  547. .hint = NULL,
  548. .func = &wifi_cmd_clr_rx_statistics,
  549. };
  550. ESP_ERROR_CHECK(esp_console_cmd_register(&clr_rx_cmd));
  551. #endif
  552. }