wifi_twt.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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. #include "freertos/FreeRTOS.h"
  10. #include "freertos/event_groups.h"
  11. #if CONFIG_SOC_WIFI_HE_SUPPORT
  12. #include "esp_console.h"
  13. #include "argtable3/argtable3.h"
  14. #include "esp_netif.h"
  15. #include "esp_event.h"
  16. #include "esp_wifi.h"
  17. #include "esp_wifi_he.h"
  18. /*******************************************************
  19. * Constants
  20. *******************************************************/
  21. static const char *TAG = "twt";
  22. /*******************************************************
  23. * Structures
  24. *******************************************************/
  25. typedef struct {
  26. struct arg_int *setup;
  27. struct arg_int *teardown;
  28. struct arg_int *suspend;
  29. struct arg_int *trigger; //1-trigger-enabled, 0-non-trigger-enabled, setup
  30. struct arg_int *flowtype; //1-unannounced, 0-announced, setup
  31. struct arg_int *negtype;
  32. struct arg_int *wakeinvlexp; //setup
  33. struct arg_int *wakeduraunit; //1-TU, 0-256us
  34. struct arg_int *wakeinvlman; //setup
  35. struct arg_int *minwakedur; //setup
  36. struct arg_int *flowid;
  37. struct arg_int *twtid;
  38. struct arg_int *setup_timeout_time_ms;
  39. struct arg_int *suspend_time_ms;
  40. struct arg_int *all_twt;
  41. struct arg_end *end;
  42. } wifi_itwt_args_t;
  43. typedef struct {
  44. struct arg_int *timeout;
  45. struct arg_end *end;
  46. } wifi_itwt_send_probereq_t;
  47. /*******************************************************
  48. * Variable Definitions
  49. *******************************************************/
  50. static wifi_itwt_args_t itwt_args;
  51. static wifi_itwt_send_probereq_t itwt_probe_args;
  52. /*******************************************************
  53. * Function Declarations
  54. *******************************************************/
  55. /*******************************************************
  56. * Function Definitions
  57. *******************************************************/
  58. static int wifi_cmd_itwt(int argc, char **argv)
  59. {
  60. int nerrors = arg_parse(argc, argv, (void **) &itwt_args);
  61. if (nerrors != 0) {
  62. arg_print_errors(stderr, itwt_args.end, argv[0]);
  63. return 1;
  64. }
  65. esp_err_t err = ESP_OK;
  66. if (itwt_args.setup->count) {
  67. if (itwt_args.wakeinvlman->count) {
  68. if (itwt_args.wakeinvlman->ival[0] < 0 || itwt_args.wakeinvlman->ival[0] > 65535) {
  69. ESP_LOGE(TAG, "(itwt)expect [0, 65535], wake_invl_mant: %d", itwt_args.wakeinvlman->ival[0]);
  70. return 1;
  71. }
  72. }
  73. if (itwt_args.wakeinvlexp->count) {
  74. if (itwt_args.wakeinvlexp->ival[0] < 0 || itwt_args.wakeinvlexp->ival[0] > 31) {
  75. ESP_LOGE(TAG, "(itwt)expect [0, 31], wake_invl_expn: %d", itwt_args.wakeinvlexp->ival[0]);
  76. return 1;
  77. }
  78. }
  79. if (itwt_args.minwakedur->count) {
  80. if (itwt_args.minwakedur->ival[0] < 0 || itwt_args.minwakedur->ival[0] > 255) {
  81. ESP_LOGE(TAG, "(itwt)expect [0, 255], min_wake_dura: %d", itwt_args.minwakedur->ival[0]);
  82. return 1;
  83. }
  84. }
  85. if (itwt_args.wakeduraunit->count) {
  86. if (itwt_args.wakeduraunit->ival[0] < 0 || itwt_args.wakeduraunit->ival[0] > 1) {
  87. ESP_LOGE(TAG, "(itwt)expect [0, 1], wake duration unit: %d", itwt_args.wakeduraunit->ival[0]);
  88. return 1;
  89. }
  90. }
  91. if (itwt_args.twtid->count) {
  92. if (itwt_args.twtid->ival[0] < 0 || itwt_args.twtid->ival[0] > 32767) {
  93. ESP_LOGE(TAG, "(itwt)expect [0, 32767], twt id: %d", itwt_args.twtid->ival[0]);
  94. return 1;
  95. }
  96. }
  97. if (itwt_args.setup_timeout_time_ms->count) {
  98. if (itwt_args.setup_timeout_time_ms->ival[0] < 0 || itwt_args.setup_timeout_time_ms->ival[0] > 65535) {
  99. ESP_LOGE(TAG, "(itwt)expect [0, 65535], setup timeout time: %d", itwt_args.setup_timeout_time_ms->ival[0]);
  100. return 1;
  101. }
  102. }
  103. wifi_twt_setup_config_t setup_config = {
  104. .setup_cmd = (itwt_args.setup->ival[0] <= TWT_DEMAND) ? itwt_args.setup->ival[0] : TWT_REQUEST,
  105. .flow_id = 0,
  106. .twt_id = itwt_args.twtid->count ? itwt_args.twtid->ival[0] : 0,
  107. .flow_type = itwt_args.flowtype->count ? ((itwt_args.flowtype->ival[0] == 0) ? 0 : 1) : 0,
  108. .min_wake_dura = itwt_args.minwakedur->count ? itwt_args.minwakedur->ival[0] : 255,
  109. .wake_duration_unit = itwt_args.wakeduraunit->count ? itwt_args.wakeduraunit->ival[0] : 0,
  110. .wake_invl_expn = itwt_args.wakeinvlexp->count ? itwt_args.wakeinvlexp->ival[0] : 10,
  111. .wake_invl_mant = itwt_args.wakeinvlman->count ? itwt_args.wakeinvlman->ival[0] : 512,
  112. .trigger = itwt_args.trigger->count ? (itwt_args.trigger->ival[0] ? 1 : 0) : 1,
  113. .timeout_time_ms = itwt_args.setup_timeout_time_ms->count ? itwt_args.setup_timeout_time_ms->ival[0] : 5000,
  114. };
  115. err = esp_wifi_sta_itwt_setup(&setup_config);
  116. ESP_LOGI(TAG, "(itwt)setup, trigger:%d, %s, flow_id:%d, err:0x%x",
  117. setup_config.trigger, setup_config.flow_type ? "unannounce" : "announced", setup_config.flow_id, err);
  118. }
  119. if (itwt_args.teardown->count) {
  120. // teardown a given flow id, all_twt has a high priority
  121. int flow_id = itwt_args.flowid->count ? itwt_args.flowid->ival[0] : (-1);
  122. bool all_twt = itwt_args.all_twt->count ? ((itwt_args.all_twt->ival[0] == 1) ? true : false) : false;
  123. flow_id = (all_twt == true) ? FLOW_ID_ALL : flow_id;
  124. if (flow_id >= 0) {
  125. err = esp_wifi_sta_itwt_teardown(flow_id);
  126. ESP_LOGI(TAG, "(itwt)teardown, flow_id:%d, all_twt:%d, err:0x%x", flow_id, all_twt, err);
  127. } else {
  128. ESP_LOGE(TAG, "(itwt)teardown, should specify an existing flow id");
  129. }
  130. }
  131. if (itwt_args.suspend->count) {
  132. // suspend a given flow id
  133. int flow_id = itwt_args.flowid->count ? itwt_args.flowid->ival[0] : (-1);
  134. bool all_twt = itwt_args.all_twt->count ? (itwt_args.all_twt->ival[0] ? true : false) : false;
  135. flow_id = (all_twt == true) ? FLOW_ID_ALL : flow_id;
  136. int suspend_time_ms = itwt_args.suspend_time_ms->count ? itwt_args.suspend_time_ms->ival[0] : 0;
  137. if (flow_id > 0) {
  138. err = esp_wifi_sta_itwt_suspend(flow_id, suspend_time_ms);
  139. ESP_LOGI(TAG, "(itwt)suspend, flow_id:%d, all_twt:%d, suspend:%d ms, err:0x%x", flow_id, all_twt, suspend_time_ms, err);
  140. } else {
  141. ESP_LOGE(TAG, "(itwt)suspend, should specify an existing flow id");
  142. }
  143. }
  144. return 0;
  145. }
  146. static int wifi_cmd_itwt_probe(int argc, char **argv)
  147. {
  148. int nerrors = arg_parse(argc, argv, (void **) &itwt_probe_args);
  149. if (nerrors != 0) {
  150. arg_print_errors(stderr, itwt_probe_args.end, argv[0]);
  151. return 1;
  152. }
  153. esp_err_t err = ESP_OK;
  154. if (itwt_probe_args.timeout->count) {
  155. if (itwt_probe_args.timeout->ival[0] > 0) {
  156. ESP_LOGI(TAG, "(itwt)send probe req, timeout:%d ms", itwt_probe_args.timeout->ival[0]);
  157. err = esp_wifi_sta_itwt_send_probe_req(itwt_probe_args.timeout->ival[0]);
  158. } else {
  159. ESP_LOGE(TAG, "(itwt)invalid input, timeout:%d ms", itwt_probe_args.timeout->ival[0]);
  160. }
  161. }
  162. ESP_LOGI(TAG, "err:0x%x", err);
  163. return err;
  164. }
  165. void register_wifi_itwt(void)
  166. {
  167. /* itwt setup/teardown */
  168. itwt_args.setup = arg_int0(NULL, "setup", "<setup>", "twt setup/teardown an individual flow id");
  169. itwt_args.teardown = arg_int0(NULL, "teardown", "<setup>", "twt setup/teardown an individual flow id");
  170. itwt_args.suspend = arg_int0(NULL, "suspend", "<setup>", "twt setup/teardown an individual flow id");
  171. itwt_args.trigger = arg_int0("t", NULL, "<trigger>", "trigger");
  172. itwt_args.flowtype = arg_int0("f", NULL, "<flow_type>", "flow type: 0-announced, 1-unannounced");
  173. itwt_args.negtype = arg_int0("n", NULL, "<neg_type>", "negotiate type");
  174. itwt_args.minwakedur = arg_int0("d", NULL, "<minwakedur>", "Norminal Min. Wake Duration");
  175. itwt_args.wakeduraunit = arg_int0("u", NULL, "<wakeduraunit>", "wake duration unit 0-256us, 1-TU (TU = 1024us)");
  176. itwt_args.wakeinvlexp = arg_int0("e", NULL, "<wakeinvlexp>", "Wake Interval Exponent");
  177. itwt_args.wakeinvlman = arg_int0("m", NULL, "<wakeinvlman>", "Wake Interval Mantissa");
  178. itwt_args.flowid = arg_int0("i", NULL, "<flow_id>", "Flow ID");
  179. itwt_args.suspend_time_ms = arg_int0("s", NULL, "<suspend_time_ms>", "time of suspending iTWT agreements, unit ms");
  180. itwt_args.twtid = arg_int0("w", NULL, "<twt_id>", "TWT ID");
  181. itwt_args.setup_timeout_time_ms = arg_int0("u", NULL, "<setup_timeout_time_ms>", "iTWT setup timeout time, unit ms");
  182. itwt_args.all_twt = arg_int0("a", NULL, "<all_twt>", "All TWT");
  183. itwt_args.end = arg_end(1);
  184. const esp_console_cmd_t itwt_cmd = {
  185. .command = "itwt",
  186. .help = "itwt setup, teardown or suspend",
  187. .hint = NULL,
  188. .func = &wifi_cmd_itwt,
  189. .argtable = &itwt_args
  190. };
  191. ESP_ERROR_CHECK(esp_console_cmd_register(&itwt_cmd));
  192. /* itwt probe */
  193. itwt_probe_args.timeout = arg_int0("t", NULL, "[timeout]", "time of sending a probe request frame and receiving a probe response frame from ap, unit ms");
  194. itwt_probe_args.end = arg_end(1);
  195. const esp_console_cmd_t itwt_probe_cmd = {
  196. .command = "probe",
  197. .help = "send probe request for TSF update when at lease one itwt agreement setup",
  198. .hint = NULL,
  199. .func = &wifi_cmd_itwt_probe,
  200. .argtable = &itwt_probe_args
  201. };
  202. ESP_ERROR_CHECK(esp_console_cmd_register(&itwt_probe_cmd));
  203. }
  204. #else
  205. void register_wifi_itwt(void)
  206. {
  207. ;
  208. }
  209. #endif /* CONFIG_SOC_WIFI_HE_SUPPORT */