network_manager.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. /*
  2. Copyright (c) 2017-2021 Sebastien L
  3. */
  4. #ifdef NETWORK_MANAGER_LOG_LEVEL
  5. #define LOG_LOCAL_LEVEL NETWORK_MANAGER_LOG_LEVEL
  6. #endif
  7. #include "network_manager.h"
  8. #include "network_ethernet.h"
  9. #include "network_status.h"
  10. #include "network_wifi.h"
  11. #include <stdbool.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include "dns_server.h"
  16. #include "esp_log.h"
  17. #include "esp_system.h"
  18. #include "freertos/FreeRTOS.h"
  19. #include "platform_esp32.h"
  20. #include "esp_netif.h"
  21. #include "freertos/task.h"
  22. #include "cJSON.h"
  23. #include "cmd_system.h"
  24. #include "esp_app_format.h"
  25. #include "esp_event.h"
  26. #include "esp_wifi.h"
  27. #include "esp_wifi_types.h"
  28. #include "lwip/api.h"
  29. #include "lwip/err.h"
  30. #include "lwip/ip4_addr.h"
  31. #include "lwip/netdb.h"
  32. #include "mdns.h"
  33. #include "messaging.h"
  34. #include "tools.h"
  35. #include "trace.h"
  36. #include "Config.h"
  37. #include "accessors.h"
  38. #include "esp_err.h"
  39. #include "http_server_handlers.h"
  40. #include "network_manager.h"
  41. QueueHandle_t network_queue;
  42. BaseType_t network_task_handle;
  43. static const char TAG[] = "network";
  44. static TaskHandle_t task_network_manager = NULL;
  45. RTC_NOINIT_ATTR static bool s_wifi_prioritized;
  46. typedef struct network_callback {
  47. network_status_reached_cb cb;
  48. nm_state_t state;
  49. int sub_state;
  50. const char* from;
  51. SLIST_ENTRY(network_callback)
  52. next; //!< next callback
  53. } network_callback_t;
  54. /** linked list of command structures */
  55. static SLIST_HEAD(cb_list, network_callback) s_cb_list;
  56. network_t NM;
  57. //! Create and initialize the array of state machines.
  58. state_machine_t* const SM[] = {(state_machine_t*)&NM};
  59. static void network_timer_cb(void* timer_id);
  60. int get_root_id(const state_t* state);
  61. const state_t* get_root(const state_t* const state);
  62. static void network_task(void* pvParameters);
  63. void network_start_stop_dhcp_client(esp_netif_t* netif, bool start) {
  64. tcpip_adapter_dhcp_status_t status;
  65. esp_err_t err = ESP_OK;
  66. ESP_LOGD(TAG, "Checking if DHCP client for STA interface is running");
  67. if (!netif) {
  68. ESP_LOGE(TAG, "Invalid adapter. Cannot start/stop dhcp. ");
  69. return;
  70. }
  71. if ((err = esp_netif_dhcpc_get_status(netif, &status)) != ESP_OK) {
  72. ESP_LOGE(TAG, "Error retrieving dhcp status : %s", esp_err_to_name(err));
  73. return;
  74. }
  75. switch (status) {
  76. case ESP_NETIF_DHCP_STARTED:
  77. if (start) {
  78. ESP_LOGD(TAG, "DHCP client already started");
  79. } else {
  80. ESP_LOGI(TAG, "Stopping DHCP client");
  81. err = esp_netif_dhcpc_stop(netif);
  82. if (err != ESP_OK) {
  83. ESP_LOGE(TAG, "Error stopping DHCP Client : %s", esp_err_to_name(err));
  84. }
  85. }
  86. break;
  87. case ESP_NETIF_DHCP_STOPPED:
  88. if (start) {
  89. ESP_LOGI(TAG, "ESP_NETIF_DHCP_STOPPED Starting DHCP client");
  90. err = esp_netif_dhcpc_start(netif);
  91. if (err != ESP_OK) {
  92. ESP_LOGE(TAG, "Error stopping DHCP Client : %s", esp_err_to_name(err));
  93. }
  94. } else {
  95. ESP_LOGI(TAG, "DHCP client already started");
  96. }
  97. break;
  98. case ESP_NETIF_DHCP_INIT:
  99. if (start) {
  100. ESP_LOGI(TAG, "ESP_NETIF_DHCP_INIT: Starting DHCP client");
  101. err = esp_netif_dhcpc_start(netif);
  102. if (err != ESP_OK) {
  103. ESP_LOGE(TAG, "Error stopping DHCP Client : %s", esp_err_to_name(err));
  104. }
  105. } else {
  106. ESP_LOGI(TAG, "Stopping DHCP client");
  107. err = esp_netif_dhcpc_stop(netif);
  108. if (err != ESP_OK) {
  109. ESP_LOGE(TAG, "Error stopping DHCP Client : %s", esp_err_to_name(err));
  110. }
  111. }
  112. break;
  113. default:
  114. ESP_LOGW(TAG, "Unknown DHCP status");
  115. break;
  116. }
  117. }
  118. void network_start_stop_dhcps(esp_netif_t* netif, bool start) {
  119. tcpip_adapter_dhcp_status_t status;
  120. esp_err_t err = ESP_OK;
  121. ESP_LOGD(TAG, "Checking if DHCP server is running");
  122. if (!netif) {
  123. ESP_LOGE(TAG, "Invalid adapter. Cannot start/stop dhcp server. ");
  124. return;
  125. }
  126. if ((err = esp_netif_dhcps_get_status(netif, &status)) != ESP_OK) {
  127. ESP_LOGE(TAG, "Error retrieving dhcp server status : %s", esp_err_to_name(err));
  128. return;
  129. }
  130. switch (status) {
  131. case ESP_NETIF_DHCP_STARTED:
  132. if (start) {
  133. ESP_LOGD(TAG, "DHCP server already started");
  134. } else {
  135. ESP_LOGI(TAG, "Stopping DHCP server");
  136. ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
  137. }
  138. break;
  139. case ESP_NETIF_DHCP_STOPPED:
  140. if (start) {
  141. ESP_LOGI(TAG, "Starting DHCP server");
  142. ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
  143. } else {
  144. ESP_LOGI(TAG, "DHCP server already stopped");
  145. }
  146. break;
  147. case ESP_NETIF_DHCP_INIT:
  148. if (start) {
  149. ESP_LOGI(TAG, "Starting DHCP server");
  150. ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
  151. } else {
  152. ESP_LOGI(TAG, "Stopping DHCP server");
  153. ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
  154. }
  155. break;
  156. default:
  157. ESP_LOGW(TAG, "Unknown DHCP status");
  158. break;
  159. }
  160. }
  161. /*********************************************************************************************
  162. * String conversion routines
  163. */
  164. #define ADD_ROOT(name, ...) CASE_TO_STR(name);
  165. #define ADD_ROOT_LEAF(name, ...) CASE_TO_STR(name);
  166. #define ADD_LEAF(name, ...) CASE_TO_STR(name);
  167. #define ADD_EVENT(name) CASE_TO_STR(name);
  168. #define ADD_FIRST_EVENT(name) CASE_TO_STR(name);
  169. static const char* state_to_string(const state_t* state) {
  170. if (!state) {
  171. return "";
  172. }
  173. switch (state->Parent ? state->Parent->Id : state->Id) {
  174. ALL_NM_STATE
  175. default:
  176. break;
  177. }
  178. return "Unknown";
  179. }
  180. static const char* wifi_state_to_string(mn_wifi_active_state_t state) {
  181. switch (state) {
  182. ALL_WIFI_STATE(, )
  183. default:
  184. break;
  185. }
  186. return "Unknown";
  187. }
  188. static const char* eth_state_to_string(mn_eth_active_state_t state) {
  189. switch (state) {
  190. ALL_ETH_STATE(, )
  191. default:
  192. break;
  193. }
  194. return "Unknown";
  195. }
  196. static const char* wifi_configuring_state_to_string(mn_wifi_configuring_state_t state) {
  197. switch (state) {
  198. ALL_WIFI_CONFIGURING_STATE(, )
  199. default:
  200. break;
  201. }
  202. return "Unknown";
  203. }
  204. static const char* sub_state_to_string(const state_t* state) {
  205. if (!state) {
  206. return "N/A";
  207. }
  208. int root_id = get_root_id(state);
  209. switch (root_id) {
  210. case NETWORK_ETH_ACTIVE_STATE:
  211. return eth_state_to_string(state->Id);
  212. break;
  213. case NETWORK_WIFI_ACTIVE_STATE:
  214. return wifi_state_to_string(state->Id);
  215. case NETWORK_WIFI_CONFIGURING_ACTIVE_STATE:
  216. return wifi_configuring_state_to_string(state->Id);
  217. default:
  218. break;
  219. }
  220. return "*";
  221. }
  222. const char* network_event_to_string(network_event_t state) {
  223. switch (state) {
  224. ALL_NM_EVENTS
  225. default:
  226. break;
  227. }
  228. return "Unknown";
  229. }
  230. #undef ADD_EVENT
  231. #undef ADD_FIRST_EVENT
  232. #undef ADD_ROOT
  233. #undef ADD_ROOT_LEAF
  234. #undef ADD_LEAF
  235. typedef struct {
  236. int parent_state;
  237. int sub_state_last;
  238. } max_sub_states_t;
  239. static const max_sub_states_t state_max[] = {{.parent_state = NETWORK_INSTANTIATED_STATE, .sub_state_last = 0},
  240. {.parent_state = NETWORK_ETH_ACTIVE_STATE, .sub_state_last = TOTAL_ETH_ACTIVE_STATE - 1},
  241. {.parent_state = NETWORK_WIFI_ACTIVE_STATE, .sub_state_last = TOTAL_WIFI_ACTIVE_STATE - 1},
  242. {.parent_state = WIFI_CONFIGURING_STATE, .sub_state_last = TOTAL_WIFI_CONFIGURING_STATE - 1},
  243. {.parent_state = WIFI_CONFIGURING_STATE, .sub_state_last = TOTAL_WIFI_CONFIGURING_STATE - 1}, {.parent_state = -1}};
  244. void check_queue() {
  245. if (!network_queue) {
  246. ESP_LOGD(TAG, " Creating message queue");
  247. network_queue = xQueueCreate(6, sizeof(queue_message));
  248. }
  249. }
  250. void network_initialize_task() {
  251. if (cold_boot) {
  252. ESP_LOGI(TAG, "Setting wifi priotitized flag to false");
  253. s_wifi_prioritized = false;
  254. }
  255. check_queue();
  256. ESP_LOGD(TAG, "Creating network manager task");
  257. network_task_handle = xTaskCreate(&network_task, "network", 4096 * 2, NULL, ESP_TASK_TIMER_PRIO, &task_network_manager);
  258. }
  259. static void event_logger(uint32_t state_machine, uint32_t state, uint32_t event) {
  260. ESP_LOGD(TAG, "Handling network manager event state Id %d->[%s]", state, network_event_to_string(event));
  261. }
  262. static const char* get_state_machine_result_string(state_machine_result_t result) {
  263. switch (result) {
  264. case EVENT_HANDLED:
  265. return "EVENT_HANDLED";
  266. case EVENT_UN_HANDLED:
  267. return "EVENT_UN_HANDLED";
  268. case TRIGGERED_TO_SELF:
  269. return "TRIGGERED_TO_SELF";
  270. }
  271. return "Unknown";
  272. }
  273. static void result_logger(uint32_t state, state_machine_result_t result) {
  274. ESP_LOGD(TAG, "Network Manager Result: %s, New State id: %d", get_state_machine_result_string(result), state);
  275. }
  276. static void network_task(void* pvParameters) {
  277. queue_message msg;
  278. BaseType_t xStatus;
  279. network_initialize_state_machine_globals();
  280. initialize_network_handlers((state_machine_t*)&NM);
  281. // make sure that the start event processes before everything
  282. // else, as some critical initialization happen there.
  283. network_async_front(EN_START);
  284. /* main processing loop */
  285. for (;;) {
  286. xStatus = xQueueReceive(network_queue, &msg, portMAX_DELAY);
  287. if (xStatus == pdPASS) {
  288. // pass the event to the sync processor
  289. NM.event_parameters = &msg;
  290. NM.Machine.Event = msg.trigger;
  291. if (dispatch_event(SM, 1, event_logger, result_logger) == EVENT_UN_HANDLED) {
  292. network_manager_format_from_to_states(
  293. ESP_LOG_ERROR, "Unhandled Event", NULL, NM.Machine.State, msg.trigger, false, "network manager");
  294. }
  295. } /* end of if status=pdPASS */
  296. } /* end of for loop */
  297. vTaskDelete(NULL);
  298. }
  299. int get_max_substate(nm_state_t state) {
  300. for (int i = 0; state_max[i].parent_state != -1; i++) {
  301. if (state_max[i].parent_state == state) {
  302. return state_max[i].sub_state_last;
  303. }
  304. }
  305. return -1;
  306. }
  307. esp_err_t network_register_state_callback(nm_state_t state, int sub_state, const char* from, network_status_reached_cb cb) {
  308. network_callback_t* item = NULL;
  309. if (!cb) {
  310. return ESP_ERR_INVALID_ARG;
  311. }
  312. item = calloc(1, sizeof(*item));
  313. if (item == NULL) {
  314. return ESP_ERR_NO_MEM;
  315. }
  316. if (sub_state != -1 && sub_state > get_max_substate(state)) {
  317. // sub state has to be valid
  318. return ESP_ERR_INVALID_ARG;
  319. }
  320. item->state = state;
  321. item->cb = cb;
  322. item->from = from;
  323. item->sub_state = sub_state;
  324. network_callback_t* last = SLIST_FIRST(&s_cb_list);
  325. if (last == NULL) {
  326. SLIST_INSERT_HEAD(&s_cb_list, item, next);
  327. } else {
  328. network_callback_t* it;
  329. while ((it = SLIST_NEXT(last, next)) != NULL) {
  330. last = it;
  331. }
  332. SLIST_INSERT_AFTER(last, item, next);
  333. }
  334. return ESP_OK;
  335. }
  336. const state_t* get_root(const state_t* const state) {
  337. if (!state) return NULL;
  338. return state->Parent == NULL ? state : get_root(state->Parent);
  339. }
  340. int get_root_id(const state_t* state) {
  341. if (!state) return -1;
  342. return state->Parent == NULL ? state->Id : get_root_id(state->Parent);
  343. }
  344. static bool is_root_state(const state_t* state) { return state->Parent == NULL; }
  345. static bool is_current_state(const state_t* state, nm_state_t state_id, int sub_state_id) {
  346. return get_root(state)->Id == state_id && (sub_state_id == -1 || (!is_root_state(state) && state->Id == sub_state_id));
  347. }
  348. void network_execute_cb(state_machine_t* const state_machine, const char* caller) {
  349. network_callback_t* it;
  350. SLIST_FOREACH(it, &s_cb_list, next) {
  351. if (is_current_state(state_machine->State, it->state, it->sub_state)) {
  352. char* cb_prefix = messaging_alloc_format_string("BEGIN Executing Callback %s", it->from);
  353. NETWORK_DEBUG_STATE_MACHINE(true, STR_OR_BLANK(cb_prefix), state_machine, false, STR_OR_BLANK(caller));
  354. FREE_AND_NULL(cb_prefix);
  355. it->cb((nm_state_t)get_root(state_machine->State)->Id, is_root_state(state_machine->State) ? -1 : state_machine->State->Id);
  356. cb_prefix = messaging_alloc_format_string("END Executing Callback %s", it->from);
  357. NETWORK_DEBUG_STATE_MACHINE(false, STR_OR_BLANK(cb_prefix), state_machine, false, STR_OR_BLANK(caller));
  358. FREE_AND_NULL(cb_prefix);
  359. }
  360. }
  361. }
  362. bool network_is_wifi_prioritized() {
  363. sys_dev_eth_common* common = NULL;
  364. bool result = s_wifi_prioritized;
  365. bool valid_model = SYS_ETH_COMMON(common) && common->model != sys_dev_eth_models_NONE;
  366. if (result) {
  367. result = network_wifi_get_known_count() > 0 || !valid_model;
  368. ESP_LOGD(TAG, "Wifi is prioritized with %d known access points.%s %s", network_wifi_get_known_count(),
  369. valid_model ? " And a valid ethernet adapter" : "", result ? "Wifi prioritized" : "Ethernet prioritized");
  370. }
  371. return result;
  372. }
  373. void network_prioritize_wifi(bool activate) {
  374. if (s_wifi_prioritized == activate) return;
  375. s_wifi_prioritized = activate;
  376. ESP_LOGI(TAG, "Wifi is %sprioritized", activate ? "" : "not ");
  377. }
  378. void network_manager_format_state_machine(
  379. esp_log_level_t level, const char* prefix, state_machine_t* state_machine, bool show_source, const char* caller) {
  380. state_t const* source_state = NULL;
  381. state_t const* current_state = NULL;
  382. network_event_t event = -1;
  383. if (state_machine) {
  384. source_state = ((network_t*)state_machine)->source_state;
  385. current_state = state_machine->State;
  386. event = state_machine->Event;
  387. network_manager_format_from_to_states(level, prefix, source_state, current_state, event, show_source, caller);
  388. } else {
  389. ESP_LOG_LEVEL(level, TAG, "%s - %s -> [%s]", STR_OR_BLANK(caller), prefix, network_event_to_string(event));
  390. }
  391. }
  392. void network_manager_format_from_to_states(esp_log_level_t level, const char* prefix, const state_t* from_state, const state_t* current_state,
  393. network_event_t event, bool show_source, const char* caller) {
  394. const char* source_state = "";
  395. const char* source_sub_state = "";
  396. const char* state = "N/A";
  397. const char* sub_state = "N/A";
  398. if (current_state) {
  399. state = state_to_string(current_state);
  400. sub_state = sub_state_to_string(current_state);
  401. }
  402. if (!from_state) {
  403. source_state = "N/A";
  404. } else {
  405. source_state = state_to_string(from_state);
  406. source_sub_state = sub_state_to_string(from_state);
  407. }
  408. if (show_source) {
  409. ESP_LOG_LEVEL(level, TAG, "%s %s %s(%s)->%s(%s) [%s]", STR_OR_BLANK(caller), prefix, source_state, source_sub_state, state, sub_state,
  410. network_event_to_string(event));
  411. } else {
  412. ESP_LOG_LEVEL(level, TAG, "%s %s %s(%s) [%s]", STR_OR_BLANK(caller), prefix, state, sub_state, network_event_to_string(event));
  413. }
  414. }
  415. #define xSafeQueueSendToBack(xQueue, pvItemToQueue, xTicksToWait) \
  416. check_queue(); \
  417. xQueueSendToBack(xQueue, pvItemToQueue, xTicksToWait);
  418. #define xSafeQueueSendToFront(xQueue, pvItemToQueue, xTicksToWait) \
  419. check_queue(); \
  420. xQueueSendToFront(xQueue, pvItemToQueue, xTicksToWait);
  421. void network_async(network_event_t trigger) {
  422. queue_message msg;
  423. memset(&msg, 0x00, sizeof(msg));
  424. msg.trigger = trigger;
  425. ESP_LOGD(TAG, "Posting event %s directly", network_event_to_string(trigger));
  426. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  427. }
  428. void network_async_got_ip(network_event_t trigger,ip_event_got_ip_t*event_data) {
  429. queue_message msg;
  430. memset(&msg, 0x00, sizeof(msg));
  431. msg.trigger = trigger;
  432. msg.ctx.got_ip_event_data = (ip_event_got_ip_t*)clone_obj_psram(event_data,sizeof(ip_event_got_ip_t));
  433. ESP_LOGD(TAG, "Posting event %s", network_event_to_string(trigger));
  434. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  435. }
  436. void network_async_front(network_event_t trigger) {
  437. queue_message msg;
  438. memset(&msg, 0x00, sizeof(msg));
  439. msg.trigger = trigger;
  440. ESP_LOGD(TAG, "Posting event %s directly to front of the queue", network_event_to_string(trigger));
  441. xSafeQueueSendToFront(network_queue, &msg, portMAX_DELAY);
  442. }
  443. void network_async_commit_protowrapper(void* protoWrapperBase) {
  444. queue_message msg;
  445. memset(&msg, 0, sizeof(msg));
  446. msg.trigger = EN_COMMIT_CHANGES;
  447. msg.ctx.strval = (char*)protoWrapperBase; // Cast to void pointer
  448. ESP_LOGD(TAG, "Posting event %s", network_event_to_string(msg.trigger));
  449. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  450. }
  451. void network_async_fail() { network_async(EN_FAIL); }
  452. void network_async_success() { network_async(EN_SUCCESS); }
  453. void network_async_connected() { network_async(EN_CONNECTED); }
  454. void network_async_link_up() { network_async(EN_LINK_UP); }
  455. void network_async_link_down() { network_async(EN_LINK_DOWN); }
  456. void network_async_configure() { network_async(EN_CONFIGURE); }
  457. void network_async_eth_got_ip() { network_async(EN_ETH_GOT_IP); }
  458. void network_async_timer() { network_async(EN_TIMER); }
  459. void network_async_scan() { network_async(EN_SCAN); }
  460. void network_async_update_status() { network_async(EN_UPDATE_STATUS); }
  461. void network_async_delete() { network_async(EN_DELETE); }
  462. void network_async_scan_done() { network_async(EN_SCAN_DONE); }
  463. void network_async_delete_connection(const char * ssid){
  464. queue_message msg;
  465. memset(&msg, 0x00, sizeof(msg));
  466. msg.trigger = EN_REMOVE;
  467. msg.ctx.credentials.ssid = strdup_psram(ssid);
  468. ESP_LOGD(TAG, "Posting event %s for ssid %s", network_event_to_string(msg.trigger),ssid);
  469. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  470. }
  471. void network_async_connect(const char* ssid, const char* password) {
  472. queue_message msg;
  473. memset(&msg, 0x00, sizeof(msg));
  474. msg.trigger = EN_CONNECT_NEW;
  475. msg.ctx.credentials.ssid = strdup_psram(ssid);
  476. if (password && strlen(password) > 0) {
  477. msg.ctx.credentials.password = strdup_psram(password);
  478. }
  479. ESP_LOGD(TAG, "Posting event %s", network_event_to_string(msg.trigger));
  480. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  481. }
  482. void network_async_add(const char* ssid, const char* password) {
  483. queue_message msg;
  484. memset(&msg, 0x00, sizeof(msg));
  485. msg.trigger = EN_ADD;
  486. msg.ctx.credentials.ssid = strdup_psram(ssid);
  487. msg.ctx.credentials.password = strdup_psram(STR_OR_BLANK(password));
  488. ESP_LOGD(TAG, "Posting event %s", network_event_to_string(msg.trigger));
  489. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  490. }
  491. void network_async_lost_connection(wifi_event_sta_disconnected_t* disconnected_event) {
  492. queue_message msg;
  493. memset(&msg, 0x00, sizeof(msg));
  494. msg.trigger = EN_LOST_CONNECTION;
  495. ESP_LOGD(TAG, "Posting event %s", network_event_to_string(msg.trigger));
  496. msg.ctx.disconnected_event = clone_obj_psram(disconnected_event, sizeof(wifi_event_sta_disconnected_t));
  497. if (msg.ctx.disconnected_event) {
  498. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  499. } else {
  500. ESP_LOGE(TAG, "Unable to post lost connection event.");
  501. }
  502. }
  503. void network_async_reboot(reboot_type_t rtype) {
  504. queue_message msg;
  505. memset(&msg, 0x00, sizeof(msg));
  506. msg.trigger = EN_REBOOT;
  507. msg.ctx.rtype = rtype;
  508. ESP_LOGD(TAG, "Posting event %s - type %d", network_event_to_string(msg.trigger), rtype);
  509. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  510. }
  511. void network_async_callback_withret(void* ctx, network_manager_ret_cb_t cb) {
  512. queue_message msg;
  513. memset(&msg, 0x00, sizeof(msg));
  514. msg.trigger = EN_EXECUTE_CALLBACK;
  515. msg.ctx.cb_ctx.ret_cb = cb;
  516. msg.ctx.cb_ctx.cb = NULL;
  517. msg.ctx.cb_ctx.ctx = ctx;
  518. ESP_LOGD(TAG, "Posting event %s %s", network_event_to_string(msg.trigger), "with return");
  519. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  520. }
  521. void network_async_callback(void* ctx, network_manager_cb_t cb) {
  522. queue_message msg;
  523. memset(&msg, 0x00, sizeof(msg));
  524. msg.trigger = EN_EXECUTE_CALLBACK;
  525. msg.ctx.cb_ctx.cb = cb;
  526. msg.ctx.cb_ctx.ret_cb = NULL;
  527. msg.ctx.cb_ctx.ctx = ctx;
  528. ESP_LOGD(TAG, "Posting event %s %s", network_event_to_string(msg.trigger), "without return");
  529. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  530. }
  531. void network_reboot_ota(char* url) {
  532. queue_message msg;
  533. memset(&msg, 0x00, sizeof(msg));
  534. if (url == NULL) {
  535. msg.trigger = EN_REBOOT;
  536. msg.ctx.rtype = OTA;
  537. ESP_LOGD(TAG, "Posting event %s - type %d", network_event_to_string(msg.trigger), msg.ctx.rtype);
  538. } else {
  539. msg.trigger = EN_REBOOT_URL;
  540. ESP_LOGD(TAG, "Posting event %s - type reboot URL", network_event_to_string(msg.trigger));
  541. msg.ctx.strval = strdup_psram(url);
  542. }
  543. xSafeQueueSendToBack(network_queue, &msg, portMAX_DELAY);
  544. }
  545. network_t* network_get_state_machine() { return &NM; }
  546. static void network_timer_cb(void* timer_id) { network_async_timer(); }
  547. esp_netif_t* network_get_active_interface() {
  548. if (NM.wifi_ap_netif && (network_wifi_is_ap_mode() || network_wifi_is_ap_sta_mode())) {
  549. return NM.wifi_ap_netif;
  550. } else if (NM.wifi_netif && network_wifi_is_sta_mode()) {
  551. return NM.wifi_netif;
  552. }
  553. return NM.eth_netif;
  554. }
  555. bool network_is_interface_connected(esp_netif_t* interface) {
  556. esp_err_t err = ESP_OK;
  557. tcpip_adapter_ip_info_t ipInfo;
  558. if (!interface) {
  559. return false;
  560. }
  561. err = network_get_ip_info_for_netif(interface, &ipInfo);
  562. if (err != ESP_OK) {
  563. ESP_LOGD(TAG, "network_get_ip_info_for_netif returned %s", esp_err_to_name(err));
  564. }
  565. return ((err == ESP_OK) && (ipInfo.ip.addr != IPADDR_ANY));
  566. }
  567. static esp_netif_t* get_connected_interface() {
  568. esp_netif_t* interface = NULL;
  569. for (int i = 0; i < 4; i++) {
  570. switch (i) {
  571. case 0:
  572. // try the active interface
  573. interface = network_get_active_interface();
  574. break;
  575. case 1:
  576. interface = NM.wifi_ap_netif;
  577. break;
  578. case 2:
  579. interface = NM.wifi_netif;
  580. break;
  581. case 3:
  582. interface = NM.eth_netif;
  583. break;
  584. default:
  585. break;
  586. }
  587. if (interface && network_is_interface_connected(interface)) {
  588. ESP_LOGD(TAG, "Found connected interface in iteration #%d", i);
  589. return interface;
  590. }
  591. }
  592. ESP_LOGD(TAG, "No connected interface found");
  593. return NULL;
  594. }
  595. esp_err_t network_get_ip_info_for_netif(esp_netif_t* netif, tcpip_adapter_ip_info_t* ipInfo) {
  596. esp_netif_ip_info_t loc_ip_info;
  597. ESP_LOGD(TAG,"%s Getting IP info","network_get_ip_info_for_netif");
  598. if (!ipInfo) {
  599. ESP_LOGE(TAG, "Invalid pointer for ipInfo");
  600. return ESP_ERR_INVALID_ARG;
  601. }
  602. if (!netif) {
  603. ESP_LOGE(TAG, "Invalid pointer for netif");
  604. return ESP_ERR_INVALID_ARG;
  605. }
  606. ESP_LOGD(TAG,"%s Pointers were valid","network_get_ip_info_for_netif");
  607. memset(ipInfo, 0x00, sizeof(tcpip_adapter_ip_info_t));
  608. esp_err_t err = esp_netif_get_ip_info(netif, &loc_ip_info);
  609. if (err == ESP_OK) {
  610. ESP_LOGD(TAG,"%s Setting ip4 address","network_get_ip_info_for_netif");
  611. ip4_addr_set(&(ipInfo->ip), &loc_ip_info.ip);
  612. ip4_addr_set(&(ipInfo->gw), &loc_ip_info.gw);
  613. ip4_addr_set(&(ipInfo->netmask), &loc_ip_info.netmask);
  614. }
  615. return err;
  616. }
  617. esp_err_t network_get_ip_info(tcpip_adapter_ip_info_t* ipInfo) {
  618. esp_netif_t* netif = get_connected_interface();
  619. if (netif) {
  620. return network_get_ip_info_for_netif(netif, ipInfo);
  621. }
  622. return ESP_FAIL;
  623. }
  624. esp_err_t network_get_hostname(const char** hostname) { return esp_netif_get_hostname(get_connected_interface(), hostname); }
  625. void network_set_timer(uint16_t duration, const char* tag) {
  626. if (duration > 0) {
  627. if (tag) {
  628. ESP_LOGD(TAG, "Setting timer tag to %s", tag);
  629. NM.timer_tag = strdup_psram(tag);
  630. }
  631. if (!NM.state_timer) {
  632. ESP_LOGD(TAG, "Starting %s timer with period of %u ms.", STR_OR_ALT(NM.timer_tag, "anonymous"), duration);
  633. NM.state_timer = xTimerCreate("background STA", pdMS_TO_TICKS(duration), pdFALSE, NULL, network_timer_cb);
  634. } else {
  635. ESP_LOGD(TAG, "Changing %s timer period to %u ms.", STR_OR_ALT(NM.timer_tag, "anonymous"), duration);
  636. xTimerChangePeriod(NM.state_timer, pdMS_TO_TICKS(duration), portMAX_DELAY);
  637. }
  638. xTimerStart(NM.state_timer, portMAX_DELAY);
  639. } else if (NM.state_timer) {
  640. ESP_LOGD(TAG, "Stopping timer %s", STR_OR_ALT(NM.timer_tag, "anonymous"));
  641. xTimerStop(NM.state_timer, portMAX_DELAY);
  642. FREE_AND_NULL(NM.timer_tag);
  643. }
  644. }
  645. void network_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
  646. ip_event_got_ip_t* s = NULL;
  647. if (event_base != IP_EVENT) return;
  648. switch (event_id) {
  649. case IP_EVENT_ETH_GOT_IP:
  650. case IP_EVENT_STA_GOT_IP:
  651. s = (ip_event_got_ip_t*)event_data;
  652. network_async_got_ip(event_id== IP_EVENT_ETH_GOT_IP ? EN_ETH_GOT_IP : EN_GOT_IP,s);
  653. break;
  654. case IP_EVENT_STA_LOST_IP:
  655. ESP_LOGD(TAG, "IP_EVENT_STA_LOST_IP");
  656. break;
  657. case IP_EVENT_AP_STAIPASSIGNED:
  658. ESP_LOGD(TAG, "IP_EVENT_AP_STAIPASSIGNED");
  659. break;
  660. case IP_EVENT_GOT_IP6:
  661. ESP_LOGD(TAG, "IP_EVENT_GOT_IP6");
  662. break;
  663. default:
  664. break;
  665. }
  666. }
  667. void network_set_hostname(esp_netif_t* interface) {
  668. esp_err_t err;
  669. ESP_LOGD(TAG, "network_set_hostname. Retrieving host name from config structure");
  670. char* temp = NULL;
  671. if (!platform || !platform->has_names || strlen(platform->names.device) == 0) {
  672. temp = alloc_get_fallback_unique_name();
  673. ESP_LOGE(TAG, "Device name not set. Falling back to %s", temp);
  674. }
  675. ESP_LOGD(TAG, "Setting host name to : %s", temp ? temp : platform->names.device);
  676. if ((err = esp_netif_set_hostname(interface, temp ? temp : platform->names.device)) != ESP_OK) {
  677. ESP_LOGE(TAG, "Unable to set host name. Error: %s", esp_err_to_name(err));
  678. }
  679. if (temp) free(temp);
  680. }