Network manager implemented and relatively stable

This commit is contained in:
Sebastien L
2021-12-10 13:07:27 -05:00
parent 81756a7649
commit 63fbc2f645
66 changed files with 4528 additions and 2679 deletions

View File

@@ -1,9 +1,9 @@
set( WEBPACK_DIR webapp/webpack/dist )
idf_component_register( SRC_DIRS . webapp
INCLUDE_DIRS . webapp ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32 ${IDF_PATH}/components/esp_http_server/src/util ${IDF_PATH}/components/esp_http_server/src/
idf_component_register( SRC_DIRS . webapp UML-State-Machine-in-C/src
INCLUDE_DIRS . webapp UML-State-Machine-in-C/src ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32 ${IDF_PATH}/components/esp_http_server/src/util ${IDF_PATH}/components/esp_http_server/src/
REQUIRES squeezelite-ota json mdns
PRIV_REQUIRES tools cpp-stateless services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt
PRIV_REQUIRES tools services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt
)

View File

@@ -1,41 +0,0 @@
# What is esp32-wifi-manager?
*esp32-wifi-manager* is an esp32 program that enables easy management of wifi networks through a web application.
*esp32-wifi-manager* is **lightweight** (8KB of task stack in total) and barely uses any CPU power through a completely event driven architecture. It's an all in one wifi scanner, http server & dns daemon living in the least amount of RAM possible.
For real time constrained applications, *esp32-wifi-manager* can live entirely on PRO CPU, leaving the entire APP CPU untouched for your own needs.
*esp32-wifi-manager* will automatically attempt to re-connect to a previously saved network on boot, and it will start its own wifi access point through which you can manage wifi networks if a saved network cannot be found and/or if the connection is lost.
*esp32-wifi-manager* is an esp-idf project that compiles successfully with the esp-idf 3.2 release. You can simply copy the project and start adding your own code to it.
# Demo
[![esp32-wifi-manager demo](http://img.youtube.com/vi/hxlZi15bym4/0.jpg)](http://www.youtube.com/watch?v=hxlZi15bym4)
# Look and Feel
![esp32-wifi-manager on an mobile device](https://idyl.io/wp-content/uploads/2017/11/esp32-wifi-manager-password.png "esp32-wifi-manager") ![esp32-wifi-manager on an mobile device](https://idyl.io/wp-content/uploads/2017/11/esp32-wifi-manager-connected-to.png "esp32-wifi-manager")
# Adding esp32-wifi-manager to your code
Ther are effectively three different ways you can embed esp32-wifi-manager with your code:
* Just forget about it and poll in your code for wifi connectivity status
* Use event callbacks
* Modify esp32-wifi-manager code directly to fit your needs
**Event callbacks** are the cleanest way to use the wifi manager and that's the recommended way to do it. A typical use-case would be to get notified when wifi manager finally gets a connection an access point. In order to do this you can simply define a callback function:
```c
void cb_connection_ok(void *pvParameter){
ESP_LOGI(TAG, "I have a connection!");
}
```
Then just register it by calling:
```c
wifi_manager_set_callback(EVENT_STA_GOT_IP, &cb_connection_ok);
```
That's it! Now everytime the event is triggered it will call this function.
# License
*esp32-wifi-manager* is MIT licensed. As such, it can be included in any project, commercial or not, as long as you retain original copyright. Please make sure to read the license file.

Submodule components/wifi-manager/UML-State-Machine-in-C added at 96264241ad

View File

@@ -24,6 +24,7 @@
#include <_esp_http_server.h>
#include "esp_httpd_priv.h"
#include "ctrl_sock.h"
#include "globdefs.h"
static const char *TAG = "_httpd";
@@ -269,18 +270,18 @@ static void _httpd_thread(void *arg)
static struct httpd_data *__httpd_create(const httpd_config_t *config)
{
/* Allocate memory for httpd instance data */
struct httpd_data *hd = calloc(1, sizeof(struct httpd_data));
struct httpd_data *hd = malloc_init_external(sizeof(struct httpd_data));
if (!hd) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance"));
return NULL;
}
hd->hd_calls = calloc(config->max_uri_handlers, sizeof(httpd_uri_t *));
hd->hd_calls = malloc_init_external(config->max_uri_handlers* sizeof(httpd_uri_t *));
if (!hd->hd_calls) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers"));
free(hd);
return NULL;
}
hd->hd_sd = calloc(config->max_open_sockets, sizeof(struct sock_db));
hd->hd_sd = malloc_init_external(config->max_open_sockets* sizeof(struct sock_db));
if (!hd->hd_sd) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data"));
free(hd->hd_calls);
@@ -288,7 +289,7 @@ static struct httpd_data *__httpd_create(const httpd_config_t *config)
return NULL;
}
struct httpd_req_aux *ra = &hd->hd_req_aux;
ra->resp_hdrs = calloc(config->max_resp_headers, sizeof(struct resp_hdr));
ra->resp_hdrs = malloc_init_external(config->max_resp_headers* sizeof(struct resp_hdr));
if (!ra->resp_hdrs) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers"));
free(hd->hd_sd);
@@ -296,7 +297,7 @@ static struct httpd_data *__httpd_create(const httpd_config_t *config)
free(hd);
return NULL;
}
hd->err_handler_fns = calloc(HTTPD_ERR_CODE_MAX, sizeof(httpd_err_handler_func_t));
hd->err_handler_fns = malloc_init_external(HTTPD_ERR_CODE_MAX* sizeof(httpd_err_handler_func_t));
if (!hd->err_handler_fns) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers"));
free(ra->resp_hdrs);

View File

@@ -59,8 +59,8 @@ static const char TAG[] = "dns_server";
static TaskHandle_t task_dns_server = NULL;
int socket_fd;
void dns_server_start() {
xTaskCreate(&dns_server, "dns_server", 3072, NULL, WIFI_MANAGER_TASK_PRIORITY-1, &task_dns_server);
void dns_server_start(esp_netif_t * netif) {
xTaskCreate(&dns_server, "dns_server", 3072, (void *)netif, WIFI_MANAGER_TASK_PRIORITY-1, &task_dns_server);
}
void dns_server_stop(){
@@ -75,7 +75,8 @@ void dns_server_stop(){
void dns_server(void *pvParameters) {
struct sockaddr_in sa, ra;
esp_err_t esp_err = ESP_OK;
esp_netif_t * netif = (esp_netif_t * )pvParameters;
/* Set redirection DNS hijack to the access point IP */
ip4_addr_t ip_resolved;
inet_pton(AF_INET, DEFAULT_AP_IP, &ip_resolved);
@@ -90,10 +91,14 @@ void dns_server(void *pvParameters) {
memset(&sa, 0, sizeof(struct sockaddr_in));
/* Bind to port 53 (typical DNS Server port) */
tcpip_adapter_ip_info_t ip;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
esp_netif_ip_info_t ip_info;
esp_err = esp_netif_get_ip_info(netif,&ip_info);
if(esp_err!=ESP_OK) {
ESP_LOGE(TAG, "Failed to get adapter info for udp: %s", esp_err_to_name(esp_err));
exit(1);
}
ra.sin_family = AF_INET;
ra.sin_addr.s_addr = ip.ip.addr;
ra.sin_addr.s_addr = ip_info.ip.addr;
ra.sin_port = htons(53);
if (bind(socket_fd, (struct sockaddr *)&ra, sizeof(struct sockaddr_in)) == -1) {
ESP_LOGE(TAG, "Failed to bind to 53/udp");
@@ -149,7 +154,7 @@ void dns_server(void *pvParameters) {
for(char* c=domain; *c != '\0'; c++){
if(*c < ' ' || *c > 'z') *c = '.'; /* technically we should test if the first two bits are 00 (e.g. if( (*c & 0xC0) == 0x00) *c = '.') but this makes the code a lot more readable */
}
ESP_LOGI(TAG, "Replying to DNS request for %s from %s", domain, ip_address);
ESP_LOGD(TAG, "Replying to DNS request for %s from %s", domain, ip_address);
/* create DNS answer at the end of the query*/

View File

@@ -35,6 +35,7 @@ Contains the freeRTOS task for the DNS server that processes the requests.
#include <esp_system.h>
#include <stdbool.h>
#include "squeezelite-ota.h"
#include "esp_netif.h"
#ifdef __cplusplus
@@ -128,7 +129,7 @@ typedef struct __attribute__((__packed__)) dns_answer_t{
}dns_answer_t;
void dns_server(void *pvParameters);
void dns_server_start();
void dns_server_start(esp_netif_t * netif);
void dns_server_stop();

View File

@@ -1,34 +1,5 @@
/*
Copyright (c) 2017-2019 Tony Pottier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file http_server.c
@author Tony Pottier
@brief Defines all functions necessary for the HTTP server to run.
Contains the freeRTOS task for the HTTP listener and all necessary support
function to process requests, decode URLs, serve files, etc. etc.
@note http_server task cannot run without the wifi_manager task!
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
Copyright (c) 2017-2021 Sebastien L
*/
#include "http_server_handlers.h"
@@ -57,7 +28,8 @@ function to process requests, decode URLs, serve files, etc. etc.
#include "webapp/webpack.h"
#include "network_wifi.h"
#include "network_status.h"
#include "globdefs.h"
#define HTTP_STACK_SIZE (5*1024)
const char str_na[]="N/A";
#define STR_OR_NA(s) s?s:str_na
@@ -104,7 +76,7 @@ char * alloc_get_http_header(httpd_req_t * req, const char * key){
* extra byte for null termination */
buf_len = httpd_req_get_hdr_value_len(req, key) + 1;
if (buf_len > 1) {
buf = malloc(buf_len);
buf = malloc_init_external(buf_len);
/* Copy null terminated value string into buffer */
if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
ESP_LOGD_LOC(TAG, "Found header => %s: %s",key, buf);
@@ -120,16 +92,14 @@ char * http_alloc_get_socket_address(httpd_req_t *req, u8_t local, in_port_t * p
union sockaddr_aligned addr;
len = sizeof(addr);
ip_addr_t * ip_addr=NULL;
char * ipstr = malloc(INET6_ADDRSTRLEN);
memset(ipstr,0x0,INET6_ADDRSTRLEN);
char * ipstr = malloc_init_external(INET6_ADDRSTRLEN);
typedef int (*getaddrname_fn_t)(int s, struct sockaddr *name, socklen_t *namelen);
getaddrname_fn_t get_addr = NULL;
int s = httpd_req_to_sockfd(req);
if(s == -1) {
free(ipstr);
return strdup("httpd_req_to_sockfd error");
return strdup_psram("httpd_req_to_sockfd error");
}
ESP_LOGV_LOC(TAG,"httpd socket descriptor: %u", s);
@@ -192,7 +162,7 @@ bool is_captive_portal_host_name(httpd_req_t *req){
ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name);
}
ap_ip_address = malloc(IP4ADDR_STRLEN_MAX);
ap_ip_address = malloc_init_external(IP4ADDR_STRLEN_MAX);
memset(ap_ip_address, 0x00, IP4ADDR_STRLEN_MAX);
if(ap_ip_address){
ESP_LOGD_LOC(TAG, "Converting soft ip address to string");
@@ -233,8 +203,7 @@ session_context_t* get_session_context(httpd_req_t *req){
bool newConnection=false;
if (! req->sess_ctx) {
ESP_LOGD(TAG,"New connection context. Allocating session buffer");
req->sess_ctx = malloc(sizeof(session_context_t));
memset(req->sess_ctx,0x00,sizeof(session_context_t));
req->sess_ctx = malloc_init_external(sizeof(session_context_t));
req->free_ctx = free_ctx_func;
newConnection = true;
// get the remote IP address only once per session
@@ -256,11 +225,13 @@ bool is_user_authenticated(httpd_req_t *req){
return true;
}
ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
ESP_LOGD(TAG, "Heap internal:%zu (min:%zu) external:%zu (min:%zu) dma:%zu (min:%zu)",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM),
heap_caps_get_free_size(MALLOC_CAP_DMA),
heap_caps_get_minimum_free_size(MALLOC_CAP_DMA));
// todo: ask for user to authenticate
return false;
@@ -439,7 +410,7 @@ esp_err_t ap_scan_handler(httpd_req_t *req){
// todo: redirect to login page
// return ESP_OK;
}
network_manager_async_scan();
network_async_scan();
esp_err_t err = set_content_type_from_req(req);
if(err == ESP_OK){
httpd_resp_send(req, (const char *)empty, HTTPD_RESP_USE_STRLEN);
@@ -529,9 +500,9 @@ esp_err_t ap_get_handler(httpd_req_t *req){
}
/* if we can get the mutex, write the last version of the AP list */
esp_err_t err = set_content_type_from_req(req);
if( err == ESP_OK && wifi_manager_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)){
char *buff = wifi_manager_alloc_get_ap_list_json();
wifi_manager_unlock_json_buffer();
if( err == ESP_OK && network_status_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)){
char *buff = network_status_alloc_get_ap_list_json();
network_status_unlock_json_buffer();
if(buff!=NULL){
httpd_resp_send(req, (const char *)buff, HTTPD_RESP_USE_STRLEN);
free(buff);
@@ -683,7 +654,7 @@ esp_err_t config_post_handler(httpd_req_t *req){
else {
// we're getting a request to do an OTA from that URL
ESP_LOGW_LOC(TAG, "Found OTA request!");
otaURL=strdup(val);
otaURL=strdup_psram(val);
bOTA=true;
}
}
@@ -730,7 +701,7 @@ esp_err_t config_post_handler(httpd_req_t *req){
ESP_LOGW_LOC(TAG, "Restarting system to process OTA for url %s",otaURL);
}
network_manager_reboot_ota(otaURL);
network_reboot_ota(otaURL);
free(otaURL);
}
return err;
@@ -766,15 +737,15 @@ esp_err_t connect_post_handler(httpd_req_t *req){
cJSON * ssid_object = cJSON_GetObjectItem(root, "ssid");
if(ssid_object !=NULL){
ssid = strdup(ssid_object->valuestring);
ssid = strdup_psram(ssid_object->valuestring);
}
cJSON * password_object = cJSON_GetObjectItem(root, "pwd");
if(password_object !=NULL){
password = strdup(password_object->valuestring);
password = strdup_psram(password_object->valuestring);
}
cJSON * host_name_object = cJSON_GetObjectItem(root, "host_name");
if(host_name_object !=NULL){
host_name = strdup(host_name_object->valuestring);
host_name = strdup_psram(host_name_object->valuestring);
}
cJSON_Delete(root);
@@ -785,14 +756,7 @@ esp_err_t connect_post_handler(httpd_req_t *req){
}
if(ssid !=NULL && strlen(ssid) <= MAX_SSID_SIZE && strlen(password) <= MAX_PASSWORD_SIZE ){
wifi_config_t* config = wifi_manager_get_wifi_sta_config();
memset(config, 0x00, sizeof(wifi_config_t));
strlcpy((char *)config->sta.ssid, ssid, sizeof(config->sta.ssid)+1);
if(password){
strlcpy((char *)config->sta.password, password, sizeof(config->sta.password)+1);
}
ESP_LOGD_LOC(TAG, "http_server_netconn_serve: network_manager_async_scan() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password);
network_manager_async_scan();
network_async_connect(ssid, password);
httpd_resp_send(req, (const char *)success, strlen(success));
}
else {
@@ -816,7 +780,7 @@ esp_err_t connect_delete_handler(httpd_req_t *req){
return err;
}
httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_disconnect();
network_async_delete();
return ESP_OK;
}
@@ -833,7 +797,7 @@ esp_err_t reboot_ota_post_handler(httpd_req_t *req){
}
httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_reboot(OTA);
network_async_reboot(OTA);
return ESP_OK;
}
esp_err_t reboot_post_handler(httpd_req_t *req){
@@ -848,7 +812,7 @@ esp_err_t reboot_post_handler(httpd_req_t *req){
return err;
}
httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_reboot(RESTART);
network_async_reboot(RESTART);
return ESP_OK;
}
esp_err_t recovery_post_handler(httpd_req_t *req){
@@ -863,7 +827,7 @@ esp_err_t recovery_post_handler(httpd_req_t *req){
return err;
}
httpd_resp_send(req, (const char *)success, strlen(success));
network_manager_async_reboot(RECOVERY);
network_async_reboot(RECOVERY);
return ESP_OK;
}
@@ -881,7 +845,7 @@ esp_err_t flash_post_handler(httpd_req_t *req){
if(err != ESP_OK){
return err;
}
char * binary_buffer = malloc(req->content_len);
char * binary_buffer = malloc_init_external(req->content_len);
if(binary_buffer == NULL){
ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
/* Respond with 400 Bad Request */
@@ -981,11 +945,11 @@ esp_err_t process_redirect(httpd_req_t *req, const char * status){
remote_ip = http_alloc_get_socket_address(req,0, &port);
size_t buf_size = strlen(redirect_payload1) +strlen(redirect_payload2) + strlen(redirect_payload3) +2*(strlen(location_prefix)+strlen(ap_ip_address))+1;
char * redirect=malloc(buf_size);
char * redirect=malloc_init_external(buf_size);
if(strcasestr(status,"302")){
size_t url_buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1;
redirect_url = malloc(url_buf_size);
redirect_url = malloc_init_external(url_buf_size);
memset(redirect_url,0x00,url_buf_size);
snprintf(redirect_url, buf_size,"%s%s/",location_prefix, ap_ip_address);
ESP_LOGW_LOC(TAG, "Redirecting host [%s] to %s (from uri %s)",remote_ip, redirect_url,req->uri);
@@ -1034,9 +998,9 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){
remote_ip = http_alloc_get_socket_address(req,0, &port);
ESP_LOGW_LOC(TAG, "%s requested invalid URL: [%s]",remote_ip, req->uri);
if(wifi_manager_lock_sta_ip_string(portMAX_DELAY)){
sta_ip_address = strdup(wifi_manager_get_sta_ip_string());
wifi_manager_unlock_sta_ip_string();
if(network_status_lock_sta_ip_string(portMAX_DELAY)){
sta_ip_address = strdup_psram(network_status_get_sta_ip_string());
network_status_unlock_sta_ip_string();
}
else {
ESP_LOGE(TAG,"Unable to obtain local IP address from WiFi Manager.");
@@ -1149,9 +1113,9 @@ esp_err_t status_get_handler(httpd_req_t *req){
return err;
}
if(wifi_manager_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)) {
char *buff = wifi_manager_alloc_get_ip_info_json();
wifi_manager_unlock_json_buffer();
if(network_status_lock_json_buffer(( TickType_t ) 200/portTICK_PERIOD_MS)) {
char *buff = network_status_alloc_get_ip_info_json();
network_status_unlock_json_buffer();
if(buff) {
httpd_resp_send(req, (const char *)buff, strlen(buff));
free(buff);
@@ -1164,7 +1128,7 @@ esp_err_t status_get_handler(httpd_req_t *req){
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object");
}
// update status for next status call
network_manager_async_update_status();
network_async_update_status();
return ESP_OK;
}

View File

@@ -1,34 +1,5 @@
/*
Copyright (c) 2017-2019 Tony Pottier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file http_server.h
@author Tony Pottier
@brief Defines all functions necessary for the HTTP server to run.
Contains the freeRTOS task for the HTTP listener and all necessary support
function to process requests, decode URLs, serve files, etc. etc.
@note http_server task cannot run without the wifi_manager task!
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
Copyright (c) 2017-2021 Sebastien L
*/
#ifndef HTTP_SERVER_H_INCLUDED

View File

@@ -1,38 +1,40 @@
#include "esp_eth.h"
#include "network_ethernet.h"
static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
static EXT_RAM_ATTR network_ethernet_driver_t DM9051;
static esp_err_t start(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_dm9051_config_t eth_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
// we assume that isr has been installed already
eth_config.int_gpio_num = ethernet_config->intr;
return esp_eth_mac_new_dm9051(&eth_config, &mac_config);
#else
return NULL;
#endif
}
static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = 1;
phy_config.phy_addr = -1;
phy_config.reset_gpio_num = ethernet_config->rst;
return esp_eth_phy_new_dm9051(&phy_config);
esp_eth_mac_t* mac = esp_eth_mac_new_dm9051(&eth_config, &mac_config);
esp_eth_phy_t* phy = esp_eth_phy_new_dm9051(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
return esp_eth_driver_install(&config, &DM9051.handle);
#else
return NULL;
return ESP_ERR_NOT_SUPPORTED;
#endif
}
static void init_config(eth_config_t* ethernet_config) {
}
static network_ethernet_driver_t DM9051 = {
.mac_new = mac_new,
.phy_new = phy_new,
.init_config = init_config,
.valid = true,
};
static void init_config(eth_config_t* ethernet_config) {
DM9051.start = start;
DM9051.rmii = true;
DM9051.spi = false;
DM9051.valid = true;
}
network_ethernet_driver_t* DM9051_Detect(char* Driver) {
if (!strcasestr(Driver, "DM9051"))
return NULL;
#ifdef CONFIG_ETH_SPI_ETHERNET_DM9051
DM9051.valid = true;
#else
DM9051.valid = false;
#endif
DM9051.init_config = init_config;
return &DM9051;
}

View File

@@ -1,47 +1,40 @@
#include "esp_eth.h"
#include "network_ethernet.h"
static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
static EXT_RAM_ATTR network_ethernet_driver_t LAN8720;
static esp_err_t start(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.smi_mdc_gpio_num = ethernet_config->mdc;
mac_config.smi_mdio_gpio_num = ethernet_config->mdio;
mac_config.sw_reset_timeout_ms = 400;
return esp_eth_mac_new_esp32(&mac_config);
#else
return NULL;
#endif
}
static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = 1;
phy_config.reset_gpio_num = ethernet_config->rst;
return esp_eth_phy_new_lan8720(&phy_config);
esp_eth_mac_t* mac = esp_eth_mac_new_esp32(&mac_config);
esp_eth_phy_t* phy = esp_eth_phy_new_lan8720(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
return esp_eth_driver_install(&config, &LAN8720.handle);
#else
return NULL;
#endif
return ESP_ERR_NOT_SUPPORTED;
#endif
}
static void init_config(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
#else
return NULL;
#endif
LAN8720.start = start;
LAN8720.rmii = true;
LAN8720.spi = false;
}
static network_ethernet_driver_t LAN8720 = {
.mac_new = mac_new,
.phy_new = phy_new,
.init_config = init_config,
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
.valid = true,
#else
.valid = false,
#endif
};
network_ethernet_driver_t* LAN8720_Detect(char* Driver) {
if (!strcasestr(Driver, "LAN8720"))
return NULL;
#ifdef CONFIG_ETH_PHY_INTERFACE_RMII
LAN8720.valid = true;
#else
LAN8720.valid = false;
#endif
LAN8720.init_config = init_config;
return &LAN8720;
}

View File

@@ -1,43 +1,55 @@
#include "esp_eth.h"
#include "globdefs.h"
#include "network_ethernet.h"
static EXT_RAM_ATTR network_ethernet_driver_t W5500;
static EXT_RAM_ATTR spi_device_interface_config_t devcfg;
static EXT_RAM_ATTR esp_netif_config_t cfg_spi;
static EXT_RAM_ATTR esp_netif_inherent_config_t esp_netif_config;
static esp_eth_mac_t* mac_new(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
static esp_err_t start(spi_device_handle_t spi_handle, eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
eth_w5500_config_t eth_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
// we assume that isr has been installed already
eth_config.int_gpio_num = ethernet_config->intr;
return esp_eth_mac_new_w5500(&eth_config, &mac_config);
#else
return NULL;
#endif
}
static esp_eth_phy_t* phy_new(eth_config_t* ethernet_config) {
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = 1;
eth_config.int_gpio_num = ethernet_config->intr;
phy_config.phy_addr = -1; // let the system automatically find out the phy address
phy_config.reset_gpio_num = ethernet_config->rst;
return esp_eth_phy_new_w5500(&phy_config);
esp_eth_mac_t* mac = esp_eth_mac_new_w5500(&eth_config, &mac_config);
esp_eth_phy_t* phy = esp_eth_phy_new_w5500(&phy_config);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
return esp_eth_driver_install(&config, &W5500.handle);
#else
return NULL;
return ESP_ERR_NOT_SUPPORTED;
#endif
}
static void init_config(eth_config_t* ethernet_config) {
}
esp_netif_inherent_config_t loc_esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
devcfg.command_bits = 16; // Actually it's the address phase in W5500 SPI frame
devcfg.address_bits = 8; // Actually it's the control phase in W5500 SPI frame
devcfg.mode = 0;
devcfg.clock_speed_hz = ethernet_config->speed > 0 ? ethernet_config->speed : SPI_MASTER_FREQ_20M; // default speed
devcfg.queue_size = 20;
devcfg.spics_io_num = ethernet_config->cs;
memcpy(&esp_netif_config, &loc_esp_netif_config, sizeof(loc_esp_netif_config));
cfg_spi.base = &esp_netif_config,
cfg_spi.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH;
W5500.cfg_netif = &cfg_spi;
W5500.devcfg = &devcfg;
W5500.start = start;
W5500.spi = true;
W5500.rmii = false;
static network_ethernet_driver_t W5500 = {
.mac_new = mac_new,
.phy_new = phy_new,
.init_config = init_config,
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
.valid = true,
#else
.valid = false,
#endif
};
}
network_ethernet_driver_t* W5500_Detect(char* Driver, network_ethernet_driver_t* Device) {
if (!strcasestr(Driver, "W5500"))
return NULL;
W5500.init_config = init_config;
#ifdef CONFIG_ETH_SPI_ETHERNET_W5500
W5500.valid = true;
#else
W5500.valid = false;
#endif
return &W5500;
}

View File

@@ -1,3 +1,6 @@
#ifdef NETWORK_ETHERNET_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_ETHERNET_LOG_LEVEL
#endif
#include "network_ethernet.h"
#include "freertos/timers.h"
#include "globdefs.h"
@@ -5,14 +8,13 @@
#include "network_status.h"
#include "platform_config.h"
#include "trace.h"
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "accessors.h"
#include "esp_log.h"
//#include "dnserver.h"
static char TAG[] = "network_ethernet";
TimerHandle_t ETH_timer;
esp_eth_handle_t eth_handle = NULL;
esp_netif_t* eth_netif = NULL;
EventGroupHandle_t ethernet_event_group;
const int LINK_UP_BIT = BIT0;
@@ -22,7 +24,6 @@ static network_ethernet_driver_t* network_driver = NULL;
extern network_ethernet_detect_func_t DM9051_Detect, W5500_Detect, LAN8720_Detect;
static network_ethernet_detect_func_t* drivers[] = {DM9051_Detect, W5500_Detect, LAN8720_Detect, NULL};
#define ETH_TIMEOUT_MS (30 * 1000)
static void network_manager_ethernet_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
/****************************************************************************************
*
@@ -67,7 +68,7 @@ bool network_ethernet_is_up() {
return (xEventGroupGetBits(ethernet_event_group) & LINK_UP_BIT)!=0;
}
bool network_ethernet_enabled() {
return eth_handle != NULL;
return network_driver !=NULL && network_driver->handle != NULL;
}
bool network_ethernet_wait_for_link(uint16_t max_wait_ms){
if(!network_ethernet_enabled()) return false;
@@ -89,75 +90,33 @@ bool network_ethernet_wait_for_link(uint16_t max_wait_ms){
static void ETH_Timeout(void* timer_id);
void destroy_network_ethernet() {
}
static void set_host_name() {
ESP_LOGE(TAG, "TODO: Find a way to set the host name here!");
// esp_err_t err;
// ESP_LOGD(TAG, "Retrieving host name from nvs");
// char* host_name = (char*)config_alloc_get(NVS_TYPE_STR, "host_name");
// if (host_name == NULL) {
// ESP_LOGE(TAG, "Could not retrieve host name from nvs");
// } else {
// if (!network_ethernet_enabled()) {
// ESP_LOGE(TAG, "Cannot set name on a disabled interface");
// } else {
// ESP_LOGD(TAG, "Setting host name to : %s", host_name);
// if ((err = esp_netif_set_hostname(eth_handle, host_name)) != ESP_OK) {
// ESP_LOGE(TAG, "Unable to set host name. Error: %s", esp_err_to_name(err));
// }
// ESP_LOGD(TAG, "Done setting host name to : %s", host_name);
// }
// FREE_AND_NULL(host_name);
// }
}
static void network_ethernet_print_config(const eth_config_t* eth_config) {
// #if defined(CONFIG_ETH_PHY_INTERFACE_RMII)
// if(eth_config->)
// ESP_LOGI(TAG,
// "Model: %s, rst=%d, mdc=%d, mdio=%d, host=%d, cs=%d, mosi=%d, miso=%d, intr=%d, clk=%d, speed=%d, tx_en=%d, tx0=%d, tx1=%d, rx0=%d, rx1=%d, crs_dv=%d",
// eth_config->model, eth_config->rst, eth_config->mdc, eth_config->mdio, eth_config->host, eth_config->cs,
// eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->clk, eth_config->speed,
// eth_config->tx_en, eth_config->tx0, eth_config->tx1, eth_config->rx0, eth_config->rx1, eth_config->crs_dv);
// #else
// ESP_LOGI(TAG, "Model: %s, rst=%d, mdc=%d, mdio=%d, host=%d, cs=%d, mosi=%d, miso=%d, intr=%d, clk=%d, speed=%d ",
// eth_config->model, eth_config->rst, eth_config->mdc, eth_config->mdio, eth_config->host, eth_config->cs,
// eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->clk, eth_config->speed);
// :
// #endif
ESP_LOGI(TAG,"Ethernet config: \n model: %s, valid: %s, type: %s, mdc:%d, mdio:%d, rst:%d, mosi:%d, miso:%d, intr:%d, cs:%d, speed:%d, clk:%d, host:%s(%d)",
eth_config->model, eth_config->valid?"YES":"NO",eth_config->spi?"SPI":"RMII", eth_config->mdc, eth_config->mdio, eth_config->rst, eth_config->mosi, eth_config->miso, eth_config->intr, eth_config->cs, eth_config->speed, eth_config->clk, eth_config->host==0?"SPI1":eth_config->host==1?"SPI2":eth_config->host==2?"SPI3":"",eth_config->host);
}
void init_network_ethernet() {
esp_err_t err = ESP_OK;
esp_eth_mac_t* mac;
esp_eth_phy_t* phy;
eth_config_t eth;
ESP_LOGI(TAG, "Attempting to initialize Ethernet");
config_eth_init(&eth);
ESP_LOGD(TAG, "Attempting to initialize Ethernet");
// quick check if we have a valid ethernet configuration
if (!eth.valid) {
ESP_LOGI(TAG, "No ethernet");
return;
}
network_driver = network_ethernet_driver_autodetect(eth.model);
if (!network_driver) {
messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Invalid ethernet Ethernet chip %s", eth.model);
return;
}
if (!network_driver->valid) {
messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Code not compiled for Ethernet chip %s", eth.model);
if(!eth.valid){
ESP_LOGI(TAG,"No Ethernet configuration, or configuration invalid");
return;
}
network_driver->init_config(&eth);
network_ethernet_print_config(&eth);
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
eth_netif = esp_netif_new(&cfg);
eth_netif = esp_netif_new(network_driver->cfg_netif);
esp_eth_set_default_handlers(eth_netif);
esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL);
esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL);
ethernet_event_group = xEventGroupCreate();
xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT);
spi_device_handle_t spi_handle = NULL;
if (network_driver->eth_config.spi) {
if (network_driver->spi) {
spi_host_device_t host = SPI3_HOST;
if (eth.host != -1) {
@@ -169,12 +128,18 @@ void init_network_ethernet() {
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
// can't use SPI0
if (eth.host == 1)
if (eth.host == 0)
{
ESP_LOGW(TAG,"Cannot use SPI1 host. Defaulting to SPI2");
host = SPI2_HOST;
ESP_LOGI(TAG, "Initializing SPI bus on host %d with mosi %d and miso %d", host, eth.mosi, eth.miso);
err = spi_bus_initialize(host, &buscfg, 1);
}
else {
host = eth.host;
}
ESP_LOGI(TAG, "Initializing SPI bus on host %d (SPI%d) with mosi %d and miso %d", host,host+1, eth.mosi, eth.miso);
err = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI bus init failed : %s", esp_err_to_name(err));
}
@@ -184,38 +149,39 @@ void init_network_ethernet() {
host = spi_system_host;
}
if (err == ESP_OK) {
spi_device_interface_config_t devcfg = {
.command_bits = 1,
.address_bits = 7,
.mode = 0,
.clock_speed_hz = eth.speed,
.spics_io_num = eth.cs,
.queue_size = 20};
ESP_LOGI(TAG, "Adding ethernet SPI on host %d with mosi %d and miso %d", host, eth.mosi, eth.miso);
err = spi_bus_add_device(host, &devcfg, &spi_handle);
ESP_LOGI(TAG, "Adding ethernet SPI on host %d (SPI%d) with mosi %d and miso %d", host,host+1, eth.mosi, eth.miso);
err = spi_bus_add_device(host, network_driver->devcfg, &spi_handle);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI host failed : %s", esp_err_to_name(err));
}
}
if (err == ESP_OK) {
ESP_LOGD(TAG, "Setting up ethernet driver");
mac = network_driver->mac_new(spi_handle, &eth);
phy = network_driver->phy_new(&eth);
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
err = esp_eth_driver_install(&config, &eth_handle);
err = network_driver->start(spi_handle,&eth);
}
if(err == ESP_OK){
uint8_t mac_address[6];
esp_read_mac(mac_address,ESP_MAC_ETH);
char * mac_string=network_manager_alloc_get_mac_string(mac_address);
ESP_LOGD(TAG,"Assigning mac address %s to ethernet interface", STR_OR_BLANK(mac_string));
FREE_AND_NULL(mac_string);
esp_eth_ioctl(network_driver->handle, ETH_CMD_S_MAC_ADDR, mac_address);
}
if (err == ESP_OK) {
ESP_LOGD(TAG, "Attaching ethernet to network interface");
err = esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle));
err = esp_netif_attach(eth_netif, esp_eth_new_netif_glue(network_driver->handle));
}
if (err == ESP_OK) {
ESP_LOGI(TAG, "Starting ethernet network");
err = esp_eth_start(eth_handle);
err = esp_eth_start(network_driver->handle);
}
if (err != ESP_OK) {
messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "Configuring Ethernet failed: %s", esp_err_to_name(err));
eth_handle = NULL;
if(spi_handle) {
spi_bus_remove_device(spi_handle);
}
network_driver->handle = NULL;
}
}
@@ -235,18 +201,17 @@ static void eth_event_handler(void* arg, esp_event_base_t event_base, int32_t ev
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "");
ESP_LOGI(TAG, "Ethernet Link Up, HW Addr %02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
ESP_LOGD(TAG, "Sending EVENT_ETH_LINK_UP message to network manager");
network_manager_async_link_up();
network_async_link_up();
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT);
ESP_LOGD(TAG, "Sending EVENT_ETH_LINK_DOWN message to network manager");
network_manager_async_link_down();
network_async_link_down();
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started. Setting host name");
set_host_name();
network_set_hostname(eth_netif);
network_async_success();
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
@@ -254,30 +219,10 @@ static void eth_event_handler(void* arg, esp_event_base_t event_base, int32_t ev
default:
break;
}
} else if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) {
network_manager_ethernet_ip_event_handler(arg, event_base, event_id, event_data);
}
}
}
static void ETH_Timeout(void* timer_id) {
network_manager_async_fail();
network_async_fail();
}
static void network_manager_ethernet_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base != IP_EVENT)
return;
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
ip_event_got_ip_t* s = event_data;
tcpip_adapter_if_t index = s->if_index;
esp_netif_ip_info_t* ip_info = &s->ip_info;
ESP_LOGI(TAG, "Got an IP address from Ethernet interface #%i. IP=" IPSTR ", Gateway=" IPSTR ", NetMask=" IPSTR ", %s",
index,
IP2STR(&ip_info->ip),
IP2STR(&ip_info->gw),
IP2STR(&ip_info->netmask),
s->ip_changed ? "Address was changed" : "Address unchanged");
ip_event_got_ip_t* parm = malloc(sizeof(ip_event_got_ip_t));
memcpy(parm, event_data, sizeof(ip_event_got_ip_t));
network_manager_async_got_ip(parm);
}

View File

@@ -3,19 +3,26 @@
#include "network_manager.h"
#include "accessors.h"
#include <string.h>
#include "esp_netif_defaults.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
bool valid;
eth_config_t eth_config;
esp_eth_mac_t* (*mac_new)(spi_device_handle_t spi_handle, eth_config_t * eth_config);
esp_eth_phy_t *(*phy_new)( eth_config_t* eth_config);
bool rmii;
bool spi;
esp_eth_handle_t handle;
esp_netif_config_t * cfg_netif;
spi_device_interface_config_t * devcfg;
// esp_eth_mac_t* (*mac_new)(spi_device_handle_t spi_handle, eth_config_t * eth_config);
// esp_eth_phy_t *(*phy_new)( eth_config_t* eth_config);
esp_err_t (*start)(spi_device_handle_t spi_handle,eth_config_t *ethernet_config);
void (*init_config)(eth_config_t * eth_config);
} network_ethernet_driver_t;
typedef network_ethernet_driver_t* network_ethernet_detect_func_t(const char* Driver);
network_ethernet_driver_t* network_ethernet_driver_autodetect(const char* Driver);
void destroy_network_ethernet();
void init_network_ethernet();
bool network_ethernet_wait_for_link(uint16_t max_wait_ms);

View File

@@ -1,34 +1,10 @@
/*
Copyright (c) 2017-2019 Tony Pottier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file wifi_manager.c
@author Tony Pottier
@brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis
Contains the freeRTOS task and all necessary support
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
Copyright (c) 2017-2021 Sebastien L
*/
#ifdef NETWORK_MANAGER_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_MANAGER_LOG_LEVEL
#endif
#include "network_manager.h"
#include <stdbool.h>
#include <stdio.h>
@@ -37,16 +13,15 @@ Contains the freeRTOS task and all necessary support
#include "network_ethernet.h"
#include "network_status.h"
#include "network_wifi.h"
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "dns_server.h"
#include "esp_log.h"
#include "platform_esp32.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "platform_esp32.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "freertos/task.h"
#include "cJSON.h"
#include "cmd_system.h"
@@ -62,59 +37,696 @@ Contains the freeRTOS task and all necessary support
#include "lwip/netdb.h"
#include "mdns.h"
#include "messaging.h"
#include "state_machine.h"
#include "platform_config.h"
#include "trace.h"
#include "accessors.h"
#include "esp_err.h"
#include "globdefs.h"
#include "http_server_handlers.h"
#include "network_manager.h"
QueueHandle_t network_queue;
BaseType_t network_task_handle;
static const char TAG[] = "network";
static TaskHandle_t task_network_manager = NULL;
RTC_NOINIT_ATTR static bool s_wifi_prioritized = false;
extern esp_reset_reason_t xReason;
typedef struct network_callback {
network_status_reached_cb cb;
nm_state_t state;
int sub_state;
const char* from;
SLIST_ENTRY(network_callback)
next; //!< next callback
} network_callback_t;
/** linked list of command structures */
static SLIST_HEAD(cb_list, network_callback) s_cb_list;
network_t NM;
//! Create and initialize the array of state machines.
state_machine_t* const SM[] = {(state_machine_t*)&NM};
static void network_timer_cb(void* timer_id);
int get_root_id(const state_t * state);
const state_t* get_root( const state_t* const state);
static void network_task(void* pvParameters);
void network_start_stop_dhcp(esp_netif_t* netif, bool start) {
tcpip_adapter_dhcp_status_t status;
esp_err_t err = ESP_OK;
ESP_LOGD(TAG, "Checking if DHCP client for STA interface is running");
if (!netif) {
ESP_LOGE(TAG, "Invalid adapter. Cannot start/stop dhcp. ");
return;
}
if((err=esp_netif_dhcpc_get_status(netif, &status))!=ESP_OK){
ESP_LOGE(TAG,"Error retrieving dhcp status : %s", esp_err_to_name(err));
return;
}
switch (status)
{
case ESP_NETIF_DHCP_STARTED:
if(start){
ESP_LOGD(TAG, "DHCP client already started");
}
else {
ESP_LOGI(TAG, "Stopping DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_stop(netif));
}
break;
case ESP_NETIF_DHCP_STOPPED:
if(start){
ESP_LOGI(TAG, "Starting DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_start(netif));
}
else {
ESP_LOGI(TAG, "DHCP client already started");
}
break;
case ESP_NETIF_DHCP_INIT:
if(start){
ESP_LOGI(TAG, "Starting DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_start(netif));
}
else {
ESP_LOGI(TAG, "Stopping DHCP client");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcpc_stop(netif));
}
break;
default:
ESP_LOGW(TAG,"Unknown DHCP status");
break;
}
}
void network_start_stop_dhcps(esp_netif_t* netif, bool start) {
tcpip_adapter_dhcp_status_t status;
esp_err_t err = ESP_OK;
ESP_LOGD(TAG, "Checking if DHCP server is running");
if (!netif) {
ESP_LOGE(TAG, "Invalid adapter. Cannot start/stop dhcp server. ");
return;
}
if((err=esp_netif_dhcps_get_status(netif, &status))!=ESP_OK){
ESP_LOGE(TAG,"Error retrieving dhcp server status : %s", esp_err_to_name(err));
return;
}
switch (status)
{
case ESP_NETIF_DHCP_STARTED:
if(start){
ESP_LOGD(TAG, "DHCP server already started");
}
else {
ESP_LOGI(TAG, "Stopping DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
}
break;
case ESP_NETIF_DHCP_STOPPED:
if(start){
ESP_LOGI(TAG, "Starting DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
}
else {
ESP_LOGI(TAG, "DHCP server already stopped");
}
break;
case ESP_NETIF_DHCP_INIT:
if(start){
ESP_LOGI(TAG, "Starting DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
}
else {
ESP_LOGI(TAG, "Stopping DHCP server");
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
}
break;
default:
ESP_LOGW(TAG,"Unknown DHCP status");
break;
}
}
/*********************************************************************************************
* String conversion routines
*/
#ifndef STR_OR_BLANK
#define STR_OR_BLANK(p) p == NULL ? "" : p
#endif
#define ADD_ROOT(name,...) CASE_TO_STR(name);
#define ADD_ROOT_LEAF(name,...) CASE_TO_STR(name);
#define ADD_LEAF(name,...) CASE_TO_STR(name);
#define ADD_EVENT(name) CASE_TO_STR(name);
#define ADD_FIRST_EVENT(name) CASE_TO_STR(name);
static const char* state_to_string(const state_t * state) {
if(!state) {
return "";
}
switch (state->Parent?state->Parent->Id:state->Id) {
ALL_NM_STATE
default:
break;
}
return "Unknown";
}
static const char* wifi_state_to_string(mn_wifi_active_state_t state) {
switch (state) {
ALL_WIFI_STATE(,)
default:
break;
}
return "Unknown";
}
static const char* eth_state_to_string(mn_eth_active_state_t state) {
switch (state) {
ALL_ETH_STATE(,)
default:
break;
}
return "Unknown";
}
static const char* wifi_configuring_state_to_string(mn_wifi_configuring_state_t state) {
switch (state) {
ALL_WIFI_CONFIGURING_STATE(,)
default:
break;
}
return "Unknown";
}
static const char* sub_state_to_string(const state_t * state) {
if(!state) {
return "N/A";
}
int root_id = get_root_id(state);
switch (root_id)
{
case NETWORK_ETH_ACTIVE_STATE:
return eth_state_to_string(state->Id);
break;
case NETWORK_WIFI_ACTIVE_STATE:
return wifi_state_to_string(state->Id);
case NETWORK_WIFI_CONFIGURING_ACTIVE_STATE:
return wifi_configuring_state_to_string(state->Id);
default:
break;
}
return "*";
}
//EventGroupHandle_t wifi_manager_event_group;
void (**cb_ptr_arr)(void*) = NULL;
static const char* event_to_string(network_event_t state) {
switch (state) {
ALL_NM_EVENTS
/* @brief tag used for ESP serial console messages */
//static const char TAG[] = "network_manager";
default:
break;
}
return "Unknown";
}
/* @brief indicate that the ESP32 is currently connected. */
const int WIFI_MANAGER_WIFI_CONNECTED_BIT = BIT0;
const int WIFI_MANAGER_AP_STA_CONNECTED_BIT = BIT1;
/* @brief Set automatically once the SoftAP is started */
const int WIFI_MANAGER_AP_STARTED_BIT = BIT2;
/* @brief When set, means a client requested to connect to an access point.*/
const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT = BIT3;
/* @brief This bit is set automatically as soon as a connection was lost */
const int WIFI_MANAGER_STA_DISCONNECT_BIT = BIT4;
/* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */
const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT = BIT5;
/* @brief When set, means a client requested to disconnect from currently connected AP. */
const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT = BIT6;
/* @brief When set, means a scan is in progress */
const int WIFI_MANAGER_SCAN_BIT = BIT7;
/* @brief When set, means user requested for a disconnect */
const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT = BIT8;
/* @brief When set, means user requested connecting to a new network and it failed */
const int WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT = BIT9;
#undef ADD_EVENT
#undef ADD_FIRST_EVENT
#undef ADD_ROOT
#undef ADD_ROOT_LEAF
#undef ADD_LEAF
/* @brief task handle for the main wifi_manager task */
typedef struct {
int parent_state;
int sub_state_last ;
} max_sub_states_t;
static const max_sub_states_t state_max[] = {
{ .parent_state = NETWORK_INSTANTIATED_STATE, .sub_state_last = 0 },
{.parent_state = NETWORK_ETH_ACTIVE_STATE, .sub_state_last = TOTAL_ETH_ACTIVE_STATE-1 },
{.parent_state = NETWORK_WIFI_ACTIVE_STATE, .sub_state_last = TOTAL_WIFI_ACTIVE_STATE-1 },
{.parent_state = WIFI_CONFIGURING_STATE, .sub_state_last = TOTAL_WIFI_CONFIGURING_STATE-1 },
{.parent_state = WIFI_CONFIGURING_STATE, .sub_state_last = TOTAL_WIFI_CONFIGURING_STATE-1 },
{.parent_state =-1}
};
void network_start() {
if(xReason == ESP_RST_POWERON ){
ESP_LOGD(TAG, "Power on reset, initializing wifi priotitized to false");
s_wifi_prioritized = false;
}
ESP_LOGD(TAG, " Creating message queue");
network_queue = xQueueCreate(3, sizeof(queue_message));
ESP_LOGD(TAG, " Creating network manager task");
network_task_handle = xTaskCreate(&network_task, "network", 4096, NULL, WIFI_MANAGER_TASK_PRIORITY, &task_network_manager);
}
static void event_logger(uint32_t state_machine, uint32_t state, uint32_t event) {
ESP_LOGI(TAG, "Handling network manager event state Id %d->[%s]", state, event_to_string(event));
}
static const char * get_state_machine_result_string(state_machine_result_t result) {
switch(result) {
case EVENT_HANDLED:
return "EVENT_HANDLED";
case EVENT_UN_HANDLED:
return "EVENT_UN_HANDLED";
case TRIGGERED_TO_SELF:
return "TRIGGERED_TO_SELF";
}
return "Unknown";
}
static void result_logger(uint32_t state, state_machine_result_t result) {
ESP_LOGD(TAG, "Network Manager Result: %s, New State id: %d", get_state_machine_result_string(result) , state);
}
static void network_task(void* pvParameters) {
queue_message msg;
BaseType_t xStatus;
initialize_network_handlers((state_machine_t*)&NM);
network_async(EN_START);
/* main processing loop */
for (;;) {
xStatus = xQueueReceive(network_queue, &msg, portMAX_DELAY);
if (xStatus == pdPASS) {
// pass the event to the sync processor
NM.event_parameters = &msg;
NM.Machine.Event = msg.trigger;
if (dispatch_event(SM, 1, event_logger, result_logger) == EVENT_UN_HANDLED) {
network_manager_format_from_to_states(ESP_LOG_ERROR,"Unhandled Event",NULL,NM.Machine.State,msg.trigger,false,"network manager");
}
} /* end of if status=pdPASS */
} /* end of for loop */
vTaskDelete(NULL);
}
int get_max_substate(nm_state_t state){
for(int i=0;state_max[i].parent_state!=-1;i++){
if(state_max[i].parent_state == state){
return state_max[i].sub_state_last;
}
}
return -1;
}
esp_err_t network_register_state_callback(nm_state_t state,int sub_state, const char* from, network_status_reached_cb cb) {
network_callback_t* item = NULL;
if (!cb) {
return ESP_ERR_INVALID_ARG;
}
item = calloc(1, sizeof(*item));
if (item == NULL) {
return ESP_ERR_NO_MEM;
}
if(sub_state != -1 && sub_state>get_max_substate(state)){
// sub state has to be valid
return ESP_ERR_INVALID_ARG;
}
item->state = state;
item->cb = cb;
item->from = from;
item->sub_state=sub_state;
network_callback_t* last = SLIST_FIRST(&s_cb_list);
if (last == NULL) {
SLIST_INSERT_HEAD(&s_cb_list, item, next);
} else {
network_callback_t* it;
while ((it = SLIST_NEXT(last, next)) != NULL) {
last = it;
}
SLIST_INSERT_AFTER(last, item, next);
}
return ESP_OK;
}
const state_t* get_root( const state_t* const state){
if(!state) return NULL;
return state->Parent==NULL?state: get_root(state->Parent);
}
int get_root_id(const state_t * state){
if(!state) return -1;
return state->Parent==NULL?state->Id: get_root_id(state->Parent);
}
void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*)) {
if (cb_ptr_arr && message_code < MESSAGE_CODE_COUNT) {
cb_ptr_arr[message_code] = func_ptr;
static bool is_root_state(const state_t * state){
return state->Parent==NULL;
}
static bool is_current_state(const state_t* state, nm_state_t state_id, int sub_state_id){
return get_root(state)->Id == state_id && (sub_state_id==-1 || (!is_root_state(state) && state->Id == sub_state_id) );
}
void network_execute_cb(state_machine_t* const state_machine, const char * caller) {
network_callback_t* it;
SLIST_FOREACH(it, &s_cb_list, next) {
if (is_current_state(state_machine->State,it->state, it->sub_state)) {
char * cb_prefix= messaging_alloc_format_string("BEGIN Executing Callback %s", it->from) ;
NETWORK_DEBUG_STATE_MACHINE(true,STR_OR_BLANK(cb_prefix),state_machine,false, STR_OR_BLANK(caller));
FREE_AND_NULL(cb_prefix);
it->cb((nm_state_t)get_root(state_machine->State)->Id, is_root_state(state_machine->State)?-1:state_machine->State->Id);
cb_prefix= messaging_alloc_format_string("END Executing Callback %s", it->from) ;
NETWORK_DEBUG_STATE_MACHINE(false,STR_OR_BLANK(cb_prefix),state_machine,false, STR_OR_BLANK(caller));
FREE_AND_NULL(cb_prefix);
}
}
}
bool network_is_wifi_prioritized() {
eth_config_t eth_config;
config_eth_init(&eth_config);
// char* prioritize = (char*)config_alloc_get_default(NVS_TYPE_STR, "prio_wifi", "N", 0);
// bool result = strcasecmp("N", prioritize);
bool result = s_wifi_prioritized;
if(result){
result = network_wifi_get_known_count()>0 || !eth_config.valid;
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");
}
return result;
}
void network_prioritize_wifi(bool activate) {
if(s_wifi_prioritized == activate) return;
s_wifi_prioritized = activate;
ESP_LOGI(TAG,"Wifi is %s prioritized",activate?"":"not");
// if (network_is_wifi_prioritized() != activate) {
// ESP_LOGW(TAG, "Wifi will %s be prioritized on next boot", activate ? "" : "NOT");
// config_set_value(NVS_TYPE_STR, "prio_wifi", activate ? "Y" : "N");
// }
}
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) {
state_t const* source_state = NULL;
state_t const* current_state = NULL;
network_event_t event = -1;
MEMTRACE_PRINT_DELTA();
if (state_machine) {
source_state = ((network_t *)state_machine)->source_state;
current_state = state_machine->State;
event = state_machine->Event;
network_manager_format_from_to_states(level, prefix, source_state, current_state, event, show_source,caller);
}
else {
ESP_LOG_LEVEL(level, TAG, "%s - %s -> [%s]",
STR_OR_BLANK(caller),
prefix,
event_to_string(event));
}
}
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) {
const char* source_state = "";
const char* source_sub_state = "";
const char* state = "N/A";
const char* sub_state = "N/A";
if (current_state) {
state = state_to_string(current_state);
sub_state = sub_state_to_string(current_state);
}
if (!from_state) {
source_state = "N/A";
} else {
source_state = state_to_string(from_state);
source_sub_state = sub_state_to_string(from_state);
}
if (show_source) {
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,
event_to_string(event));
} else {
ESP_LOG_LEVEL(level, TAG, "%s %s %s(%s) [%s]",
STR_OR_BLANK(caller),
prefix,
state,
sub_state,
event_to_string(event));
}
}
void network_async(network_event_t trigger) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = trigger;
ESP_LOGD(TAG, "Posting event %s directly", event_to_string(trigger));
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
void network_async_fail() {
network_async(EN_FAIL);
}
void network_async_success() {
network_async(EN_SUCCESS);
}
void network_async_connected(){
network_async(EN_CONNECTED);
}
void network_async_link_up() {
network_async(EN_LINK_UP);
}
void network_async_link_down() {
network_async(EN_LINK_DOWN);
}
void network_async_configure() {
network_async(EN_CONFIGURE);
}
void network_async_got_ip() {
network_async(EN_GOT_IP);
}
void network_async_eth_got_ip() {
network_async(EN_ETH_GOT_IP);
}
void network_async_timer() {
network_async(EN_TIMER);
}
void network_async_start() {
network_async(EN_START);
}
void network_async_scan() {
network_async(EN_SCAN);
}
void network_async_update_status() {
network_async(EN_UPDATE_STATUS);
}
void network_async_delete() {
network_async(EN_DELETE);
}
void network_async_scan_done() {
network_async(EN_SCAN_DONE);
}
void network_async_connect(const char * ssid, const char * password) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = EN_CONNECT_NEW;
msg.ssid = strdup_psram(ssid);
if(password && strlen(password) >0){
msg.password = strdup_psram(password);
}
ESP_LOGD(TAG, "Posting event %s", event_to_string(msg.trigger));
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
void network_async_lost_connection(wifi_event_sta_disconnected_t* disconnected_event) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = EN_LOST_CONNECTION;
ESP_LOGD(TAG, "Posting event %s", event_to_string(msg.trigger));
msg.disconnected_event = malloc_init_external(sizeof(wifi_event_sta_disconnected_t));
if(msg.disconnected_event){
memcpy(msg.disconnected_event, disconnected_event,sizeof(wifi_event_sta_disconnected_t));
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
else {
ESP_LOGE(TAG,"Unable to post lost connection event.");
}
}
void network_async_reboot(reboot_type_t rtype) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
msg.trigger = EN_REBOOT;
msg.rtype = rtype;
ESP_LOGD(TAG, "Posting event %s - type %d", event_to_string(msg.trigger),rtype);
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
void network_reboot_ota(char* url) {
queue_message msg;
memset(&msg,0x00,sizeof(msg));
if (url == NULL) {
msg.trigger = EN_REBOOT;
msg.rtype = OTA;
ESP_LOGD(TAG, "Posting event %s - type %d", event_to_string(msg.trigger),msg.rtype);
} else {
msg.trigger = EN_REBOOT_URL;
ESP_LOGD(TAG, "Posting event %s - type reboot URL", event_to_string(msg.trigger));
msg.strval = strdup_psram(url);
}
xQueueSendToBack(network_queue, &msg, portMAX_DELAY);
}
network_t* network_get_state_machine() {
return &NM;
}
static void network_timer_cb(void* timer_id) {
network_async_timer();
}
esp_netif_t* network_get_active_interface() {
if (NM.wifi_ap_netif && (network_wifi_is_ap_mode() || network_wifi_is_ap_sta_mode())) {
return NM.wifi_ap_netif;
} else if (NM.wifi_netif && network_wifi_is_sta_mode()) {
return NM.wifi_netif;
}
return NM.eth_netif;
}
bool network_is_interface_connected(esp_netif_t* interface) {
esp_err_t err = ESP_OK;
tcpip_adapter_ip_info_t ipInfo;
if(!interface){
return false;
}
err = network_get_ip_info_for_netif(interface, &ipInfo);
if(err != ESP_OK){
ESP_LOGD(TAG,"network_get_ip_info_for_netif returned %s", esp_err_to_name(err));
}
return ((err == ESP_OK) && (ipInfo.ip.addr != IPADDR_ANY));
}
static esp_netif_t* get_connected_interface() {
esp_netif_t* interface = NULL;
for (int i = 0; i < 4; i++) {
switch (i) {
case 0:
// try the active interface
interface = network_get_active_interface();
break;
case 1:
interface = NM.wifi_ap_netif;
break;
case 2:
interface = NM.wifi_netif;
break;
case 3:
interface = NM.eth_netif;
break;
default:
break;
}
if (interface && network_is_interface_connected(interface)) {
ESP_LOGD(TAG,"Found connected interface in iteration #%d",i);
return interface;
}
}
ESP_LOGD(TAG,"No connected interface found");
return NULL;
}
esp_err_t network_get_ip_info_for_netif(esp_netif_t* netif, tcpip_adapter_ip_info_t* ipInfo) {
esp_netif_ip_info_t loc_ip_info;
if (!ipInfo ) {
ESP_LOGE(TAG, "Invalid pointer for ipInfo");
return ESP_ERR_INVALID_ARG;
}
if (!netif) {
ESP_LOGE(TAG, "Invalid pointer for netif");
return ESP_ERR_INVALID_ARG;
}
memset(ipInfo,0x00,sizeof(tcpip_adapter_ip_info_t));
esp_err_t err= esp_netif_get_ip_info(netif, &loc_ip_info);
if(err==ESP_OK){
ip4_addr_set(&(ipInfo->ip),&loc_ip_info.ip);
ip4_addr_set(&(ipInfo->gw),&loc_ip_info.gw);
ip4_addr_set(&(ipInfo->netmask),&loc_ip_info.netmask);
}
return err;
}
esp_err_t network_get_ip_info(tcpip_adapter_ip_info_t* ipInfo) {
esp_netif_t* netif= get_connected_interface();
if(netif){
return network_get_ip_info_for_netif(netif,ipInfo);
}
return ESP_FAIL;
}
esp_err_t network_get_hostname(const char** hostname) {
return esp_netif_get_hostname(get_connected_interface(), hostname);
}
void network_set_timer(uint16_t duration) {
if (duration > 0) {
if (!NM.state_timer) {
ESP_LOGD(TAG, "Starting new pulse check timer with period of %u ms.", duration);
NM.state_timer = xTimerCreate("background STA", pdMS_TO_TICKS(duration), pdFALSE, NULL, network_timer_cb);
} else {
ESP_LOGD(TAG, "Changing the pulse timer period to %u ms.", duration);
xTimerChangePeriod(NM.state_timer, pdMS_TO_TICKS(duration), portMAX_DELAY);
}
xTimerStart(NM.state_timer, portMAX_DELAY);
} else if (NM.state_timer) {
ESP_LOGD(TAG, "Stopping timer");
xTimerStop(NM.state_timer, portMAX_DELAY);
}
}
void network_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
ip_event_got_ip_t* s = NULL;
esp_netif_ip_info_t* ip_info = NULL;
if (event_base != IP_EVENT)
return;
switch (event_id) {
case IP_EVENT_ETH_GOT_IP:
case IP_EVENT_STA_GOT_IP:
s = (ip_event_got_ip_t*)event_data;
ip_info = &s->ip_info;
ESP_LOGI(TAG, "Got an IP address from interface %s. IP=" IPSTR ", Gateway=" IPSTR ", NetMask=" IPSTR ", %s",
event_id == IP_EVENT_ETH_GOT_IP ? "Eth" : event_id == IP_EVENT_STA_GOT_IP ? "Wifi"
: "Unknown",
IP2STR(&ip_info->ip),
IP2STR(&ip_info->gw),
IP2STR(&ip_info->netmask),
s->ip_changed ? "Address was changed" : "Address unchanged");
network_async(event_id == IP_EVENT_ETH_GOT_IP ? EN_ETH_GOT_IP : EN_GOT_IP);
break;
case IP_EVENT_STA_LOST_IP:
ESP_LOGD(TAG, "IP_EVENT_STA_LOST_IP");
break;
case IP_EVENT_AP_STAIPASSIGNED:
ESP_LOGD(TAG, "IP_EVENT_AP_STAIPASSIGNED");
break;
case IP_EVENT_GOT_IP6:
ESP_LOGD(TAG, "IP_EVENT_GOT_IP6");
break;
default:
break;
}
}
void network_set_hostname(esp_netif_t* interface) {
esp_err_t err;
ESP_LOGD(TAG, "Retrieving host name from nvs");
char* host_name = (char*)config_alloc_get(NVS_TYPE_STR, "host_name");
if (host_name == NULL) {
ESP_LOGE(TAG, "Could not retrieve host name from nvs");
} else {
ESP_LOGD(TAG, "Setting host name to : %s", host_name);
if ((err = esp_netif_set_hostname(interface, host_name)) != ESP_OK) {
ESP_LOGE(TAG, "Unable to set host name. Error: %s", esp_err_to_name(err));
}
free(host_name);
}
}
#define LOCAL_MAC_SIZE 20
char* network_manager_alloc_get_mac_string(uint8_t mac[6]) {
char* macStr = malloc_init_external(LOCAL_MAC_SIZE);
if(macStr){
snprintf(macStr, LOCAL_MAC_SIZE, MACSTR, MAC2STR(mac));
}
return macStr;
}

View File

@@ -1,41 +1,5 @@
/*
Copyright (c) 2017-2019 Tony Pottier
#pragma once
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@file network_manager.h
@author Tony Pottier
@brief Defines all functions necessary for esp32 to connect to a wifi/scan wifis
Contains the freeRTOS task and all necessary support
@see https://idyl.io
@see https://github.com/tonyp7/esp32-wifi-manager
*/
#ifndef WIFI_MANAGER_H_INCLUDED
#define WIFI_MANAGER_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
@@ -43,8 +7,192 @@ extern "C" {
#include "cJSON.h"
#include "esp_eth.h"
#include "freertos/event_groups.h"
#include "state_machine.h"
#include "state_machine.h"
#include "hsm.h"
#include "esp_log.h"
#ifdef __cplusplus
extern "C" {
#endif
#define STA_POLLING_MIN (15 * 1000)
#define STA_POLLING_MAX (10 * 60 * 1000)
#define ETH_LINK_DOWN_REBOOT (2 * 1000)
#define ETH_DHCP_FAIL (6 * 1000)
#define WIFI_DHCP_FAIL (6 * 1000)
/*
* --------------------- ENUMERATION ---------------------
*/
//#define ADD_ROOT(NAME, HANDLER, ENTRY, EXIT, CHILD)
//#define ADD_ROOT(NAME, HANDLER, ENTRY, EXIT, CHILD)
//#define ADD_LEAF(NAME, HANDLER, ENTRY, EXIT, PARENT, LEVEL)
#define ALL_NM_STATE \
ADD_ROOT_LEAF(NETWORK_INSTANTIATED_STATE)\
ADD_ROOT_LEAF(NETWORK_INITIALIZING_STATE)\
ADD_ROOT(NETWORK_ETH_ACTIVE_STATE, Eth_Active_State)\
ADD_ROOT(NETWORK_WIFI_ACTIVE_STATE, Wifi_Active_State)\
ADD_ROOT(NETWORK_WIFI_CONFIGURING_ACTIVE_STATE, Wifi_Configuring_State)
#define ALL_ETH_STATE(PARENT, LEVEL)\
ADD_LEAF(ETH_STARTING_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKUP_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_LINKDOWN_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_ACTIVE_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(ETH_CONNECTING_NEW_STATE,PARENT,LEVEL)
#define ALL_WIFI_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_INITIALIZING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTING_NEW_FAILED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_USER_DISCONNECTED_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_LOST_CONNECTION_STATE,PARENT,LEVEL)
#define ALL_WIFI_CONFIGURING_STATE(PARENT, LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_STATE,PARENT,LEVEL)\
ADD_LEAF(WIFI_CONFIGURING_CONNECT_SUCCESS_GOTOSTA_STATE,PARENT,LEVEL)
#define ADD_ROOT(name, ...) name,
#define ADD_ROOT_LEAF(name, ...) name,
#define ADD_LEAF(name, ...) name,
typedef enum {
ALL_NM_STATE
TOTAL_NM_STATE
} nm_state_t;
typedef enum {
ALL_WIFI_STATE(,)
TOTAL_WIFI_ACTIVE_STATE
} mn_wifi_active_state_t;
typedef enum {
ALL_ETH_STATE(,)
TOTAL_ETH_ACTIVE_STATE
} mn_eth_active_state_t;
typedef enum {
ALL_WIFI_CONFIGURING_STATE(,)
TOTAL_WIFI_CONFIGURING_STATE
} mn_wifi_configuring_state_t;
#undef ADD_STATE
#undef ADD_ROOT
#undef ADD_ROOT_LEAF
#undef ADD_LEAF
typedef void (*network_status_reached_cb)(nm_state_t state_id, int sub_state );
//! List of oven events
#define ALL_NM_EVENTS \
ADD_FIRST_EVENT(EN_LINK_UP) \
ADD_EVENT(EN_LINK_DOWN)\
ADD_EVENT(EN_CONFIGURE)\
ADD_EVENT(EN_GOT_IP)\
ADD_EVENT(EN_ETH_GOT_IP)\
ADD_EVENT(EN_DELETE)\
ADD_EVENT(EN_TIMER)\
ADD_EVENT(EN_START)\
ADD_EVENT(EN_SCAN)\
ADD_EVENT(EN_FAIL)\
ADD_EVENT(EN_SUCCESS)\
ADD_EVENT(EN_SCAN_DONE)\
ADD_EVENT(EN_CONNECT)\
ADD_EVENT(EN_CONNECT_NEW)\
ADD_EVENT(EN_REBOOT)\
ADD_EVENT(EN_REBOOT_URL)\
ADD_EVENT(EN_LOST_CONNECTION)\
ADD_EVENT(EN_ETHERNET_FALLBACK)\
ADD_EVENT(EN_UPDATE_STATUS)\
ADD_EVENT(EN_CONNECTED)
#define ADD_EVENT(name) name,
#define ADD_FIRST_EVENT(name) name=1,
typedef enum {
ALL_NM_EVENTS
} network_event_t;
#undef ADD_EVENT
#undef ADD_FIRST_EVENT
typedef enum {
OTA,
RECOVERY,
RESTART,
} reboot_type_t;
typedef struct {
network_event_t trigger;
char * ssid;
char * password;
reboot_type_t rtype;
char* strval;
wifi_event_sta_disconnected_t* disconnected_event;
esp_netif_t *netif;
} queue_message;
typedef struct
{
state_machine_t Machine; //!< Abstract state machine
const state_t* source_state;
bool ethernet_connected;
TimerHandle_t state_timer;
uint32_t STA_duration;
int32_t total_connected_time;
int64_t last_connected;
uint16_t num_disconnect;
uint16_t retries;
bool wifi_connected;
esp_netif_t *wifi_netif;
esp_netif_t *eth_netif;
esp_netif_t *wifi_ap_netif;
queue_message * event_parameters;
} network_t;
/*
* --------------------- External function prototype ---------------------
*/
void network_start();
network_t * network_get_state_machine();
void network_event_simple(network_event_t trigger);
void network_event(network_event_t trigger, void* param);
void network_async_event(network_event_t trigger, void* param);
void network_async(network_event_t trigger);
void network_async_fail();
void network_async_success();
void network_async_link_up();
void network_async_link_down();
void network_async_configure();
void network_async_got_ip();
void network_async_timer();
void network_async_start();
void network_async_scan();
void network_async_scan_done();
void network_async_connect(const char * ssid, const char * password);
void network_async_lost_connection(wifi_event_sta_disconnected_t * disconnected_event);
void network_async_reboot(reboot_type_t rtype);
void network_reboot_ota(char* url);
void network_async_delete();
void network_async_update_status();
void network_async_eth_got_ip();
void network_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
bool network_is_interface_connected(esp_netif_t * interface);
/*
* --------------------- Inline functions ---------------------
*/
/**
* @brief Defines the maximum size of a SSID name. 32 is IEEE standard.
* @warning limit is also hard coded in wifi_config_t. Never extend this value.
@@ -149,96 +297,23 @@ extern "C" {
*/
#define DEFAULT_STA_POWER_SAVE WIFI_PS_MIN_MODEM
/**
* @brief Defines the maximum length in bytes of a JSON representation of an access point.
*
* maximum ap string length with full 32 char ssid: 75 + \\n + \0 = 77\n
* example: {"ssid":"abcdefghijklmnopqrstuvwxyz012345","chan":12,"rssi":-100,"auth":4},\n
* BUT: we need to escape JSON. Imagine a ssid full of \" ? so it's 32 more bytes hence 77 + 32 = 99.\n
* this is an edge case but I don't think we should crash in a catastrophic manner just because
* someone decided to have a funny wifi name.
*/
#define JSON_ONE_APP_SIZE 99
/**
* @brief Defines the complete list of all messages that the wifi_manager can process.
*
* Some of these message are events ("EVENT"), and some of them are action ("ORDER")
* Each of these messages can trigger a callback function and each callback function is stored
* in a function pointer array for convenience. Because of this behavior, it is extremely important
* to maintain a strict sequence and the top level special element 'MESSAGE_CODE_COUNT'
*
* @see wifi_manager_set_callback
*/
typedef enum message_code_t {
NONE = 0,
ORDER_START_HTTP_SERVER = 1,
ORDER_STOP_HTTP_SERVER = 2,
ORDER_START_DNS_SERVICE = 3,
ORDER_STOP_DNS_SERVICE = 4,
ORDER_START_WIFI_SCAN = 5,
ORDER_LOAD_AND_RESTORE_STA = 6,
ORDER_CONNECT_STA = 7,
ORDER_DISCONNECT_STA = 8,
ORDER_START_AP = 9,
ORDER_START_HTTP = 10,
ORDER_START_DNS_HIJACK = 11,
EVENT_STA_DISCONNECTED = 12,
EVENT_SCAN_DONE = 13,
EVENT_GOT_IP = 14,
ORDER_RESTART_OTA = 15,
ORDER_RESTART_RECOVERY = 16,
ORDER_RESTART_OTA_URL = 17,
ORDER_RESTART = 18,
ORDER_UPDATE_STATUS = 19,
EVENT_ETH_GOT_IP = 20,
EVENT_ETH_TIMEOUT = 21,
EVENT_ETH_LINK_UP = 22,
EVENT_ETH_LINK_DOWN = 23,
MESSAGE_CODE_COUNT = 24 /* important for the callback array */
}message_code_t;
/* @brief indicate that the ESP32 is currently connected. */
extern const int WIFI_MANAGER_WIFI_CONNECTED_BIT;
extern const int WIFI_MANAGER_AP_STA_CONNECTED_BIT;
/* @brief Set automatically once the SoftAP is started */
extern const int WIFI_MANAGER_AP_STARTED_BIT;
/* @brief When set, means a client requested to connect to an access point.*/
extern const int WIFI_MANAGER_REQUEST_STA_CONNECT_BIT;
/* @brief This bit is set automatically as soon as a connection was lost */
extern const int WIFI_MANAGER_STA_DISCONNECT_BIT ;
/* @brief When set, means the wifi manager attempts to restore a previously saved connection at startup. */
extern const int WIFI_MANAGER_REQUEST_RESTORE_STA_BIT ;
/* @brief When set, means a client requested to disconnect from currently connected AP. */
extern const int WIFI_MANAGER_REQUEST_WIFI_DISCONNECT_BIT ;
/* @brief When set, means a scan is in progress */
extern const int WIFI_MANAGER_SCAN_BIT ;
/* @brief When set, means user requested for a disconnect */
extern const int WIFI_MANAGER_REQUEST_DISCONNECT_BIT ;
/* @brief When set, means user requested connecting to a new network and it failed */
extern const int WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT ;
void network_manager_reboot_ota(char * url);
void network_reboot_ota(char * url);
/**
* @brief simplified reason codes for a lost connection.
*
* esp-idf maintains a big list of reason codes which in practice are useless for most typical application.
* UPDATE_CONNECTION_OK - Web UI expects this when attempting to connect to a new access point succeeds
* UPDATE_FAILED_ATTEMPT - Web UI expects this when attempting to connect to a new access point fails
* UPDATE_USER_DISCONNECT = 2,
* UPDATE_LOST_CONNECTION = 3,
* UPDATE_FAILED_ATTEMPT_AND_RESTORE - Web UI expects this when attempting to connect to a new access point fails and previous connection is restored
* UPDATE_ETHERNET_CONNECTED = 5
*/
typedef enum update_reason_code_t {
UPDATE_CONNECTION_OK = 0,
UPDATE_CONNECTION_OK = 0, // expected when
UPDATE_FAILED_ATTEMPT = 1,
UPDATE_USER_DISCONNECT = 2,
UPDATE_LOST_CONNECTION = 3,
@@ -247,33 +322,6 @@ typedef enum update_reason_code_t {
}update_reason_code_t;
typedef enum connection_request_made_by_code_t{
CONNECTION_REQUEST_NONE = 0,
CONNECTION_REQUEST_USER = 1,
CONNECTION_REQUEST_AUTO_RECONNECT = 2,
CONNECTION_REQUEST_RESTORE_CONNECTION = 3,
CONNECTION_REQUEST_MAX_FAILED = 4,
CONNECTION_REQUEST_MAX = 0x7fffffff /*force the creation of this enum as a 32 bit int */
}connection_request_made_by_code_t;
/**
* The wifi manager settings in use
*/
//struct wifi_settings_t{
// bool sta_only;
// bool sta_static_ip;
// wifi_ps_type_t sta_power_save;
// tcpip_adapter_ip_info_t sta_static_ip_config;
//};
//extern struct wifi_settings_t wifi_settings;
// /**
// * @brief Structure used to store one message in the queue.
// */
// typedef struct{
// message_code_t code;
// void *param;
// } queue_message;
@@ -284,59 +332,95 @@ typedef enum connection_request_made_by_code_t{
/**
* Frees up all memory allocated by the wifi_manager and kill the task.
*/
void network_manager_destroy();
void network_destroy();
/**
* Filters the AP scan list to unique SSIDs
*/
void filter_unique( wifi_ap_record_t * aplist, uint16_t * ap_num);
/**
* Main task for the wifi_manager
*/
void network_manager( void * pvParameters );
char* wifi_manager_alloc_get_ap_list_json();
cJSON * wifi_manager_clear_ap_list_json(cJSON **old);
char* network_status_alloc_get_ap_list_json();
cJSON * network_manager_clear_ap_list_json(cJSON **old);
/**
* @brief A standard wifi event handler as recommended by Espressif
*/
esp_err_t wifi_manager_event_handler(void *ctx, system_event_t *event);
esp_err_t network_manager_event_handler(void *ctx, system_event_t *event);
/**
* @brief Clears the connection status json.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful.
* @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/
cJSON * wifi_manager_clear_ip_info_json(cJSON **old);
cJSON * wifi_manager_get_new_json(cJSON **old);
cJSON * network_status_clear_ip_info_json(cJSON **old);
cJSON * network_status_get_new_json(cJSON **old);
/**
* @brief Start the mDNS service
*/
void wifi_manager_initialise_mdns();
void network_manager_initialise_mdns();
/**
* @brief Register a callback to a custom function when specific event message_code happens.
* @brief Register a callback to a custom function when specific network manager states are reached.
*/
void wifi_manager_set_callback(message_code_t message_code, void (*func_ptr)(void*) );
esp_err_t network_register_state_callback(nm_state_t state, int sub_state, const char* from, network_status_reached_cb cb);
bool network_is_wifi_prioritized();
esp_netif_t * network_get_active_interface();
esp_err_t network_get_hostname( const char **hostname);
esp_err_t network_get_ip_info(tcpip_adapter_ip_info_t* ipInfo);
void network_set_timer(uint16_t duration);
void network_set_hostname(esp_netif_t * netif);
esp_err_t network_get_ip_info_for_netif(esp_netif_t* netif, tcpip_adapter_ip_info_t* ipInfo);
void network_start_stop_dhcp(esp_netif_t* netif, bool start);
void network_start_stop_dhcps(esp_netif_t* netif, bool start);
void network_prioritize_wifi(bool activate);
#define ADD_ROOT_FORWARD_DECLARATION(name, ...) ADD_STATE_FORWARD_DECLARATION_(name)
#define ADD_ROOT_LEAF_FORWARD_DECLARATION(name, ...) ADD_STATE_FORWARD_DECLARATION_(name)
#define ADD_LEAF_FORWARD_DECLARATION(name, ...) ADD_STATE_FORWARD_DECLARATION_(name)
#define ADD_STATE_FORWARD_DECLARATION_(name) \
static state_machine_result_t name##_handler(state_machine_t* const State_Machine); \
static state_machine_result_t name##_entry_handler(state_machine_t* const State_Machine); \
static state_machine_result_t name##_exit_handler(state_machine_t* const State_Machine);
void initialize_network_handlers(state_machine_t* state_machine);
void network_manager_format_from_to_states(esp_log_level_t level, const char* prefix, state_t const * from_state, state_t const* current_state, network_event_t event,bool show_source, const char * caller );
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) ;
char* network_manager_alloc_get_mac_string(uint8_t mac[6]);
bool network_manager_is_flag_set(EventBits_t bit);
void network_manager_set_flag(EventBits_t bit);
void network_manager_clear_flag(EventBits_t bit);
#if defined(LOG_LOCAL_LEVEL) && LOG_LOCAL_LEVEL >=ESP_LOG_VERBOSE
#define NETWORK_PRINT_TRANSITION(begin, prefix, source,target, event, print_source,caller ) network_manager_format_from_to_states(ESP_LOG_VERBOSE, prefix, source,target, event, print_source,caller )
#define NETWORK_DEBUG_STATE_MACHINE(begin, cb_prefix,state_machine,print_from,caller) network_manager_format_state_machine(ESP_LOG_DEBUG,cb_prefix,state_machine,print_from,caller)
#define NETWORK_EXECUTE_CB(mch) network_execute_cb(mch,__FUNCTION__);
#define network_handler_entry_print(State_Machine, begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"ENTRY START":"ENTRY END",State_Machine,false,__FUNCTION__)
#define network_exit_handler_print(State_Machine, begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"EXIT START":"END END",State_Machine,false,__FUNCTION__)
#define network_handler_print(State_Machine, begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"HANDLER START":"HANDLER END",State_Machine,false,__FUNCTION__)
#elif defined(LOG_LOCAL_LEVEL) && LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG
#define network_handler_entry_print(State_Machine, begin) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"BEGIN ENTRY":"END ENTRY",State_Machine,false,__FUNCTION__)
#define network_exit_handler_print(State_Machine, begin) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"BEGIN EXIT":"END EXIT",State_Machine,false,__FUNCTION__)
#define network_handler_print(State_Machine, begin) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,begin?"HANDLER START":"HANDLER END",State_Machine,false,__FUNCTION__)
#define NETWORK_PRINT_TRANSITION(begin, prefix, source,target, event, print_source,caller ) if(begin) network_manager_format_from_to_states(ESP_LOG_DEBUG, prefix, source,target, event, print_source,caller )#define NETWORK_EXECUTE_CB(mch) network_execute_cb(mch,__FUNCTION__);
#define NETWORK_DEBUG_STATE_MACHINE(begin, cb_prefix,state_machine,print_from,caller) if(begin) network_manager_format_state_machine(ESP_LOG_DEBUG,cb_prefix,state_machine,print_from,caller)
#else
#define network_exit_handler_print(nm, begin)
#define network_handler_entry_print(State_Machine, begin)
#define network_handler_print(State_Machine, begin)
#define NETWORK_EXECUTE_CB(mch) network_execute_cb(mch,NULL)
#define NETWORK_PRINT_TRANSITION(prefix, source,target, event, print_source,caller )
#define NETWORK_DEBUG_STATE_MACHINE(begin, cb_prefix,state_machine,print_from,caller)
#endif
#ifdef __cplusplus
}
#endif
#endif /* WIFI_MANAGER_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,7 @@
#ifdef NETWORK_STATUS_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_STATUS_LOG_LEVEL
#endif
#include "network_status.h"
#include <string.h>
#include "bt_app_core.h"
@@ -16,10 +20,12 @@
#define CONFIG_SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases"
#endif
static const char TAG[] = "network_status";
SemaphoreHandle_t wifi_manager_json_mutex = NULL;
SemaphoreHandle_t wifi_manager_sta_ip_mutex = NULL;
SemaphoreHandle_t network_status_json_mutex = NULL;
static TaskHandle_t network_json_locked_task = NULL;
SemaphoreHandle_t network_status_ip_address_mutex = NULL;
static TaskHandle_t network_status_ip_address_locked_task = NULL;
char* release_url = NULL;
char* wifi_manager_sta_ip = NULL;
char* network_status_ip_address = NULL;
char* ip_info_json = NULL;
cJSON* ip_info_cjson = NULL;
static char lms_server_ip[IP4ADDR_STRLEN_MAX] = {0};
@@ -33,11 +39,11 @@ void init_network_status() {
chained_notify = server_notify;
server_notify = connect_notify;
ESP_LOGD(TAG, "init_network_status. Creating mutexes");
wifi_manager_json_mutex = xSemaphoreCreateMutex();
wifi_manager_sta_ip_mutex = xSemaphoreCreateMutex();
network_status_json_mutex = xSemaphoreCreateMutex();
network_status_ip_address_mutex = xSemaphoreCreateMutex();
ip_info_json = NULL;
ESP_LOGD(TAG, "init_network_status. Creating status json structure");
ip_info_cjson = wifi_manager_clear_ip_info_json(&ip_info_cjson);
ip_info_cjson = network_status_clear_ip_info_json(&ip_info_cjson);
ESP_LOGD(TAG, "Getting release url ");
char* release_url = (char*)config_alloc_get_default(NVS_TYPE_STR, "release_url", QUOTE(CONFIG_SQUEEZELITE_ESP32_RELEASE_URL), 0);
if (release_url == NULL) {
@@ -46,57 +52,73 @@ void init_network_status() {
ESP_LOGD(TAG, "Found release url %s", release_url);
}
ESP_LOGD(TAG, "About to set the STA IP String to 0.0.0.0");
wifi_manager_sta_ip = (char*)malloc(STA_IP_LEN);
wifi_manager_safe_update_sta_ip_string(NULL);
network_status_ip_address = (char*)malloc_init_external(STA_IP_LEN);
network_status_safe_update_sta_ip_string(NULL);
}
void destroy_network_status() {
FREE_AND_NULL(release_url);
FREE_AND_NULL(ip_info_json);
FREE_AND_NULL(wifi_manager_sta_ip);
FREE_AND_NULL(network_status_ip_address);
cJSON_Delete(ip_info_cjson);
vSemaphoreDelete(wifi_manager_json_mutex);
wifi_manager_json_mutex = NULL;
vSemaphoreDelete(wifi_manager_sta_ip_mutex);
wifi_manager_sta_ip_mutex = NULL;
vSemaphoreDelete(network_status_json_mutex);
network_status_json_mutex = NULL;
vSemaphoreDelete(network_status_ip_address_mutex);
network_status_ip_address_mutex = NULL;
ip_info_cjson = NULL;
}
cJSON* wifi_manager_get_new_json(cJSON** old) {
ESP_LOGV(TAG, "wifi_manager_get_new_json called");
cJSON* network_status_get_new_json(cJSON** old) {
ESP_LOGV(TAG, "network_status_get_new_json called");
cJSON* root = *old;
if (root != NULL) {
cJSON_Delete(root);
*old = NULL;
}
ESP_LOGV(TAG, "wifi_manager_get_new_json done");
ESP_LOGV(TAG, "network_status_get_new_json done");
return cJSON_CreateObject();
}
cJSON* wifi_manager_clear_ip_info_json(cJSON** old) {
ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json called");
cJSON* root = wifi_manager_get_basic_info(old);
ESP_LOGV(TAG, "wifi_manager_clear_ip_info_json done");
cJSON* network_status_clear_ip_info_json(cJSON** old) {
ESP_LOGV(TAG, "network_status_clear_ip_info_json called");
cJSON* root = network_status_get_basic_info(old);
cJSON_DeleteItemFromObjectCaseSensitive(root, "ip");
cJSON_DeleteItemFromObjectCaseSensitive(root, "netmask");
cJSON_DeleteItemFromObjectCaseSensitive(root, "gw");
cJSON_DeleteItemFromObjectCaseSensitive(root, "rssi");
cJSON_DeleteItemFromObjectCaseSensitive(root, "ssid");
cJSON_DeleteItemFromObjectCaseSensitive(root, "eth");
ESP_LOGV(TAG, "network_status_clear_ip_info_json done");
return root;
}
void network_status_clear_ip() {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) {
ip_info_cjson = wifi_manager_clear_ip_info_json(&ip_info_cjson);
wifi_manager_unlock_json_buffer();
if (network_status_lock_json_buffer(portMAX_DELAY)) {
ip_info_cjson = network_status_clear_ip_info_json(&ip_info_cjson);
network_status_unlock_json_buffer();
}
}
char* wifi_manager_alloc_get_ip_info_json() {
char* network_status_alloc_get_ip_info_json() {
return cJSON_PrintUnformatted(ip_info_cjson);
}
void wifi_manager_unlock_json_buffer() {
void network_status_unlock_json_buffer() {
ESP_LOGV(TAG, "Unlocking json buffer!");
xSemaphoreGive(wifi_manager_json_mutex);
network_json_locked_task = NULL;
xSemaphoreGive(network_status_json_mutex);
}
bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait) {
bool network_status_lock_json_buffer(TickType_t xTicksToWait) {
ESP_LOGV(TAG, "Locking json buffer");
if (wifi_manager_json_mutex) {
if (xSemaphoreTake(wifi_manager_json_mutex, xTicksToWait) == pdTRUE) {
TaskHandle_t calling_task = xTaskGetCurrentTaskHandle();
if (calling_task == network_json_locked_task) {
ESP_LOGV(TAG, "json buffer already locked to current task");
return true;
}
if (network_status_json_mutex) {
if (xSemaphoreTake(network_status_json_mutex, xTicksToWait) == pdTRUE) {
ESP_LOGV(TAG, "Json buffer locked!");
network_json_locked_task = calling_task;
return true;
} else {
ESP_LOGE(TAG, "Semaphore take failed. Unable to lock json buffer mutex");
@@ -108,9 +130,15 @@ bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait) {
}
}
bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait) {
if (wifi_manager_sta_ip_mutex) {
if (xSemaphoreTake(wifi_manager_sta_ip_mutex, xTicksToWait) == pdTRUE) {
bool network_status_lock_sta_ip_string(TickType_t xTicksToWait) {
TaskHandle_t calling_task = xTaskGetCurrentTaskHandle();
if (calling_task == network_status_ip_address_locked_task) {
ESP_LOGD(TAG, "json buffer already locked to current task ");
return true;
}
if (network_status_ip_address_mutex) {
if (xSemaphoreTake(network_status_ip_address_mutex, xTicksToWait) == pdTRUE) {
network_status_ip_address_locked_task = calling_task;
return true;
} else {
return false;
@@ -120,26 +148,27 @@ bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait) {
}
}
void wifi_manager_unlock_sta_ip_string() {
xSemaphoreGive(wifi_manager_sta_ip_mutex);
void network_status_unlock_sta_ip_string() {
network_status_ip_address_locked_task = NULL;
xSemaphoreGive(network_status_ip_address_mutex);
}
void wifi_manager_safe_update_sta_ip_string(esp_ip4_addr_t* ip4) {
if (wifi_manager_lock_sta_ip_string(portMAX_DELAY)) {
strcpy(wifi_manager_sta_ip, ip4 != NULL ? ip4addr_ntoa(ip4) : "0.0.0.0");
ESP_LOGD(TAG, "Set STA IP String to: %s", wifi_manager_sta_ip);
wifi_manager_unlock_sta_ip_string();
void network_status_safe_update_sta_ip_string(esp_ip4_addr_t* ip4) {
if (network_status_lock_sta_ip_string(portMAX_DELAY)) {
strcpy(network_status_ip_address, ip4 != NULL ? ip4addr_ntoa((ip4_addr_t*)ip4) : "0.0.0.0");
ESP_LOGD(TAG, "Set STA IP String to: %s", network_status_ip_address);
network_status_unlock_sta_ip_string();
}
}
void wifi_manager_safe_reset_sta_ip_string() {
if (wifi_manager_lock_sta_ip_string(portMAX_DELAY)) {
strcpy(wifi_manager_sta_ip, "0.0.0.0");
ESP_LOGD(TAG, "Set STA IP String to: %s", wifi_manager_sta_ip);
wifi_manager_unlock_sta_ip_string();
void network_status_safe_reset_sta_ip_string() {
if (network_status_lock_sta_ip_string(portMAX_DELAY)) {
strcpy(network_status_ip_address, "0.0.0.0");
ESP_LOGD(TAG, "Set STA IP String to: %s", network_status_ip_address);
network_status_unlock_sta_ip_string();
}
}
char* wifi_manager_get_sta_ip_string() {
return wifi_manager_sta_ip;
char* network_status_get_sta_ip_string() {
return network_status_ip_address;
}
void set_lms_server_details(in_addr_t ip, u16_t hport, u16_t cport) {
strncpy(lms_server_ip, inet_ntoa(ip), sizeof(lms_server_ip));
@@ -152,98 +181,47 @@ static void connect_notify(in_addr_t ip, u16_t hport, u16_t cport) {
set_lms_server_details(ip, hport, cport);
if (chained_notify)
(*chained_notify)(ip, hport, cport);
network_manager_async_update_status();
network_async_update_status();
}
void wifi_manager_update_basic_info() {
int32_t total_connected_time = 0;
int64_t last_connected = 0;
uint16_t num_disconnect = 0;
network_wifi_get_stats(&total_connected_time, &last_connected, &num_disconnect);
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) {
monitor_gpio_t* mgpio = get_jack_insertion_gpio();
cJSON* voltage = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Voltage");
if (voltage) {
cJSON_SetNumberValue(voltage, battery_value_svc());
}
cJSON* bt_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_status");
if (bt_status) {
cJSON_SetNumberValue(bt_status, bt_app_source_get_a2d_state());
}
cJSON* bt_sub_status = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "bt_sub_status");
if (bt_sub_status) {
cJSON_SetNumberValue(bt_sub_status, bt_app_source_get_media_state());
}
cJSON* jack = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "Jack");
if (jack) {
jack->type = mgpio->gpio >= 0 && jack_inserted_svc() ? cJSON_True : cJSON_False;
}
cJSON* disconnect_count = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "disconnect_count");
if (disconnect_count) {
cJSON_SetNumberValue(disconnect_count, num_disconnect);
}
cJSON* avg_conn_time = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "avg_conn_time");
if (avg_conn_time) {
cJSON_SetNumberValue(avg_conn_time, num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0);
}
if (lms_server_cport > 0) {
cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_cport");
if (value) {
cJSON_SetNumberValue(value, lms_server_cport);
} else {
cJSON_AddNumberToObject(ip_info_cjson, "lms_cport", lms_server_cport);
}
}
if (lms_server_port > 0) {
cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_port");
if (value) {
cJSON_SetNumberValue(value, lms_server_port);
} else {
cJSON_AddNumberToObject(ip_info_cjson, "lms_port", lms_server_port);
}
}
if (strlen(lms_server_ip) > 0) {
cJSON* value = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "lms_ip");
if (!value) {
// only create if it does not exist. Since we're creating a reference
// to a char buffer, updates to cJSON aren't needed
cJSON_AddItemToObject(ip_info_cjson, "lms_ip", cJSON_CreateStringReference(lms_server_ip));
}
}
if (network_ethernet_enabled()) {
cJSON* eth = cJSON_GetObjectItemCaseSensitive(ip_info_cjson, "eth_up");
if (eth) {
eth->type = network_ethernet_is_up() ? cJSON_True : cJSON_False;
}
}
wifi_manager_unlock_json_buffer();
}
void network_status_update_basic_info() {
// locking happens below this level
network_status_get_basic_info(&ip_info_cjson);
}
cJSON* network_status_update_string(cJSON** root, const char* key, const char* value) {
if (*root == NULL) {
*root = cJSON_CreateObject();
}
if (network_status_lock_json_buffer(portMAX_DELAY)) {
if (*root == NULL) {
*root = cJSON_CreateObject();
if (*root == NULL) {
ESP_LOGE(TAG, "Error creating cJSON object!");
}
}
if (!key || !value || strlen(key) == 0)
return *root;
cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key);
if (cjsonvalue && strcasecmp(cJSON_GetStringValue(cjsonvalue), value) != 0) {
ESP_LOGD(TAG, "Value %s changed from %s to %s", key, cJSON_GetStringValue(cjsonvalue), value);
cJSON_SetValuestring(cjsonvalue, value);
if (!key || !value || strlen(key) == 0) {
ESP_LOGE(TAG, "network_status_update_string. Invalid key or value passed! key: %s, value: %s", STR_OR_ALT(key, ""), STR_OR_ALT(value, ""));
network_status_unlock_json_buffer();
return *root;
}
cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key);
if (cjsonvalue && strcasecmp(cJSON_GetStringValue(cjsonvalue), value) != 0) {
ESP_LOGD(TAG, "Value %s changed from %s to %s", key, cJSON_GetStringValue(cjsonvalue), value);
cJSON_SetValuestring(cjsonvalue, value);
} else {
cJSON_AddItemToObject(*root, key, cJSON_CreateString(value));
}
network_status_unlock_json_buffer();
} else {
cJSON_AddItemToObject(*root, key, cJSON_CreateString(value));
ESP_LOGW(TAG, "Unable to lock status json buffer. ");
}
return *root;
}
cJSON* network_status_update_number(cJSON** root, const char* key, int value) {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) {
if (network_status_lock_json_buffer(portMAX_DELAY)) {
if (*root == NULL) {
*root = cJSON_CreateObject();
}
if (key && value && strlen(key) != 0) {
if (key && strlen(key) != 0) {
cJSON* cjsonvalue = cJSON_GetObjectItemCaseSensitive(*root, key);
if (cjsonvalue) {
cJSON_SetNumberValue(cjsonvalue, value);
@@ -251,14 +229,14 @@ cJSON* network_status_update_number(cJSON** root, const char* key, int value) {
cJSON_AddNumberToObject(*root, key, value);
}
}
wifi_manager_unlock_json_buffer();
network_status_unlock_json_buffer();
} else {
ESP_LOGW(TAG, "Unable to lock status json buffer. ");
}
return *root;
}
cJSON* network_status_update_float(cJSON** root, const char* key, float value) {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) {
if (network_status_lock_json_buffer(portMAX_DELAY)) {
if (*root == NULL) {
*root = cJSON_CreateObject();
}
@@ -271,14 +249,14 @@ cJSON* network_status_update_float(cJSON** root, const char* key, float value) {
cJSON_AddNumberToObject(*root, key, value);
}
}
wifi_manager_unlock_json_buffer();
network_status_unlock_json_buffer();
} else {
ESP_LOGW(TAG, "Unable to lock status json buffer. ");
}
return *root;
}
cJSON* network_status_update_bool(cJSON** root, const char* key, bool value) {
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) {
if (network_status_lock_json_buffer(portMAX_DELAY)) {
if (*root == NULL) {
*root = cJSON_CreateObject();
}
@@ -291,91 +269,110 @@ cJSON* network_status_update_bool(cJSON** root, const char* key, bool value) {
cJSON_AddBoolToObject(*root, key, value);
}
}
wifi_manager_unlock_json_buffer();
network_status_unlock_json_buffer();
} else {
ESP_LOGW(TAG, "Unable to lock status json buffer. ");
}
return *root;
}
cJSON* wifi_manager_get_basic_info(cJSON** old) {
int32_t total_connected_time = 0;
int64_t last_connected = 0;
uint16_t num_disconnect = 0;
network_wifi_get_stats(&total_connected_time, &last_connected, &num_disconnect);
cJSON* network_status_get_basic_info(cJSON** old) {
if (network_status_lock_json_buffer(portMAX_DELAY)) {
network_t* nm = network_get_state_machine();
monitor_gpio_t* mgpio = get_jack_insertion_gpio();
const esp_app_desc_t* desc = esp_ota_get_app_description();
monitor_gpio_t* mgpio = get_jack_insertion_gpio();
const esp_app_desc_t* desc = esp_ota_get_app_description();
ESP_LOGV(TAG, "wifi_manager_get_basic_info called");
cJSON* root = network_status_update_string(&root, "project_name", desc->project_name);
*old = network_status_update_string(old, "project_name", desc->project_name);
#ifdef CONFIG_FW_PLATFORM_NAME
root = network_status_update_string(&root, "platform_name", CONFIG_FW_PLATFORM_NAME);
*old = network_status_update_string(old, "platform_name", CONFIG_FW_PLATFORM_NAME);
#endif
root = network_status_update_string(&root, "version", desc->version);
if (release_url != NULL)
root = network_status_update_string(&root, "release_url", release_url);
root = network_status_update_number(&root, "recovery", is_recovery_running ? 1 : 0);
root = network_status_update_bool(&root, "Jack", mgpio->gpio >= 0 && jack_inserted_svc());
root = network_status_update_float(&root, "Voltage", battery_value_svc());
root = network_status_update_number(&root, "disconnect_count", num_disconnect);
root = network_status_update_float(&root, "avg_conn_time", num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0);
root = network_status_update_number(&root, "bt_status", bt_app_source_get_a2d_state());
root = network_status_update_number(&root, "bt_sub_status", bt_app_source_get_media_state());
*old = network_status_update_string(old, "version", desc->version);
if (release_url != NULL)
*old = network_status_update_string(old, "release_url", release_url);
*old = network_status_update_number(old, "recovery", is_recovery_running ? 1 : 0);
*old = network_status_update_bool(old, "Jack", mgpio->gpio >= 0 && jack_inserted_svc());
*old = network_status_update_float(old, "Voltage", battery_value_svc());
*old = network_status_update_number(old, "disconnect_count", nm->num_disconnect);
*old = network_status_update_float(old, "avg_conn_time", nm->num_disconnect > 0 ? (nm->total_connected_time / nm->num_disconnect) : 0);
*old = network_status_update_number(old, "bt_status", bt_app_source_get_a2d_state());
*old = network_status_update_number(old, "bt_sub_status", bt_app_source_get_media_state());
#if CONFIG_I2C_LOCKED
root = network_status_update_bool(&root, "is_i2c_locked", true);
*old = network_status_update_bool(old, "is_i2c_locked", true);
#else
root = network_status_update_bool(&root, "is_i2c_locked", false);
*old = network_status_update_bool(old, "is_i2c_locked", false);
#endif
if (network_ethernet_enabled()) {
root = network_status_update_bool(&root, "eth_up", network_ethernet_is_up());
}
ESP_LOGV(TAG, "wifi_manager_get_basic_info done");
return root;
}
if (network_ethernet_enabled()) {
*old = network_status_update_bool(old, "eth_up", network_ethernet_is_up());
}
if (lms_server_cport > 0) {
*old = network_status_update_number(old, "lms_cport", lms_server_cport);
}
void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code) {
ESP_LOGD(TAG, "wifi_manager_generate_ip_info_json called");
if (lms_server_port > 0) {
*old = network_status_update_number(old, "lms_port", lms_server_port);
}
if (wifi_manager_lock_json_buffer(portMAX_DELAY)) {
/* generate the connection info with success */
ip_info_cjson = wifi_manager_get_basic_info(&ip_info_cjson);
wifi_manager_unlock_json_buffer();
if (strlen(lms_server_ip) > 0) {
*old = network_status_update_string(old, "lms_ip", lms_server_ip);
}
ESP_LOGV(TAG, "network_status_get_basic_info done");
network_status_unlock_json_buffer();
} else {
ESP_LOGW(TAG, "Unable to lock status json buffer. ");
}
ip_info_cjson = network_status_update_number(&ip_info_cjson, "urc", update_reason_code);
if (update_reason_code == UPDATE_CONNECTION_OK || update_reason_code == UPDATE_ETHERNET_CONNECTED) {
/* rest of the information is copied after the ssid */
tcpip_adapter_ip_info_t ip_info;
esp_netif_get_ip_info(network_wifi_get_interface(), &ip_info);
network_status_update_string(&ip_info_cjson, "ip", ip4addr_ntoa((ip4_addr_t*)&ip_info.ip));
network_status_update_string(&ip_info_cjson, "netmask", ip4addr_ntoa((ip4_addr_t*)&ip_info.netmask));
network_status_update_string(&ip_info_cjson, "gw", ip4addr_ntoa((ip4_addr_t*)&ip_info.gw));
wifi_mode_t mode;
if (esp_wifi_get_mode(&mode) == ESP_OK && (mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA)) {
/* wifi is active, and associated to an AP */
wifi_ap_record_t ap;
esp_wifi_sta_get_ap_info(&ap);
network_status_update_string(&ip_info_cjson, "ssid", ((char*)ap.ssid));
network_status_update_number(&ip_info_cjson, "rssi", ap.rssi);
}
if (network_ethernet_is_up()) {
esp_netif_get_ip_info(network_ethernet_get_interface(), &ip_info);
cJSON* ethernet_ip = cJSON_CreateObject();
cJSON_AddItemToObject(ethernet_ip, "ip", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.ip)));
cJSON_AddItemToObject(ethernet_ip, "netmask", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.netmask)));
cJSON_AddItemToObject(ethernet_ip, "gw", cJSON_CreateString(ip4addr_ntoa((ip4_addr_t*)&ip_info.gw)));
cJSON_AddItemToObject(ip_info_cjson, "eth", ethernet_ip);
}
} else {
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ip");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "netmask");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "gw");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "rssi");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ssid");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "eth");
}
ESP_LOGV(TAG, "wifi_manager_generate_ip_info_json done");
return *old;
}
void network_status_update_address(cJSON* root, esp_netif_ip_info_t* ip_info) {
if (!root || !ip_info) {
ESP_LOGE(TAG, "Cannor update IP address. JSON structure or ip_info is null");
return;
}
network_status_update_string(&root, "ip", ip4addr_ntoa((ip4_addr_t*)&ip_info->ip));
network_status_update_string(&root, "netmask", ip4addr_ntoa((ip4_addr_t*)&ip_info->netmask));
network_status_update_string(&root, "gw", ip4addr_ntoa((ip4_addr_t*)&ip_info->gw));
}
void network_status_update_ip_info(update_reason_code_t update_reason_code) {
ESP_LOGV(TAG, "network_status_update_ip_info called");
esp_netif_ip_info_t ip_info;
if (network_status_lock_json_buffer(portMAX_DELAY)) {
/* generate the connection info with success */
ip_info_cjson = network_status_get_basic_info(&ip_info_cjson);
ip_info_cjson = network_status_update_number(&ip_info_cjson, "urc", update_reason_code);
ESP_LOGD(TAG,"Updating ip info with reason code %d. Checking if Wifi interface is connected",update_reason_code);
if (network_is_interface_connected(network_wifi_get_interface())) {
esp_netif_get_ip_info(network_wifi_get_interface(), &ip_info);
network_status_update_address(ip_info_cjson, &ip_info);
if (!network_wifi_is_ap_mode()) {
/* wifi is active, and associated to an AP */
wifi_ap_record_t ap;
esp_wifi_sta_get_ap_info(&ap);
network_status_update_string(&ip_info_cjson, "ssid", ((char*)ap.ssid));
network_status_update_number(&ip_info_cjson, "rssi", ap.rssi);
}
} else {
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ip");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "netmask");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "gw");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "rssi");
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "ssid");
}
ESP_LOGD(TAG,"Checking if ethernet interface is connected");
if (network_is_interface_connected(network_ethernet_get_interface())) {
cJSON* ethernet_ip = cJSON_GetObjectItem(ip_info_cjson, "eth");
if (!ethernet_ip) {
ethernet_ip = cJSON_CreateObject();
cJSON_AddItemToObject(ip_info_cjson, "eth", ethernet_ip);
}
esp_netif_get_ip_info(network_ethernet_get_interface(), &ip_info);
network_status_update_address(ethernet_ip, &ip_info);
} else {
cJSON_DeleteItemFromObjectCaseSensitive(ip_info_cjson, "eth");
}
network_status_unlock_json_buffer();
} else {
ESP_LOGW(TAG, "Unable to lock status json buffer. ");
}
ESP_LOGV(TAG, "wifi_status_generate_ip_info_json done");
}

View File

@@ -5,7 +5,7 @@
extern "C" {
#endif
char* wifi_manager_alloc_get_ip_info_json();
char* network_status_alloc_get_ip_info_json();
/**
* @brief Tries to get access to json buffer mutex.
*
@@ -21,39 +21,39 @@ char* wifi_manager_alloc_get_ip_info_json();
* @param xTicksToWait The time in ticks to wait for the semaphore to become available.
* @return true in success, false otherwise.
*/
bool wifi_manager_lock_json_buffer(TickType_t xTicksToWait);
bool network_status_lock_json_buffer(TickType_t xTicksToWait);
/**
* @brief Releases the json buffer mutex.
*/
void wifi_manager_unlock_json_buffer();
void network_status_unlock_json_buffer();
bool wifi_manager_lock_sta_ip_string(TickType_t xTicksToWait);
void wifi_manager_unlock_sta_ip_string();
bool network_status_lock_sta_ip_string(TickType_t xTicksToWait);
void network_status_unlock_sta_ip_string();
/**
* @brief gets the string representation of the STA IP address, e.g.: "192.168.1.69"
*/
char* wifi_manager_get_sta_ip_string();
char* network_status_get_sta_ip_string();
/**
* @brief thread safe char representation of the STA IP update
*/
void wifi_manager_safe_update_sta_ip_string(esp_ip4_addr_t * ip4);
void network_status_safe_update_sta_ip_string(esp_ip4_addr_t * ip4);
/**
* @brief Generates the connection status json: ssid and IP addresses.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful.
* @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/
void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code);
void network_status_update_ip_info(update_reason_code_t update_reason_code);
void init_network_status();
void destroy_network_status();
cJSON* wifi_manager_get_basic_info(cJSON** old);
cJSON* network_status_get_basic_info(cJSON** old);
void wifi_manager_update_basic_info();
void network_status_update_basic_info();
void network_status_clear_ip();
void wifi_manager_safe_reset_sta_ip_string();
void network_status_safe_reset_sta_ip_string();
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
extern "C" {
#endif
void init_network_wifi();
esp_netif_t * network_wifi_start();
void destroy_network_wifi();
/**
* @brief saves the current STA wifi config to flash ram storage.
@@ -16,46 +16,59 @@ esp_err_t network_wifi_save_sta_config();
* @brief fetch a previously STA wifi config in the flash ram storage.
* @return true if a previously saved config was found, false otherwise.
*/
bool wifi_manager_fetch_wifi_sta_config();
bool network_wifi_load_wifi_sta_config();
wifi_config_t* wifi_manager_get_wifi_sta_config();
/**
* @brief Registers handler for wifi and ip events
*/
void wifi_manager_register_handlers();
void network_wifi_register_handlers();
/**
* @brief Generates the list of access points after a wifi scan.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful.
* @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/
void wifi_manager_generate_access_points_json(cJSON ** ap_list);
void network_wifi_generate_access_points_json(cJSON ** ap_list);
/**
* @brief Clear the list of access points.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful.
* @note This is not thread-safe and should be called only if network_status_lock_json_buffer call is successful.
*/
void wifi_manager_clear_access_points_json();
void network_wifi_clear_access_points_json();
void wifi_manager_config_ap();
esp_netif_t * network_wifi_config_ap();
void wifi_manager_filter_unique( wifi_ap_record_t * aplist, uint16_t * aps);
esp_err_t wifi_scan_done(queue_message *msg);
esp_err_t network_wifi_start_scan(queue_message *msg);
void network_wifi_filter_unique( wifi_ap_record_t * aplist, uint16_t * aps);
esp_err_t wifi_scan_done();
esp_err_t network_wifi_start_scan();
esp_err_t network_wifi_load_restore(queue_message *msg);
esp_err_t network_wifi_order_connect(queue_message *msg);
esp_err_t network_wifi_disconnected(queue_message *msg);
esp_err_t network_wifi_start_ap(queue_message *msg);
bool wifi_manager_load_wifi_sta_config(wifi_config_t* config );
bool network_wifi_get_config_for_ssid(wifi_config_t* config, const char * ssid);
esp_err_t network_wifi_handle_event(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
esp_err_t network_wifi_connect(wifi_config_t * cfg);
bool is_wifi_up();
wifi_config_t* network_wifi_set_wifi_sta_config(const char * ssid, const char * password) ;
void network_wifi_clear_config();
esp_netif_t *network_wifi_get_interface();
esp_netif_t *network_wifi_get_ap_interface();
bool network_wifi_is_ap_sta_mode();
bool network_wifi_is_sta_mode();
bool network_wifi_is_ap_mode();
bool network_wifi_sta_config_changed();
void network_wifi_get_stats( int32_t * ret_total_connected_time, int64_t * ret_last_connected, uint16_t * ret_num_disconnect);
void network_wifi_global_init();
bool network_wifi_is_known_ap(const char * ssid);
esp_err_t network_wifi_connect(const char * ssid, const char * password);
esp_err_t network_wifi_erase_legacy();
esp_err_t network_wifi_connect_ssid(const char * ssid);
esp_err_t network_wifi_connect_active_ssid();
esp_err_t network_wifi_erase_known_ap();
esp_err_t network_wifi_set_sta_mode();
size_t network_wifi_get_known_count();
esp_err_t network_wifi_built_known_ap_list();
const wifi_sta_config_t* network_wifi_load_active_config();
#ifdef __cplusplus
}
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 901 B

View File

@@ -1,793 +0,0 @@
#include <state_machine.hpp>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include "cmd_system.h"
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
#include "esp_wifi_types.h"
#include "http_server_handlers.h"
#include "messaging.h"
#include "network_ethernet.h"
#include "network_status.h"
#include "network_wifi.h"
#include "state_machine.h"
#include "trace.h"
#include "dns_server.h"
BaseType_t network_manager_task;
/* objects used to manipulate the main queue of events */
QueueHandle_t network_manager_queue;
using namespace stateless;
using namespace std::placeholders;
static const char TAG[] = "network_manager";
static TaskHandle_t task_network_manager = NULL;
TimerHandle_t STA_timer = NULL;
uint32_t STA_duration;
static int32_t total_connected_time = 0;
static int64_t last_connected = 0;
static uint16_t num_disconnect = 0;
void network_wifi_get_stats(int32_t* ret_total_connected_time, int64_t* ret_last_connected, uint16_t* ret_num_disconnect) {
*ret_total_connected_time = total_connected_time;
*ret_last_connected = last_connected;
*ret_num_disconnect = num_disconnect;
}
namespace {
std::ostream& operator<<(std::ostream& os, const state_t s) {
//static const char* name[] = { "idle", "stopped", "started", "running" };
static const char* name[] = {
"initializing",
"global",
"eth_starting",
"eth_active",
"eth_active_linkup",
"eth_active_connected",
"eth_active_linkdown",
"wifi_up",
"wifi_initializing",
"network_manager_async",
"wifi_connecting_scanning",
"wifi_connecting",
"wifi_connected",
"wifi_disconnecting",
"wifi_user_disconnected",
"wifi_connected_waiting_for_ip",
"wifi_connected_scanning",
"wifi_lost_connection",
"wifi_ap_mode",
"wifi_ap_mode_scanning",
"wifi_ap_mode_scan_done",
"wifi_ap_mode_connecting",
"wifi_ap_mode_connected",
"system_rebooting"};
os << name[(int)s];
return os;
}
const char* trigger_to_string(trig_t trigger) {
switch (trigger) {
ENUM_TO_STRING(t_link_up);
ENUM_TO_STRING(t_link_down);
ENUM_TO_STRING(t_configure);
ENUM_TO_STRING(t_got_ip);
ENUM_TO_STRING(t_next);
ENUM_TO_STRING(t_start);
ENUM_TO_STRING(t_scan);
ENUM_TO_STRING(t_fail);
ENUM_TO_STRING(t_success);
ENUM_TO_STRING(t_scan_done);
ENUM_TO_STRING(t_connect);
ENUM_TO_STRING(t_reboot);
ENUM_TO_STRING(t_reboot_url);
ENUM_TO_STRING(t_lost_connection);
ENUM_TO_STRING(t_update_status);
ENUM_TO_STRING(t_disconnect);
default:
break;
}
return "Unknown trigger";
}
std::ostream& operator<<(std::ostream& os, const trig_t & t) {
//static const char* name[] = { "start", "stop", "set_speed", "halt" };
os << trigger_to_string(t);
return os;
}
} // namespace
// namespace stateless
// {
// template<> void print_state<state>(std::ostream& os, const state& s)
// { os << s; }
// template<> void print_trigger<trigger_t_t(std::ostream& os, const trigger& t)
// { os << t; }
// }
// namespace
// {
// class network_manager
// {
// public:
// network_manager()
// : sm_(state_t::initializing)
// ,
// {
//}
// sm_.configure(state_t::idle)
// .permit(trig_t::t_start, state_t::started);
// sm_.configure(state_t::stopped)
// .on_entry([=](const TTransition&) { speed_ = 0; })
// .permit(trig_t::t_halt, state_t::idle);
// sm_.configure(state_t::started)
// .permit(trig_t::t_set_speed, state_t::running)
// .permit(trig_t::t_stop, state_t::stopped);
// sm_.configure(state_t::running)
// .on_entry_from(
// set_speed_trigger_,
// [=](const TTransition& t, int speed) { speed_ = speed; })
// .permit(trig_t::t_stop, state_t::stopped)
// .permit_reentry(trig_t::t_set_speed);
// void start(int speed)
// {
// sm_.fire(trig_t::t_start);
// set_speed(speed);
// }
// void stop()
// {
// sm_.fire(trig_t::t_stop);
// sm_.fire(trig_t::t_halt);
// }
// void set_speed(int speed)
// {
// sm_.fire(set_speed_trigger_, speed);
// }
// std::string print() const
// {
// std::ostringstream oss;
// print(oss);
// return oss.str();
// }
// void print(std::ostream& os) const
// {
// os << "Motor " << sm_ << " speed = " << speed_;
// }
// private:
// //typedef std::shared_ptr<stateless::trigger_with_parameters<trigger_t, int>> TSetSpeedTrigger;
// wifi_config_t * wifi_config;
// TStateMachine sm_;
// ;
// ;
// };
// std::ostream& operator<<(std::ostream& os, const motor& m)
// {
// m.print(os);
// return os;
// }
//}
namespace {
typedef state_machine<state_t, trig_t> TStateMachine;
typedef TStateMachine::TTransition TTransition;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, wifi_config_t*>> TConnectTrigger;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, reboot_type_t>> TRebootTrigger;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, char*>> TRebootOTATrigger;
typedef std::shared_ptr<stateless::trigger_with_parameters<trig_t, wifi_event_sta_disconnected_t*>> TDisconnectTrigger;
}; // namespace
class NetworkManager {
public:
NetworkManager()
: sm_(state_t::instantiated),
connect_trigger_(sm_.set_trigger_parameters<wifi_config_t*>(trig_t::t_connect)),
reboot_trigger_(sm_.set_trigger_parameters<reboot_type_t>(trig_t::t_reboot)),
reboot_ota_(sm_.set_trigger_parameters<char*>(trig_t::t_reboot)),
disconnected_(sm_.set_trigger_parameters<wifi_event_sta_disconnected_t*>(trig_t::t_lost_connection)) {
sm_.configure(state_t::instantiated)
.permit(trig_t::t_start, state_t::initializing);
sm_.configure(state_t::global)
.permit(trig_t::t_reboot, state_t::system_rebooting)
.permit(trig_t::t_reboot_url, state_t::system_rebooting)
.permit_reentry(trig_t::t_update_status)
.on_entry_from(trig_t::t_update_status,
[=](const TTransition& t) {
wifi_manager_update_basic_info();
});
sm_.configure(state_t::system_rebooting)
.on_entry_from(reboot_ota_, [=](const TTransition& t, char* url) {
if (url) {
start_ota(url, NULL, 0);
free(url);
}
})
.on_entry_from(reboot_trigger_, [=](const TTransition& t, reboot_type_t reboot_type) {
switch (reboot_type) {
case reboot_type_t::OTA:
ESP_LOGD(TAG, "Calling guided_restart_ota.");
guided_restart_ota();
break;
case reboot_type_t::RECOVERY:
ESP_LOGD(TAG, "Calling guided_factory.");
guided_factory();
break;
case reboot_type_t::RESTART:
ESP_LOGD(TAG, "Calling simple_restart.");
simple_restart();
break;
default:
break;
}
});
sm_.configure(state_t::initializing)
.on_entry([=](const TTransition& t) {
/* memory allocation */
ESP_LOGD(TAG, "network_manager_start. Creating message queue");
network_manager_queue = xQueueCreate(3, sizeof(queue_message));
ESP_LOGD(TAG, "network_manager_start. Allocating memory for callback functions registration");
// todo: allow registration of event callbacks
ESP_LOGD(TAG, "Initializing tcp_ip adapter");
esp_netif_init();
ESP_LOGD(TAG, "Creating the default event loop");
ESP_ERROR_CHECK(esp_event_loop_create_default());
init_network_status();
ESP_LOGD(TAG, "Initializing network. done");
/* start wifi manager task */
ESP_LOGD(TAG, "Creating network manager task");
network_manager_task = xTaskCreate(&network_manager, "network_manager", 4096, NULL, WIFI_MANAGER_TASK_PRIORITY, &task_network_manager);
// send a message to start the connections
})
.permit(trig_t::t_start, state_t::eth_starting);
sm_.configure(state_t::eth_starting)
.on_entry([=](const TTransition& t) {
/* start http server */
http_server_start();
ESP_LOGD(TAG, "network_manager task started. Configuring Network Interface");
init_network_ethernet();
})
.permit(trig_t::t_fail, state_t::wifi_initializing)
.permit(trig_t::t_success, state_t::eth_active);
sm_.configure(state_t::eth_active)
.permit(trig_t::t_link_up, state_t::eth_active_linkup)
.permit(trig_t::t_got_ip, state_t::eth_active_connected)
.permit(trig_t::t_link_down, state_t::eth_active_linkdown)
.permit(trig_t::t_fail, state_t::wifi_initializing);
sm_.configure(state_t::eth_active_linkup)
.sub_state_of(state_t::eth_active)
.on_entry([=](const TTransition& t) {
// Anything we need to do on link becoming active?
});
sm_.configure(state_t::eth_active_linkdown)
.sub_state_of(state_t::eth_active)
.on_entry([=](const TTransition& t) {
// If not connected after a certain time, start
// wifi
});
sm_.configure(state_t::eth_active_connected)
.sub_state_of(state_t::eth_active)
.on_entry([=](const TTransition& t) {
})
.on_exit([=](const TTransition& t) {
});
sm_.configure(state_t::wifi_up)
.on_entry([=](const TTransition& t) {
})
.on_exit([=](const TTransition& t) {
});
sm_.configure(state_t::wifi_initializing)
.sub_state_of(state_t::wifi_up)
.on_entry([=](const TTransition& t) {
esp_err_t err = ESP_OK;
ESP_LOGD(TAG, "network_wifi_load_restore");
if (!is_wifi_up()) {
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Load Configuration");
return ESP_FAIL;
}
if (wifi_manager_fetch_wifi_sta_config()) {
ESP_LOGI(TAG, "Saved wifi found on startup. Will attempt to connect.");
network_manager_async_connect(wifi_manager_get_wifi_sta_config());
} else {
/* no wifi saved: start soft AP! This is what should happen during a first run */
ESP_LOGD(TAG, "No saved wifi. Starting AP.");
network_manager_async_configure();
}
return err;
})
.permit(trig_t::t_configure, state_t::wifi_ap_mode)
.permit(trig_t::t_connect, state_t::wifi_connecting_scanning);
sm_.configure(state_t::wifi_connecting_scanning)
.sub_state_of(state_t::wifi_up)
.on_entry_from(connect_trigger_, [=](const TTransition& t, wifi_config_t* wifi_config) {
if (network_wifi_connect(wifi_config) == ESP_OK) {
network_manager_async_connect(wifi_config);
} else {
network_manager_async_fail();
}
// STA_duration = STA_POLLING_MIN;
// /* create timer for background STA connection */
// if (!STA_timer) {
// STA_timer = xTimerCreate("background STA", pdMS_TO_TICKS(STA_duration), pdFALSE, NULL, polling_STA);
// }
// setup a timeout here. On timeout,
// check reconnect_attempts and
// fire trig_t::t_scan if we have more attempts to try
// fire trig_t::t_fail otherwise
})
.permit_reentry_if(trig_t::t_scan, [&]() {
return ++reconnect_attempt < 3;
})
.permit(trig_t::t_connect, state_t::wifi_connecting)
.permit(trig_t::t_fail, state_t::wifi_lost_connection);
sm_.configure(state_t::wifi_connecting)
.on_entry_from(connect_trigger_, [=](const TTransition& t, wifi_config_t* wifi_config) {
// setup a timeout here. On timeout,
// check reconnect_attempts and
// fire trig_t::t_wifi_connecting_existing if we have more attempts to try
// fire trig_t::t_fail otherwise
})
.permit(trig_t::t_success, state_t::wifi_connected_waiting_for_ip)
.permit(trig_t::t_got_ip, state_t::wifi_connected)
.permit(trig_t::t_lost_connection, state_t::wifi_ap_mode);
sm_.configure(state_t::wifi_connected_waiting_for_ip)
.permit(trig_t::t_got_ip, state_t::wifi_connected);
sm_.configure(state_t::wifi_ap_mode)
.on_entry([=](const TTransition& t) {
wifi_manager_config_ap();
ESP_LOGD(TAG, "AP Starting, requesting wifi scan.");
network_manager_async_scan();
})
.on_entry_from(disconnected_, [=](const TTransition& t, wifi_event_sta_disconnected_t* disconnected_event) {
if(disconnected_event){
free(disconnected_event);
}
})
.permit(trig_t::t_scan, state_t::wifi_ap_mode_scanning);
sm_.configure(state_t::wifi_ap_mode_scanning)
.on_entry([=](const TTransition& t) {
// build a list of found AP
})
.permit(trig_t::t_scan_done, state_t::wifi_ap_mode_scan_done);
sm_.configure(state_t::wifi_ap_mode_scan_done)
.permit(trig_t::t_connect, state_t::wifi_ap_mode_connecting);
sm_.configure(state_t::wifi_ap_mode_connecting)
.on_entry_from(connect_trigger_, [=](const TTransition& t, wifi_config_t* wifi_config) {
})
.permit(trig_t::t_got_ip, state_t::wifi_ap_mode_connected)
.permit(trig_t::t_fail, state_t::wifi_ap_mode);
sm_.configure(state_t::wifi_ap_mode_connected)
.on_entry([=](const TTransition& t) {
})
.permit(trig_t::t_success, state_t::wifi_connected);
sm_.configure(state_t::wifi_connected)
.on_entry([&](const TTransition& t) {
last_connected = esp_timer_get_time();
/* bring down DNS hijack */
ESP_LOGD(TAG, "Stopping DNS.");
dns_server_stop();
if (network_wifi_sta_config_changed()) {
network_wifi_save_sta_config();
}
/* stop AP mode */
esp_wifi_set_mode(WIFI_MODE_STA);
})
.permit_reentry(trig_t::t_scan_done)
.permit(trig_t::t_lost_connection, state_t::wifi_lost_connection)
.permit(trig_t::t_scan, state_t::wifi_connected_scanning)
.permit(trig_t::t_disconnect, state_t::wifi_disconnecting)
.permit(trig_t::t_connect, state_t::wifi_connecting);
sm_.configure(state_t::wifi_disconnecting)
.permit(trig_t::t_lost_connection, state_t::wifi_user_disconnected);
sm_.configure(state_t::wifi_user_disconnected)
.on_entry_from(disconnected_,
[=](const TTransition& t, wifi_event_sta_disconnected_t* disconnected_event) {
ESP_LOGD(TAG, "WiFi disconnected by user");
network_wifi_clear_config();
wifi_manager_generate_ip_info_json(UPDATE_USER_DISCONNECT);
network_manager_async_configure();
if (disconnected_event) {
free(disconnected_event);
}
})
.permit(trig_t::t_configure, state_t::wifi_ap_mode);
sm_.configure(state_t::wifi_lost_connection)
.on_entry_from(disconnected_,
[=](const TTransition& t, wifi_event_sta_disconnected_t* disconnected_event) {
ESP_LOGE(TAG, "WiFi Connection lost.");
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "WiFi Connection lost");
wifi_manager_generate_ip_info_json(UPDATE_LOST_CONNECTION);
if (last_connected > 0)
total_connected_time += ((esp_timer_get_time() - last_connected) / (1000 * 1000));
last_connected = 0;
num_disconnect++;
ESP_LOGW(TAG, "Wifi disconnected. Number of disconnects: %d, Average time connected: %d", num_disconnect, num_disconnect > 0 ? (total_connected_time / num_disconnect) : 0);
//network_manager_async_connect(wifi_manager_get_wifi_sta_config());
if (retries < WIFI_MANAGER_MAX_RETRY) {
ESP_LOGD(TAG, "Issuing ORDER_CONNECT_STA to retry connection.");
retries++;
network_manager_async_connect(wifi_manager_get_wifi_sta_config());
free(disconnected_event);
} else {
/* In this scenario the connection was lost beyond repair: kick start the AP! */
retries = 0;
wifi_mode_t mode;
ESP_LOGW(TAG, "All connect retry attempts failed.");
/* put us in softAP mode first */
esp_wifi_get_mode(&mode);
if (WIFI_MODE_APSTA != mode) {
STA_duration = STA_POLLING_MIN;
network_manager_async_lost_connection(disconnected_event);
} else if (STA_duration < STA_POLLING_MAX) {
STA_duration *= 1.25;
free(disconnected_event);
}
/* keep polling for existing connection */
xTimerChangePeriod(STA_timer, pdMS_TO_TICKS(STA_duration), portMAX_DELAY);
xTimerStart(STA_timer, portMAX_DELAY);
ESP_LOGD(TAG, "STA search slow polling of %d", STA_duration);
}
})
.on_entry([=](const TTransition& t) {
wifi_manager_safe_reset_sta_ip_string();
})
.permit(trig_t::t_connect, state_t::wifi_connecting)
.permit(trig_t::t_lost_connection, state_t::wifi_ap_mode);
// Register a callback for state transitions (the default does nothing).
sm_.on_transition([](const TTransition& t) {
std::cout << "transition from [" << t.source() << "] to ["
<< t.destination() << "] via trigger [" << t.trigger() << "]"
<< std::endl;
});
// Override the default behaviour of throwing when a trigger is unhandled.
sm_.on_unhandled_trigger([](const state_t s, const trig_t t) {
std::cerr << "ignore unhandled trigger [" << t << "] in state [" << s
<< "]" << std::endl;
});
}
public:
bool
Allowed(trig_t trigger) {
if (!sm_.can_fire(trigger)) {
ESP_LOGW(TAG, "Network manager might not be able to process trigger %s", trigger_to_string(trigger));
return false;
}
return true;
}
bool Fire(trig_t trigger) {
try {
sm_.fire(trigger);
return true;
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
}
return false;
}
bool Event(queue_message& msg) {
trig_t trigger = msg.trigger;
try {
if (trigger == trig_t::t_connect) {
sm_.fire(connect_trigger_, msg.wifi_config);
} else if (trigger == trig_t::t_reboot) {
sm_.fire(reboot_trigger_, msg.rtype);
} else if (trigger == trig_t::t_reboot_url) {
sm_.fire(reboot_ota_, msg.strval);
} else if (trigger == trig_t::t_lost_connection) {
sm_.fire(disconnected_, msg.disconnected_event);
} else {
sm_.fire(trigger);
}
return true;
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
return false;
}
}
private:
uint8_t reconnect_attempt = 0;
bool existing_connection = false;
uint8_t retries = 0;
TStateMachine sm_;
TConnectTrigger connect_trigger_;
TRebootTrigger reboot_trigger_;
TRebootOTATrigger reboot_ota_;
TDisconnectTrigger disconnected_;
};
NetworkManager nm;
void network_manager_start() {
nm.Fire(trig_t::t_start);
}
bool network_manager_async(trig_t trigger) {
queue_message msg;
msg.trigger = trigger;
if (nm.Allowed(trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
bool network_manager_async_fail() {
return network_manager_async(trig_t::t_fail);
}
bool network_manager_async_success() {
return network_manager_async(trig_t::t_success);
}
bool network_manager_async_link_up() {
return network_manager_async(trig_t::t_link_up);
}
bool network_manager_async_link_down() {
return network_manager_async(trig_t::t_link_down);
}
bool network_manager_async_configure() {
return network_manager_async(trig_t::t_configure);
}
bool network_manager_async_got_ip() {
return network_manager_async(trig_t::t_got_ip);
}
bool network_manager_async_next() {
return network_manager_async(trig_t::t_next);
}
bool network_manager_async_start() {
return network_manager_async(trig_t::t_start);
}
bool network_manager_async_scan() {
return network_manager_async(trig_t::t_scan);
}
bool network_manager_async_update_status() {
return network_manager_async(trig_t::t_update_status);
}
bool network_manager_async_disconnect() {
return network_manager_async(trig_t::t_disconnect);
}
bool network_manager_async_scan_done() {
return network_manager_async(trig_t::t_scan_done);
}
bool network_manager_async_connect(wifi_config_t* wifi_config) {
queue_message msg;
msg.trigger = trig_t::t_connect;
msg.wifi_config = wifi_config;
if (nm.Allowed(msg.trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
bool network_manager_async_lost_connection(wifi_event_sta_disconnected_t* disconnected_event) {
queue_message msg;
msg.trigger = trig_t::t_lost_connection;
msg.disconnected_event = disconnected_event;
if (nm.Allowed(msg.trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
bool network_manager_async_reboot(reboot_type_t rtype) {
queue_message msg;
msg.trigger = trig_t::t_reboot;
msg.rtype = rtype;
if (nm.Allowed(msg.trigger)) {
return xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return false;
}
void network_manager_reboot_ota(char* url) {
queue_message msg;
if (url == NULL) {
msg.trigger = trig_t::t_reboot;
msg.rtype = reboot_type_t::OTA;
} else {
msg.trigger = trig_t::t_reboot_url;
msg.strval = strdup(url);
}
if (nm.Allowed(msg.trigger)) {
xQueueSendToFront(network_manager_queue, &msg, portMAX_DELAY);
}
return;
}
// switch (msg.code) {
// case EVENT_SCAN_DONE:
// err = wifi_scan_done(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code]) {
// ESP_LOGD(TAG, "Invoking SCAN DONE callback");
// (*cb_ptr_arr[msg.code])(NULL);
// ESP_LOGD(TAG, "Done Invoking SCAN DONE callback");
// }
// break;
// case ORDER_START_WIFI_SCAN:
// err = network_wifi_start_scan(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_LOAD_AND_RESTORE_STA:
// err = network_wifi_load_restore(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_CONNECT_STA:
// err = network_wifi_order_connect(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case EVENT_STA_DISCONNECTED:
// err = network_wifi_disconnected(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_START_AP:
// err = network_wifi_start_ap(&msg);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case EVENT_GOT_IP:
// ESP_LOGD(TAG, "MESSAGE: EVENT_GOT_IP");
// /* save IP as a string for the HTTP server host */
// //s->ip_info.ip.addr
// ip_event_got_ip_t* event = (ip_event_got_ip_t*)msg.param;
// wifi_manager_safe_update_sta_ip_string(&(event->ip_info.ip));
// wifi_manager_generate_ip_info_json(network_manager_is_flag_set(WIFI_MANAGER_REQUEST_STA_CONNECT_FAILED_BIT)? UPDATE_FAILED_ATTEMPT_AND_RESTORE : UPDATE_CONNECTION_OK, event->esp_netif, event->ip_changed);
// free(msg.param);
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case UPDATE_CONNECTION_OK:
// messaging_post_message(MESSAGING_ERROR, MESSAGING_CLASS_SYSTEM, "UPDATE_CONNECTION_OK not implemented");
// break;
// case ORDER_DISCONNECT_STA:
// ESP_LOGD(TAG, "MESSAGE: ORDER_DISCONNECT_STA. Calling esp_wifi_disconnect()");
// /* precise this is coming from a user request */
// xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_REQUEST_DISCONNECT_BIT);
// /* order wifi discconect */
// ESP_ERROR_CHECK(esp_wifi_disconnect());
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case ORDER_RESTART_OTA_URL:
// ESP_LOGD(TAG, "Calling start_ota.");
// start_ota(msg.param, NULL, 0);
// free(msg.param);
// break;
// case ORDER_RESTART_RECOVERY:
// break;
// case ORDER_RESTART:
// ESP_LOGD(TAG, "Calling simple_restart.");
// simple_restart();
// break;
// case ORDER_UPDATE_STATUS:
// ;
// break;
// case EVENT_ETH_TIMEOUT:
// ESP_LOGW(TAG, "Ethernet connection timeout. Rebooting with WiFi Active");
// network_manager_reboot(RESTART);
// break;
// case EVENT_ETH_LINK_UP:
// /* callback */
// ESP_LOGD(TAG,"EVENT_ETH_LINK_UP message received");
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// case EVENT_ETH_LINK_DOWN:
// /* callback */
// if (cb_ptr_arr[msg.code])
// (*cb_ptr_arr[msg.code])(NULL);
// break;
// default:
// break;
// } /* end of switch/case */
// if (!network_ethernet_wait_for_link(500)) {
// if(network_ethernet_enabled()){
// ESP_LOGW(TAG, "Ethernet not connected. Starting Wifi");
// }
// init_network_wifi();
// wifi_manager_send_message(ORDER_LOAD_AND_RESTORE_STA, NULL);
// }
void network_manager(void* pvParameters) {
queue_message msg;
esp_err_t err = ESP_OK;
BaseType_t xStatus;
network_manager_async(trig_t::t_start);
/* main processing loop */
for (;;) {
xStatus = xQueueReceive(network_manager_queue, &msg, portMAX_DELAY);
if (xStatus == pdPASS) {
// pass the event to the sync processor
nm.Event(msg);
} /* end of if status=pdPASS */
} /* end of for loop */
vTaskDelete(NULL);
}
void network_manager_destroy() {
vTaskDelete(task_network_manager);
task_network_manager = NULL;
/* heap buffers */
destroy_network_status();
destroy_network_wifi();
destroy_network_status();
/* RTOS objects */
vQueueDelete(network_manager_queue);
network_manager_queue = NULL;
}

View File

@@ -1,108 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#define STA_POLLING_MIN (15 * 1000)
#define STA_POLLING_MAX (10 * 60 * 1000)
//enum class state { idle, stopped, started, running };
//enum class trigger { start, stop, set_speed, halt };
typedef enum {
t_link_up,
t_link_down,
t_configure,
t_got_ip,
t_disconnect,
t_next,
t_start,
t_scan,
t_fail,
t_success,
t_scan_done,
t_connect,
t_reboot,
t_reboot_url,
t_lost_connection,
t_update_status
} trig_t;
typedef enum {
instantiated,
initializing,
global,
eth_starting,
eth_active,
eth_active_linkup,
eth_active_connected,
eth_active_linkdown,
wifi_up,
wifi_initializing,
wifi_connecting_scanning,
wifi_connecting,
wifi_connected,
wifi_disconnecting,
wifi_user_disconnected,
wifi_connected_waiting_for_ip,
wifi_connected_scanning,
wifi_lost_connection,
wifi_ap_mode,
wifi_ap_mode_scanning,
wifi_ap_mode_scan_done,
wifi_ap_mode_connecting,
wifi_ap_mode_connected,
system_rebooting
} state_t;
typedef enum {
OTA,
RECOVERY,
RESTART,
} reboot_type_t;
typedef struct {
trig_t trigger;
union
{
wifi_config_t* wifi_config;
reboot_type_t rtype;
char * strval;
wifi_event_sta_disconnected_t * disconnected_event;
} ;
} queue_message;
bool network_manager_event_simple(trig_t trigger);
bool network_manager_event(trig_t trigger, void* param);
bool network_t_connect_event(wifi_config_t* wifi_config);
bool network_t_link_event(bool link_up);
bool network_manager_async_event(trig_t trigger, void* param);
bool network_manager_async(trig_t trigger);
bool network_manager_async_fail();
bool network_manager_async_success();
bool network_manager_async_link_up();
bool network_manager_async_link_down();
bool network_manager_async_configure();
bool network_manager_async_got_ip();
bool network_manager_async_next();
bool network_manager_async_start();
bool network_manager_async_scan();
bool network_manager_async_scan_done();
bool network_manager_async_connect(wifi_config_t* wifi_config);
bool network_manager_async_lost_connection(wifi_event_sta_disconnected_t * disconnected_event);
bool network_manager_async_reboot(reboot_type_t rtype);
void network_manager_reboot_ota(char* url);
bool network_manager_async_disconnect();
bool network_manager_async_update_status();
/**
* Allocate heap memory for the wifi manager and start the wifi_manager RTOS task
*/
void network_manager_start();
#ifdef __cplusplus
}
#endif

View File

@@ -1,13 +1,13 @@
[
{"ssid":"Pantum-AP-A6D49F","chan":11,"rssi":-55,"auth":4},
{"ssid":"a0308","chan":1,"rssi":-56,"auth":3},
{"ssid":"dlink-D9D8","chan":11,"rssi":-82,"auth":4},
{"ssid":"Linksys06730","chan":7,"rssi":-85,"auth":3},
{"ssid":"SINGTEL-5171","chan":9,"rssi":-88,"auth":4},
{"ssid":"1126-1","chan":11,"rssi":-89,"auth":4},
{"ssid":"The Shah 5GHz-2","chan":1,"rssi":-90,"auth":3},
{"ssid":"SINGTEL-1D28 (2G)","chan":11,"rssi":-91,"auth":3},
{"ssid":"dlink-F864","chan":1,"rssi":-92,"auth":4},
{"ssid":"dlink-74F0","chan":1,"rssi":-93,"auth":4},
{"ssid":"MyTestSSID","chan":2,"rssi":-53,"auth":4}
{"ssid":"Pantum-AP-A6D49F","chan":11,"rssi":-55,"auth":4, "known":false},
{"ssid":"a0308","chan":1,"rssi":-56,"auth":3, "known":false},
{"ssid":"dlink-D9D8","chan":11,"rssi":-82,"auth":4, "known":false},
{"ssid":"Linksys06730","chan":7,"rssi":-85,"auth":3, "known":false},
{"ssid":"SINGTEL-5171","chan":9,"rssi":-88,"auth":4, "known":false},
{"ssid":"1126-1","chan":11,"rssi":-89,"auth":4, "known":false},
{"ssid":"The Shah 5GHz-2","chan":1,"rssi":-90,"auth":3, "known":false},
{"ssid":"SINGTEL-1D28 (2G)","chan":11,"rssi":-91,"auth":3, "known":false},
{"ssid":"dlink-F864","chan":1,"rssi":-92,"auth":4, "known":false},
{"ssid":"dlink-74F0","chan":1,"rssi":-93,"auth":4, "known":false},
{"ssid":"MyTestSSID","chan":2,"rssi":-53,"auth":4, "known":true}
]

View File

@@ -54,7 +54,7 @@
"current_time": 147319
},
{
"message": "Wifi connected",
"message": "Network connected",
"type": "MESSAGING_INFO",
"class": "MESSAGING_CLASS_SYSTEM",
"sent_time": 141256,

View File

@@ -1098,7 +1098,7 @@ function rssiToIcon(rssi) {
}
function refreshAP() {
$.getJSON('/scan.json', async function() {
$.getJSON('/scan.json', async function() {
await sleep(2000);
$.getJSON('/ap.json', function(data) {
if (data.length > 0) {
@@ -1335,6 +1335,7 @@ function handleRecoveryMode(data) {
$('#boot-form').attr('action', '/recovery.json');
}
}
function hasConnectionChanged(data){
// gw: "192.168.10.1"
// ip: "192.168.10.225"
@@ -1366,10 +1367,10 @@ function handleWifiDialog(data){
$('.connecting-status').show();
}
if(SystemConfig.ap_ssid){
$('#apName').text(SystemConfig.ap_ssid);
$('#apName').text(SystemConfig.ap_ssid.value);
}
if(SystemConfig.ap_pwd){
$('#apPass').text(SystemConfig.ap_pwd);
$('#apPass').text(SystemConfig.ap_pwd.value);
}
if(!data)
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

View File

@@ -31,11 +31,13 @@
#include "freertos/task.h"
#include "messaging.h"
#include "platform_esp32.h"
#include "globdefs.h"
#include "trace.h"
static const char TAG[] = "http_server";
static httpd_handle_t _server = NULL;
rest_server_context_t *rest_context = NULL;
RingbufHandle_t messaging=NULL;
EXT_RAM_ATTR static httpd_handle_t _server = NULL;
EXT_RAM_ATTR rest_server_context_t *rest_context = NULL;
EXT_RAM_ATTR RingbufHandle_t messaging=NULL;
void register_common_handlers(httpd_handle_t server){
httpd_uri_t css_get = { .uri = "/css/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
@@ -46,7 +48,6 @@ void register_common_handlers(httpd_handle_t server){
httpd_register_uri_handler(server, &icon_get);
httpd_uri_t png_get = { .uri = "/favicon*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &png_get);
}
void register_regular_handlers(httpd_handle_t server){
httpd_uri_t root_get = { .uri = "/", .method = HTTP_GET, .handler = root_get_handler, .user_ctx = rest_context };
@@ -124,13 +125,17 @@ void register_regular_handlers(httpd_handle_t server){
esp_err_t http_server_start()
{
ESP_LOGI(TAG, "Initializing HTTP Server");
MEMTRACE_PRINT_DELTA_MESSAGE("Registering messaging subscriber");
messaging = messaging_register_subscriber(10, "http_server");
rest_context = calloc(1, sizeof(rest_server_context_t));
MEMTRACE_PRINT_DELTA_MESSAGE("Allocating RAM for server context");
rest_context = malloc_init_external( sizeof(rest_server_context_t));
if(rest_context==NULL){
ESP_LOGE(TAG,"No memory for http context");
return ESP_FAIL;
}
strlcpy(rest_context->base_path, "/res/", sizeof(rest_context->base_path));
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
@@ -141,15 +146,17 @@ esp_err_t http_server_start()
//todo: use the endpoint below to configure session token?
// config.open_fn
ESP_LOGD(TAG, "Starting HTTP Server");
MEMTRACE_PRINT_DELTA_MESSAGE( "Starting HTTP Server");
esp_err_t err= __httpd_start(&_server, &config);
if(err != ESP_OK){
ESP_LOGE_LOC(TAG,"Start server failed");
}
else {
MEMTRACE_PRINT_DELTA_MESSAGE( "HTTP Server started. Registering common handlers");
register_common_handlers(_server);
MEMTRACE_PRINT_DELTA_MESSAGE("Registering regular handlers");
register_regular_handlers(_server);
MEMTRACE_PRINT_DELTA_MESSAGE("HTTP Server regular handlers registered");
}
return err;