network_manager.c 25 KB

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