From 3929f3e809984c1b0554c2a9bb466987914a0964 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Tue, 26 Nov 2019 08:29:19 -0500 Subject: [PATCH 01/46] Work in progress - move to httpd --- components/wifi-manager/CMakeLists.txt | 2 +- components/wifi-manager/http_server.c | 638 ---------------- .../wifi-manager/http_server_handlers.c | 699 ++++++++++++++++++ .../{http_server.h => http_server_handlers.h} | 20 + components/wifi-manager/wifi_manager.c | 2 +- .../wifi-manager/wifi_manager_http_server.c | 472 ++++++++++++ main/config.c | 27 + main/config.h | 2 + 8 files changed, 1222 insertions(+), 640 deletions(-) delete mode 100644 components/wifi-manager/http_server.c create mode 100644 components/wifi-manager/http_server_handlers.c rename components/wifi-manager/{http_server.h => http_server_handlers.h} (81%) create mode 100644 components/wifi-manager/wifi_manager_http_server.c diff --git a/components/wifi-manager/CMakeLists.txt b/components/wifi-manager/CMakeLists.txt index 4d0b9cb3..deebd64d 100644 --- a/components/wifi-manager/CMakeLists.txt +++ b/components/wifi-manager/CMakeLists.txt @@ -1,7 +1,7 @@ idf_component_register(SRCS "dns_server.c" "http_server.c" "wifi_manager.c" INCLUDE_DIRS . REQUIRES esp_common - PRIV_REQUIRES newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant cmd_system + PRIV_REQUIRES newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant cmd_system esp_http_server EMBED_FILES style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz ) diff --git a/components/wifi-manager/http_server.c b/components/wifi-manager/http_server.c deleted file mode 100644 index 2e96b0d1..00000000 --- a/components/wifi-manager/http_server.c +++ /dev/null @@ -1,638 +0,0 @@ -/* -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 -*/ - -#include "http_server.h" -#include "cmd_system.h" -#include -#include "squeezelite-ota.h" -#include "nvs_utilities.h" -#include -#include -#include "cJSON.h" -#include "esp_system.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "config.h" - -#define HTTP_STACK_SIZE (5*1024) - -/* @brief tag used for ESP serial console messages */ -static const char TAG[] = "http_server"; -/* @brief task handle for the http server */ -static TaskHandle_t task_http_server = NULL; -static StaticTask_t task_http_buffer; -#if RECOVERY_APPLICATION -static StackType_t task_http_stack[HTTP_STACK_SIZE]; -#else -static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE]; -#endif -SemaphoreHandle_t http_server_config_mutex = NULL; - -/** - * @brief embedded binary data. - * @see file "component.mk" - * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data - */ -extern const uint8_t style_css_start[] asm("_binary_style_css_start"); -extern const uint8_t style_css_end[] asm("_binary_style_css_end"); -extern const uint8_t jquery_gz_start[] asm("_binary_jquery_min_js_gz_start"); -extern const uint8_t jquery_gz_end[] asm("_binary_jquery_min_js_gz_end"); -extern const uint8_t popper_gz_start[] asm("_binary_popper_min_js_gz_start"); -extern const uint8_t popper_gz_end[] asm("_binary_popper_min_js_gz_end"); -extern const uint8_t bootstrap_js_gz_start[] asm("_binary_bootstrap_min_js_gz_start"); -extern const uint8_t bootstrap_js_gz_end[] asm("_binary_bootstrap_min_js_gz_end"); -extern const uint8_t bootstrap_css_gz_start[] asm("_binary_bootstrap_min_css_gz_start"); -extern const uint8_t bootstrap_css_gz_end[] asm("_binary_bootstrap_min_css_gz_end"); -extern const uint8_t code_js_start[] asm("_binary_code_js_start"); -extern const uint8_t code_js_end[] asm("_binary_code_js_end"); -extern const uint8_t index_html_start[] asm("_binary_index_html_start"); -extern const uint8_t index_html_end[] asm("_binary_index_html_end"); - - -/* const http headers stored in ROM */ -const static char http_hdr_template[] = "HTTP/1.1 200 OK\nContent-type: %s\nAccept-Ranges: bytes\nContent-Length: %d\nContent-Encoding: %s\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_html_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/html\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_css_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/css\nCache-Control: public, max-age=31536000\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_js_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_400_hdr[] = "HTTP/1.1 400 Bad Request\nContent-Length: 0\n\n"; -const static char http_404_hdr[] = "HTTP/1.1 404 Not Found\nContent-Length: 0\n\n"; -const static char http_503_hdr[] = "HTTP/1.1 503 Service Unavailable\nContent-Length: 0\n\n"; -const static char http_ok_json_no_cache_hdr[] = "HTTP/1.1 200 OK\nContent-type: application/json\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://"; -const static char http_redirect_hdr_end[] = "/\n\n"; - - -void http_server_start() { - ESP_LOGD(TAG, "http_server_start "); - if(task_http_server == NULL) { - task_http_server = xTaskCreateStatic( (TaskFunction_t) &http_server, "http_server", HTTP_STACK_SIZE, NULL, - WIFI_MANAGER_TASK_PRIORITY, task_http_stack, &task_http_buffer); - } -} -void http_server(void *pvParameters) { - http_server_config_mutex = xSemaphoreCreateMutex(); - struct netconn *conn, *newconn; - err_t err; - conn = netconn_new(NETCONN_TCP); - netconn_bind(conn, IP_ADDR_ANY, 80); - netconn_listen(conn); - ESP_LOGI(TAG, "HTTP Server listening on 80/tcp"); - do { - err = netconn_accept(conn, &newconn); - if(err == ERR_OK) { - http_server_netconn_serve(newconn); - netconn_delete(newconn); - } - else - { - ESP_LOGE(TAG, "Error accepting new connection. Terminating HTTP server"); - } - taskYIELD(); /* allows the freeRTOS scheduler to take over if needed. */ - } while(err == ERR_OK); - - netconn_close(conn); - netconn_delete(conn); - vSemaphoreDelete(http_server_config_mutex); - http_server_config_mutex = NULL; - vTaskDelete( NULL ); -} - - -char* http_server_get_header(char *request, char *header_name, int *len) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - - ptr = strstr(request, header_name); - if(ptr) { - ret = ptr + strlen(header_name); - ptr = ret; - while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') { - (*len)++; - ptr++; - } - return ret; - } - return NULL; -} -char* http_server_search_header(char *request, char *header_name, int *len, char ** parm_name, char ** next_position, char * bufEnd) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - int currentLength=0; - - ESP_LOGV(TAG, "searching for header name: [%s]", header_name); - ptr = strstr(request, header_name); - - - if(ptr!=NULL && ptr0) { - ESP_LOGD(TAG, "Found Header Line %s ", last); - //Content-Type: application/json - } - else { - ESP_LOGD(TAG, "Found end of headers"); - bHeaders = false; - } - last=ptr; - } - else { - //ESP_LOGD(TAG, "Body content: %s", last); - //cJSON * json = cJSON_Parse(last); - //cJSON_Delete(json); - //todo: implement body json parsing - // right now, body is coming as compressed, so we need some type of decompression to happen. - return; - } - } - return ; - -} - -void dump_net_buffer(void * buf, u16_t buflen) { - char * curbuf = malloc(buflen+1); - ESP_LOGV(TAG, "netconn buffer, length=%u",buflen); - if(curbuf==NULL) { - ESP_LOGE(TAG, "Unable to show netconn buffer. Malloc failed"); - } - memset(curbuf,0x0, buflen+1); - memcpy(curbuf,buf,buflen); - ESP_LOGV(TAG, "netconn buffer content:\n%s",curbuf); - free(curbuf); -} - -void http_server_netconn_serve(struct netconn *conn) { - - struct netbuf *inbuf; - char *buf = NULL; - u16_t buflen; - err_t err; - ip_addr_t remote_add; - u16_t port; - ESP_LOGV(TAG, "Serving page. Getting device AP address."); - const char new_line[2] = "\n"; - char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); - if(ap_ip_address==NULL){ - ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - netconn_close(conn); - return; - } - ESP_LOGV(TAG, "Getting remote device IP address."); - netconn_getaddr(conn, &remote_add, &port, 0); - char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); - ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); - err = netconn_recv(conn, &inbuf); - if(err == ERR_OK) { - ESP_LOGV(TAG, "Getting data buffer."); - netbuf_data(inbuf, (void**)&buf, &buflen); - dump_net_buffer(buf, buflen); - int lenH = 0; - /* extract the first line of the request */ - char *save_ptr = buf; - char *line = strtok_r(save_ptr, new_line, &save_ptr); - char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); - char * host = malloc(lenH+1); - memset(host,0x00,lenH+1); - if(lenH>0){ - strlcpy(host,temphost,lenH+1); - } - ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); - - if(line) { - - /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ - const char * host_name=NULL; - if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - } - else { - ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); - } - - /* determine if Host is from the STA IP address */ - wifi_manager_lock_sta_ip_string(portMAX_DELAY); - bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; - wifi_manager_unlock_sta_ip_string(); - bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); - - if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { - ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); - netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); - netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); - netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); - } - else { - //static stuff - /* default page */ - if(strstr(line, "GET / ")) { - netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, index_html_start, index_html_end- index_html_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /code.js ")) { - netconn_write(conn, http_js_hdr, sizeof(http_js_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, code_js_start, code_js_end - code_js_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /style.css ")) { - netconn_write(conn, http_css_hdr, sizeof(http_css_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, style_css_start, style_css_end - style_css_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /jquery.js ")) { - http_server_send_resource_file(conn,jquery_gz_start, jquery_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /popper.js ")) { - http_server_send_resource_file(conn,popper_gz_start, popper_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.js ")) { - http_server_send_resource_file(conn,bootstrap_js_gz_start, bootstrap_js_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.css ")) { - http_server_send_resource_file(conn,bootstrap_css_gz_start, bootstrap_css_gz_end, "text/css", "gzip" ); - } - - //dynamic stuff - else if(strstr(line, "GET /scan.json ")) { - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - } - else if(strstr(line, "GET /ap.json ")) { - /* if we can get the mutex, write the last version of the AP list */ - ESP_LOGI(TAG, "Processing ap.json request"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - char *buff = wifi_manager_alloc_get_ap_list_json(); - wifi_manager_unlock_json_buffer(); - if(buff!=NULL){ - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - ESP_LOGD(TAG, "Error retrieving ap list json string. "); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex"); - } - /* request a wifi scan */ - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - ESP_LOGI(TAG, "Done serving ap.json"); - } - else if(strstr(line, "GET /config.json ")) { - ESP_LOGI(TAG, "Serving config.json"); - ESP_LOGI(TAG, "About to get config from flash"); - http_server_send_config_json(conn); - ESP_LOGD(TAG, "Done serving config.json"); - } - else if(strstr(line, "POST /config.json ")) { - ESP_LOGI(TAG, "Serving POST config.json"); - int lenA=0; - char * last_parm=save_ptr; - char * next_parm=save_ptr; - char * last_parm_name=NULL; - bool bErrorFound=false; - bool bOTA=false; - char * otaURL=NULL; - // todo: implement json body parsing - //http_server_process_config(conn,save_ptr); - - while(last_parm!=NULL) { - // Search will return - ESP_LOGD(TAG, "Getting parameters from X-Custom headers"); - last_parm = http_server_search_header(next_parm, "X-Custom-", &lenA, &last_parm_name,&next_parm,buf+buflen); - if(last_parm!=NULL && last_parm_name!=NULL) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST config.json, config %s=%s", last_parm_name, last_parm); - if(strcmp(last_parm_name, "fwurl")==0) { - // we're getting a request to do an OTA from that URL - ESP_LOGW(TAG, "Found OTA request!"); - otaURL=strdup(last_parm); - bOTA=true; - } - else { - ESP_LOGV(TAG, "http_server_netconn_serve: POST config.json Storing parameter"); - if(config_set_value(NVS_TYPE_STR, last_parm_name , last_parm) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save nvs value."); - } - } - } - if(last_parm_name!=NULL) { - free(last_parm_name); - last_parm_name=NULL; - } - } - if(bErrorFound) { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); //400 invalid request - } - else { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - if(bOTA) { - -#if RECOVERY_APPLICATION - ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); -#else - ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); -#endif - wifi_manager_reboot_ota(otaURL); - free(otaURL); - } - } - ESP_LOGI(TAG, "Done Serving POST config.json"); - } - else if(strstr(line, "POST /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST /connect.json"); - bool found = false; - int lenS = 0, lenP = 0, lenN = 0; - char *ssid = NULL, *password = NULL; - ssid = http_server_get_header(save_ptr, "X-Custom-ssid: ", &lenS); - password = http_server_get_header(save_ptr, "X-Custom-pwd: ", &lenP); - char * new_host_name_b = http_server_get_header(save_ptr, "X-Custom-host_name: ", &lenN); - if(lenN > 0){ - lenN++; - char * new_host_name = malloc(lenN); - strlcpy(new_host_name, new_host_name_b, lenN); - if(config_set_value(NVS_TYPE_STR, "host_name", new_host_name) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save host name configuration"); - } - free(new_host_name); - } - - if(ssid && lenS <= MAX_SSID_SIZE && password && lenP <= MAX_PASSWORD_SIZE) { - wifi_config_t* config = wifi_manager_get_wifi_sta_config(); - memset(config, 0x00, sizeof(wifi_config_t)); - memcpy(config->sta.ssid, ssid, lenS); - memcpy(config->sta.password, password, lenP); - ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); - wifi_manager_connect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - found = true; - } - else{ - ESP_LOGE(TAG, "SSID or Password invalid"); - } - - - if(!found) { - /* bad request the authentification header is not complete/not the correct format */ - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request the authentification header is not complete/not the correct format"); - } - - ESP_LOGI(TAG, "http_server_netconn_serve: done serving connect.json"); - } - else if(strstr(line, "DELETE /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: DELETE /connect.json"); - /* request a disconnection from wifi and forget about it */ - wifi_manager_disconnect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - ESP_LOGI(TAG, "http_server_netconn_serve: done serving DELETE /connect.json"); - } - else if(strstr(line, "POST /reboot_ota.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot_ota.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(OTA); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot_ota.json"); - } - else if(strstr(line, "POST /reboot.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RESTART); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot.json"); - } - else if(strstr(line, "POST /recovery.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST recovery.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RECOVERY); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST recovery.json"); - } - else if(strstr(line, "GET /status.json ")) { - ESP_LOGI(TAG, "Serving status.json"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - char *buff = wifi_manager_alloc_get_ip_info_json(); - wifi_manager_unlock_json_buffer(); - if(buff) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /status failed to obtain mutex"); - } - ESP_LOGI(TAG, "Done Serving status.json"); - } - else { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request from host: %s, request %s",remote_address, line); - } - } - } - else { - ESP_LOGE(TAG, "URL not found processing for remote host : %s",remote_address); - netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY); - } - free(host); - - } - - free(ap_ip_address); - free(remote_address); - netconn_close(conn); - netbuf_delete(inbuf); - /* free the buffer */ - -} - -bool http_server_lock_json_object(TickType_t xTicksToWait) { - ESP_LOGD(TAG, "Locking config json object"); - if(http_server_config_mutex) { - if( xSemaphoreTake( http_server_config_mutex, xTicksToWait ) == pdTRUE ) { - ESP_LOGV(TAG, "config Json object locked!"); - return true; - } - else { - ESP_LOGW(TAG, "Semaphore take failed. Unable to lock config Json object mutex"); - return false; - } - } - else { - ESP_LOGW(TAG, "Unable to lock config Json object mutex"); - return false; - } - -} - -void http_server_unlock_json_object() { - ESP_LOGD(TAG, "Unlocking json buffer!"); - xSemaphoreGive( http_server_config_mutex ); -} - -void strreplace(char *src, char *str, char *rep) -{ - char *p = strstr(src, str); - if(p) - { - int len = strlen(src)+strlen(rep)-strlen(str); - char r[len]; - memset(r, 0, len); - if( p >= src ) { - strncpy(r, src, p-src); - r[p-src]='\0'; - strncat(r, rep, strlen(rep)); - strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); - strcpy(src, r); - strreplace(p+strlen(rep), str, rep); - } - } -} - diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c new file mode 100644 index 00000000..dff9c39f --- /dev/null +++ b/components/wifi-manager/http_server_handlers.c @@ -0,0 +1,699 @@ +/* +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 +*/ + +#include "http_server_handlers.h" + +#include "esp_http_server.h" +#include "cmd_system.h" +#include +#include "squeezelite-ota.h" +#include "nvs_utilities.h" +#include +#include +#include "cJSON.h" +#include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "config.h" + +#define HTTP_STACK_SIZE (5*1024) +#define FREE_AND_NULL(p) if(p!=NULL){ free(p); p=NULL;} + +/* @brief tag used for ESP serial console messages */ +static const char TAG[] = "http_server"; +/* @brief task handle for the http server */ +static TaskHandle_t task_http_server = NULL; +static StaticTask_t task_http_buffer; +#if RECOVERY_APPLICATION +static StackType_t task_http_stack[HTTP_STACK_SIZE]; +#else +static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE]; +#endif +SemaphoreHandle_t http_server_config_mutex = NULL; + +#define AUTH_TOKEN_SIZE 50 +typedef struct session_context { + char * auth_token; + bool authenticated; +} session_context_t; + + + + +/** + * @brief embedded binary data. + * @see file "component.mk" + * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data + */ +extern const uint8_t style_css_start[] asm("_binary_style_css_start"); +extern const uint8_t style_css_end[] asm("_binary_style_css_end"); +extern const uint8_t jquery_gz_start[] asm("_binary_jquery_min_js_gz_start"); +extern const uint8_t jquery_gz_end[] asm("_binary_jquery_min_js_gz_end"); +extern const uint8_t popper_gz_start[] asm("_binary_popper_min_js_gz_start"); +extern const uint8_t popper_gz_end[] asm("_binary_popper_min_js_gz_end"); +extern const uint8_t bootstrap_js_gz_start[] asm("_binary_bootstrap_min_js_gz_start"); +extern const uint8_t bootstrap_js_gz_end[] asm("_binary_bootstrap_min_js_gz_end"); +extern const uint8_t bootstrap_css_gz_start[] asm("_binary_bootstrap_min_css_gz_start"); +extern const uint8_t bootstrap_css_gz_end[] asm("_binary_bootstrap_min_css_gz_end"); +extern const uint8_t code_js_start[] asm("_binary_code_js_start"); +extern const uint8_t code_js_end[] asm("_binary_code_js_end"); +extern const uint8_t index_html_start[] asm("_binary_index_html_start"); +extern const uint8_t index_html_end[] asm("_binary_index_html_end"); +// +// +///* const http headers stored in ROM */ +//const static char http_hdr_template[] = "HTTP/1.1 200 OK\nContent-type: %s\nAccept-Ranges: bytes\nContent-Length: %d\nContent-Encoding: %s\nAccess-Control-Allow-Origin: *\n\n"; +//const static char http_html_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/html\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; +//const static char http_css_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/css\nCache-Control: public, max-age=31536000\nAccess-Control-Allow-Origin: *\n\n"; +//const static char http_js_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\nAccess-Control-Allow-Origin: *\n\n"; +//const static char http_400_hdr[] = "HTTP/1.1 400 Bad Request\nContent-Length: 0\n\n"; +//const static char http_404_hdr[] = "HTTP/1.1 404 Not Found\nContent-Length: 0\n\n"; +//const static char http_503_hdr[] = "HTTP/1.1 503 Service Unavailable\nContent-Length: 0\n\n"; +//const static char http_ok_json_no_cache_hdr[] = "HTTP/1.1 200 OK\nContent-type: application/json\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; +//const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://"; +//const static char http_redirect_hdr_end[] = "/\n\n"; + + +/* Custom function to free context */ +void free_ctx_func(void *ctx) +{ + if(ctx){ + if(ctx->auth_token) free(auth_token); + free(ctx); + } +} + +bool is_user_authenticated(httpd_req_t *req){ + if (! req->sess_ctx) { + req->sess_ctx = malloc(sizeof(session_context_t)); + memset(req->sess_ctx,0x00,sizeof(session_context_t)); + req->free_ctx = free_ctx_func; + } + session_context_t *ctx_data = (session_context_t*)req->sess_ctx; + if(ctx_data->authenticated){ + ESP_LOGD(TAG,"User is authenticated."); + return true; + } + + // todo: ask for user to authenticate + return false; +} + + + +/* Copies the full path into destination buffer and returns + * pointer to path (skipping the preceding base path) */ +static const char* get_path_from_uri(char *dest, const char *base_path, const char *uri, size_t destsize) +{ + const size_t base_pathlen = strlen(base_path); + size_t pathlen = strlen(uri); + + const char *quest = strchr(uri, '?'); + if (quest) { + pathlen = MIN(pathlen, quest - uri); + } + const char *hash = strchr(uri, '#'); + if (hash) { + pathlen = MIN(pathlen, hash - uri); + } + + if (base_pathlen + pathlen + 1 > destsize) { + /* Full path string won't fit into destination buffer */ + return NULL; + } + + /* Construct full path (base + path) */ + strcpy(dest, base_path); + strlcpy(dest + base_pathlen, uri, pathlen + 1); + + /* Return pointer to path, skipping the base */ + return dest + base_pathlen; +} + +#define IS_FILE_EXT(filename, ext) \ + (strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0) + +/* Set HTTP response content type according to file extension */ +static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename) +{ + if (IS_FILE_EXT(filename, ".pdf")) { + return httpd_resp_set_type(req, "application/pdf"); + } else if (IS_FILE_EXT(filename, ".html")) { + return httpd_resp_set_type(req, "text/html"); + } else if (IS_FILE_EXT(filename, ".jpeg")) { + return httpd_resp_set_type(req, "image/jpeg"); + } else if (IS_FILE_EXT(filename, ".ico")) { + return httpd_resp_set_type(req, "image/x-icon"); + } else if (IS_FILE_EXT(filename, ".ico")) { + return httpd_resp_set_type(req, "image/x-icon"); + } else if (IS_FILE_EXT(filename, ".css")) { + return httpd_resp_set_type(req, "text/css"); + } else if (IS_FILE_EXT(filename, ".js")) { + return httpd_resp_set_type(req, "text/javascript"); + } else if (IS_FILE_EXT(filename, ".json")) { + return httpd_resp_set_type(req, "application/json"); + } + /* This is a limited set only */ + /* For any other type always set as plain text */ + return httpd_resp_set_type(req, "text/plain"); +} +static esp_err_t set_content_type_from_req(httpd_req_t *req) +{ + char filepath[FILE_PATH_MAX]; + const char *filename = get_path_from_uri(filepath, "/" , + req->uri, sizeof(filepath)); + if (!filename) { + ESP_LOGE(TAG, "Filename is too long"); + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long"); + return ESP_FAIL; + } + + /* If name has trailing '/', respond with directory contents */ + if (filename[strlen(filename) - 1] == '/') { + httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED, "Browsing files forbidden."); + return ESP_FAIL; + } + return ESP_OK; +} + + +esp_err_t root_get_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_hdr(req, "Accept-Encoding", "identity"); + + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: send password entry page and return + } + const size_t file_size = (index_html_end - index_html_start); + esp_err_t err = set_content_type_from_req(req); + if(err == ESP_OK){ + httpd_resp_send(req, (const char *)index_html_start, file_size); + } + return err; +} + +esp_err_t resource_filehandler(httpd_req_t *req){ + char filepath[FILE_PATH_MAX]; + ESP_LOGI(TAG, "serving [%s]", req->uri); + + const char *filename = get_path_from_uri(filepath, "/res/" , + req->uri, sizeof(filepath)); + + if (!filename) { + ESP_LOGE(TAG, "Filename is too long"); + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long"); + return ESP_FAIL; + } + + /* If name has trailing '/', respond with directory contents */ + if (filename[strlen(filename) - 1] == '/') { + httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED, "Browsing files forbidden."); + return ESP_FAIL; + } + + if(strstr(line, "GET /code.js ")) { + const size_t file_size = (code_js_end - code_js_start); + set_content_type_from_file(req, filename); + httpd_resp_send(req, (const char *)code_js_start, file_size); + } + else if(strstr(line, "GET /style.css ")) { + set_content_type_from_file(req, filename); + const size_t file_size = (style_css_end - style_css_start); + httpd_resp_send(req, (const char *)style_css_start, file_size); + } else if(strstr(line, "GET /jquery.js ")) { + set_content_type_from_file(req, filename); + httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); + const size_t file_size = (jquery_gz_end - jquery_gz_start); + httpd_resp_send(req, (const char *)jquery_gz_start, file_size); + }else if(strstr(line, "GET /popper.js")) { + set_content_type_from_file(req, filename); + httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); + const size_t file_size = (popper_gz_end - popper_gz_start); + httpd_resp_send(req, (const char *)popper_gz_start, file_size); + } + else if(strstr(line, "GET /bootstrap.js ")) { + set_content_type_from_file(req, filename); + httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); + const size_t file_size = (bootstrap_js_gz_end - bootstrap_js_gz_start); + httpd_resp_send(req, (const char *)bootstrap_js_gz_start, file_size); + } + else if(strstr(line, "GET /bootstrap.css")) { + set_content_type_from_file(req, filename); + httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); + const size_t file_size = (bootstrap_css_gz_end - bootstrap_css_gz_start); + httpd_resp_send(req, (const char *)bootstrap_css_gz_start, file_size); + } + else { + ESP_LOGE(TAG, "Unknown resource: %s", filepath); + /* Respond with 404 Not Found */ + httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist"); + return ESP_FAIL; + } + ESP_LOGI(TAG, "Resource sending complete"); + return ESP_OK; + +} +esp_err_t ap_scan_handler(httpd_req_t *req){ + const char empty[] = "{}"; + ESP_LOGI(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + wifi_manager_scan_async(); + esp_err_t err = set_content_type_from_req(req); + if(err == ESP_OK){ + httpd_resp_send(req, (const char *)empty, strlen(empty)); + } + return err; +} +esp_err_t ap_get_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + /* 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 ) 10)){ + char *buff = wifi_manager_alloc_get_ap_list_json(); + wifi_manager_unlock_json_buffer(); + if(buff!=NULL){ + httpd_resp_send(req, (const char *)buff, strlen(buff)); + free(buff); + } + else { + ESP_LOGD(TAG, "Error retrieving ap list json string. "); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to retrieve AP list"); + } + } + else { + httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "AP list unavailable"); + ESP_LOGE(TAG, "GET /ap.json failed to obtain mutex"); + } + return err; +} + +esp_err_t config_get_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + esp_err_t err = set_content_type_from_req(req); + if(err == ESP_OK){ + char * json = config_alloc_get_json(false); + if(json==NULL){ + ESP_LOGD(TAG, "Error retrieving config json string. "); + httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "Error retrieving configuration object"); + err=ESP_FAIL; + } + else { + ESP_LOGD(TAG, "config json : %s",json ); + httpd_resp_send(req, (const char *)json, strlen(json)); + free(json); + } + } + return err; +} +esp_err_t post_handler_buff_receive(httpd_req_t * req){ + esp_err_t err = ESP_OK; + + int total_len = req->content_len; + int cur_len = 0; + char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; + int received = 0; + if (total_len >= SCRATCH_BUFSIZE) { + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); + return ESP_FAIL; + } + while (cur_len < total_len) { + received = httpd_req_recv(req, buf + cur_len, total_len); + if (received <= 0) { + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value"); + return ESP_FAIL; + } + cur_len += received; + } + + buf[total_len] = '\0'; +} +esp_err_t config_post_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + bool bOTA=false; + char * otaURL=NULL; + esp_err_t err = post_handler_buff_receive(req); + if(err!=ESP_OK){ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); + return err; + } + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; + cJSON *root = cJSON_Parse(buf); + cJSON *item=root->next; + while (item && err == ESP_OK) + { + cJSON *prev_item = item; + item=item->next; + if(prev_item->name==NULL) { + ESP_LOGE(TAG,"Config value does not have a name"); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Value does not have a name."); + err = ESP_FAIL; + } + if(err == ESP_OK){ + ESP_LOGI(TAG,"Found config value name [%s]", prev_item->name); + nvs_type_t item_type= config_get_item_type(prev_item); + if(item_type!=0){ + void * val = config_safe_alloc_get_entry_value(item_type, prev_item); + if(val!=NULL){ + if(strcmp(prev_item->name, "fwurl")==0) { + if(item_type!=NVS_TYPE_STR){ + ESP_LOGE(TAG,"Firmware url should be type %d. Found type %d instead.",NVS_TYPE_STR,item_type ); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Wrong type for firmware URL."); + err = ESP_FAIL; + } + else { + // we're getting a request to do an OTA from that URL + ESP_LOGW(TAG, "Found OTA request!"); + otaURL=strdup(val); + bOTA=true; + } + } + else { + if(config_set_value(item_type, last_parm_name , last_parm) != ESP_OK){ + ESP_LOGE(TAG,"Unable to store value for [%s]", prev_item->name); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to store config value"); + err = ESP_FAIL; + } + else { + ESP_LOGI(TAG,"Successfully set value for [%s]",prev_item->name); + } + } + free(val); + } + else { + ESP_LOGE(TAG,"Value not found for [%s]", prev_item->name); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Missing value for entry."); + err = ESP_FAIL; + } + } + else { + ESP_LOGE(TAG,"Unable to determine the type of config value [%s]", prev_item->name); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Missing value for entry."); + err = ESP_FAIL; + } + } + } + + + if(err==ESP_OK){ + set_content_type_from_req(req); + httpd_resp_sendstr(req, "{ok}"); + } + cJSON_Delete(root); + if(bOTA) { + +#if RECOVERY_APPLICATION + ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); +#else + ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); +#endif + wifi_manager_reboot_ota(otaURL); + free(otaURL); + } + return err; + +} +esp_err_t connect_post_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + char success[]="{}"; + char * ssid=NULL; + char * password=NULL; + char * host_name; + set_content_type_from_req(req); + esp_err_t err = post_handler_buff_receive(req); + if(err!=ESP_OK){ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); + return err; + } + char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + cJSON *root = cJSON_Parse(buf); + + if(root==NULL){ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); + return ESP_FAIL; + } + + cJSON * ssid_object = cJSON_GetObjectItem(root, "ssid"); + if(ssid_object !=NULL){ + ssid = (char *)config_safe_alloc_get_entry_value(ssid_object); + } + cJSON * password_object = cJSON_GetObjectItem(root, "pwd"); + if(password_object !=NULL){ + password = (char *)config_safe_alloc_get_entry_value(password_object); + } + cJSON * host_name_object = cJSON_GetObjectItem(root, "host_name"); + if(host_name_object !=NULL){ + host_name = (char *)config_safe_alloc_get_entry_value(host_name_object); + } + cJSON_Delete(root); + + if(host_name!=NULL){ + if(config_set_value(NVS_TYPE_STR, "host_name", host_name) != ESP_OK){ + ESP_LOGW(TAG, "Unable to save host name configuration"); + } + } + + 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(config->sta.ssid, ssid, sizeof(config->sta.ssid)+1); + if(password){ + strlcpy(config->sta.password, password, sizeof(config->sta.password)+1); + } + ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); + wifi_manager_connect_async(); + httpd_resp_send(req, (const char *)success, strlen(success)); + } + else { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed json. Missing or invalid ssid/password."); + err = ESP_FAIL; + } + FREE_AND_NULL(ssid); + FREE_AND_NULL(password); + FREE_AND_NULL(host_name); + return err; +} +esp_err_t connect_delete_handler(httpd_req_t *req){ + char success[]="{}"; + ESP_LOGI(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + set_content_type_from_req(req); + httpd_resp_send(req, (const char *)success, strlen(success)); + wifi_manager_disconnect_async(); + + return ESP_OK; +} +esp_err_t reboot_ota_post_handler(httpd_req_t *req){ + char success[]="{}"; + ESP_LOGI(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + set_content_type_from_req(req); + httpd_resp_send(req, (const char *)success, strlen(success)); + wifi_manager_reboot(OTA); + return ESP_OK; +} +esp_err_t reboot_post_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + char success[]="{}"; + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + set_content_type_from_req(req); + httpd_resp_send(req, (const char *)success, strlen(success)); + wifi_manager_reboot(RESTART); + return ESP_OK; +} +esp_err_t recovery_post_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + char success[]="{}"; + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + set_content_type_from_req(req); + httpd_resp_send(req, (const char *)success, strlen(success)); + wifi_manager_reboot(RECOVERY); + return ESP_OK; +} +esp_err_t status_post_handler(httpd_req_t *req){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + char success[]="{}"; + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + set_content_type_from_req(req); + + if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { + char *buff = wifi_manager_alloc_get_ip_info_json(); + wifi_manager_unlock_json_buffer(); + if(buff) { + httpd_resp_send(req, (const char *)buff, strlen(buff)); + free(buff); + } + else { + httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "Empty status object"); + } + } + else { + httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "Error retrieving status object"); + } + + return ESP_OK; +} + + + + + + + + + + +void http_server_netconn_serve(struct netconn *conn) { + + struct netbuf *inbuf; + char *buf = NULL; + u16_t buflen; + err_t err; + ip_addr_t remote_add; + u16_t port; + ESP_LOGV(TAG, "Serving page. Getting device AP address."); + const char new_line[2] = "\n"; + char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); + if(ap_ip_address==NULL){ + ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); + netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); + netconn_close(conn); + return; + } + ESP_LOGV(TAG, "Getting remote device IP address."); + netconn_getaddr(conn, &remote_add, &port, 0); + char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); + ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); + err = netconn_recv(conn, &inbuf); + if(err == ERR_OK) { + ESP_LOGV(TAG, "Getting data buffer."); + netbuf_data(inbuf, (void**)&buf, &buflen); + dump_net_buffer(buf, buflen); + int lenH = 0; + /* extract the first line of the request */ + char *save_ptr = buf; + char *line = strtok_r(save_ptr, new_line, &save_ptr); + char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); + char * host = malloc(lenH+1); + memset(host,0x00,lenH+1); + if(lenH>0){ + strlcpy(host,temphost,lenH+1); + } + ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); + + if(line) { + + /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ + const char * host_name=NULL; + if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { + ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); + } + else { + ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); + } + + /* determine if Host is from the STA IP address */ + wifi_manager_lock_sta_ip_string(portMAX_DELAY); + bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; + wifi_manager_unlock_sta_ip_string(); + bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); + + if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { + ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); + netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); + netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); + netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); + } + else { + //static stuff + +} + + +void strreplace(char *src, char *str, char *rep) +{ + char *p = strstr(src, str); + if(p) + { + int len = strlen(src)+strlen(rep)-strlen(str); + char r[len]; + memset(r, 0, len); + if( p >= src ) { + strncpy(r, src, p-src); + r[p-src]='\0'; + strncat(r, rep, strlen(rep)); + strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); + strcpy(src, r); + strreplace(p+strlen(rep), str, rep); + } + } +} + diff --git a/components/wifi-manager/http_server.h b/components/wifi-manager/http_server_handlers.h similarity index 81% rename from components/wifi-manager/http_server.h rename to components/wifi-manager/http_server_handlers.h index 89542f24..a9cb5557 100644 --- a/components/wifi-manager/http_server.h +++ b/components/wifi-manager/http_server_handlers.h @@ -62,6 +62,26 @@ function to process requests, decode URLs, serve files, etc. etc. #ifdef __cplusplus extern "C" { #endif +esp_err_t root_get_handler(httpd_req_t *req); +esp_err_t resource_filehandler(httpd_req_t *req); +esp_err_t resource_filehandler(httpd_req_t *req); +esp_err_t resource_filehandler(httpd_req_t *req); +esp_err_t resource_filehandler(httpd_req_t *req); +esp_err_t resource_filehandler(httpd_req_t *req); +esp_err_t resource_filehandler(httpd_req_t *req); +esp_err_t ap_get_handler(httpd_req_t *req); +esp_err_t config_get_handler(httpd_req_t *req); +esp_err_t config_post_handler(httpd_req_t *req); +esp_err_t connect_post_handler(httpd_req_t *req); +esp_err_t connect_delete_handler(httpd_req_t *req); +esp_err_t reboot_ota_post_handler(httpd_req_t *req); +esp_err_t reboot_post_handler(httpd_req_t *req); +esp_err_t recovery_post_handler(httpd_req_t *req); +esp_err_t status_post_handler(httpd_req_t *req); +esp_err_t ap_scan_handler(httpd_req_t *req); + + + /** * @brief RTOS task for the HTTP server. Do not start manually. diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c index 2afe482e..44766880 100644 --- a/components/wifi-manager/wifi_manager.c +++ b/components/wifi-manager/wifi_manager.c @@ -37,7 +37,6 @@ Contains the freeRTOS task and all necessary support #include #include "dns_server.h" -#include "http_server.h" #include "esp_system.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -62,6 +61,7 @@ Contains the freeRTOS task and all necessary support #include "cJSON.h" #include "nvs_utilities.h" #include "cmd_system.h" +#include "http_server_handlers.h" #ifndef RECOVERY_APPLICATION #define RECOVERY_APPLICATION 0 diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c new file mode 100644 index 00000000..14905402 --- /dev/null +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -0,0 +1,472 @@ +/* + * Squeezelite for esp32 + * + * (c) Sebastien 2019 + * Philippe G. 2019, philippe_44@outlook.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#include "http_server_handlers.h" +#include "esp_log.h" +#include "esp_http_server.h" +#include +#include +#include +#include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "config.h" + +static const char TAG[] = "http_server"; + +static httpd_handle_t server = NULL; +#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128) +#define SCRATCH_BUFSIZE (10240) + +typedef struct rest_server_context { + char base_path[ESP_VFS_PATH_MAX + 1]; + char scratch[SCRATCH_BUFSIZE]; +} rest_server_context_t; +#define ESP_LOGE_LOC(t,str, ...) ESP_LOGE(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define ESP_LOGI_LOC(t,str, ...) ESP_LOGI(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define ESP_LOGD_LOC(t,str, ...) ESP_LOGD(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) + + +esp_err_t http_server_start() +{ + ESP_LOGI(REST_TAG, "Initializing HTTP Server"); + rest_server_context_t *rest_context = calloc(1, 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_handle_t server = NULL; + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.uri_match_fn = httpd_uri_match_wildcard; + + ESP_LOGI(REST_TAG, "Starting HTTP Server"); + esp_err_t err= httpd_start(&server, &config); + if(err != ESP_OK){ + ESP_LOGE_LOC(TAG,"Start server failed"); + } + else { + + httpd_uri_t root_get = { .uri = "/", .method = HTTP_GET, .handler = root_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &root_get); + httpd_uri_t res_get = { .uri = "/res/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &res_get); + + httpd_uri_t ap_get = { .uri = "/ap.json", .method = HTTP_GET, .handler = ap_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &ap_get); + httpd_uri_t scan_get = { .uri = "/scan.json", .method = HTTP_GET, .handler = ap_scan_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &scan_get); + httpd_uri_t config_get = { .uri = "/config.json", .method = HTTP_GET, .handler = config_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &config_get); + httpd_uri_t status_get = { .uri = "/status.json", .method = HTTP_GET, .handler = status_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &status_get); + + + httpd_uri_t config_post = { .uri = "/config.json", .method = HTTP_POST, .handler = config_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &config_post); + httpd_uri_t connect_post = { .uri = "/connect.json", .method = HTTP_POST, .handler = connect_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &connect_post); + + httpd_uri_t reboot_ota_post = { .uri = "/reboot_ota.json", .method = HTTP_POST, .handler = reboot_ota_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &reboot_ota_post); + + httpd_uri_t reboot_post = { .uri = "/reboot.json", .method = HTTP_POST, .handler = reboot_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &reboot_post); + + httpd_uri_t recovery_post = { .uri = "/recovery.json", .method = HTTP_POST, .handler = recovery_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &recovery_post); + + httpd_uri_t connect_delete = { .uri = "/connect.json", .method = HTTP_DELETE, .handler = connect_delete_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &connect_delete); + + } + + return err; +} + + + + +/* Function to free context */ +void adder_free_func(void *ctx) +{ + ESP_LOGI(TAG, "/adder Free Context function called"); + free(ctx); +} + +/* This handler keeps accumulating data that is posted to it into a per + * socket/session context. And returns the result. + */ +esp_err_t adder_post_handler(httpd_req_t *req) +{ + /* Log total visitors */ + unsigned *visitors = (unsigned *)req->user_ctx; + ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors)); + + char buf[10]; + char outbuf[50]; + int ret; + + /* Read data received in the request */ + ret = httpd_req_recv(req, buf, sizeof(buf)); + if (ret <= 0) { + if (ret == HTTPD_SOCK_ERR_TIMEOUT) { + httpd_resp_send_408(req); + } + return ESP_FAIL; + } + + buf[ret] = '\0'; + int val = atoi(buf); + ESP_LOGI(TAG, "/adder handler read %d", val); + + /* Create session's context if not already available */ + if (! req->sess_ctx) { + ESP_LOGI(TAG, "/adder allocating new session"); + req->sess_ctx = malloc(sizeof(int)); + req->free_ctx = adder_free_func; + *(int *)req->sess_ctx = 0; + } + + /* Add the received data to the context */ + int *adder = (int *)req->sess_ctx; + *adder += val; + + /* Respond with the accumulated value */ + snprintf(outbuf, sizeof(outbuf),"%d", *adder); + httpd_resp_send(req, outbuf, strlen(outbuf)); + return ESP_OK; +} + +/* This handler gets the present value of the accumulator */ +esp_err_t adder_get_handler(httpd_req_t *req) +{ + /* Log total visitors */ + unsigned *visitors = (unsigned *)req->user_ctx; + ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors)); + + char outbuf[50]; + + /* Create session's context if not already available */ + if (! req->sess_ctx) { + ESP_LOGI(TAG, "/adder GET allocating new session"); + req->sess_ctx = malloc(sizeof(int)); + req->free_ctx = adder_free_func; + *(int *)req->sess_ctx = 0; + } + ESP_LOGI(TAG, "/adder GET handler send %d", *(int *)req->sess_ctx); + + /* Respond with the accumulated value */ + snprintf(outbuf, sizeof(outbuf),"%d", *((int *)req->sess_ctx)); + httpd_resp_send(req, outbuf, strlen(outbuf)); + return ESP_OK; +} + +/* This handler resets the value of the accumulator */ +esp_err_t adder_put_handler(httpd_req_t *req) +{ + /* Log total visitors */ + unsigned *visitors = (unsigned *)req->user_ctx; + ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors)); + + char buf[10]; + char outbuf[50]; + int ret; + + /* Read data received in the request */ + ret = httpd_req_recv(req, buf, sizeof(buf)); + if (ret <= 0) { + if (ret == HTTPD_SOCK_ERR_TIMEOUT) { + httpd_resp_send_408(req); + } + return ESP_FAIL; + } + + buf[ret] = '\0'; + int val = atoi(buf); + ESP_LOGI(TAG, "/adder PUT handler read %d", val); + + /* Create session's context if not already available */ + if (! req->sess_ctx) { + ESP_LOGI(TAG, "/adder PUT allocating new session"); + req->sess_ctx = malloc(sizeof(int)); + req->free_ctx = adder_free_func; + } + *(int *)req->sess_ctx = val; + + /* Respond with the reset value */ + snprintf(outbuf, sizeof(outbuf),"%d", *((int *)req->sess_ctx)); + httpd_resp_send(req, outbuf, strlen(outbuf)); + return ESP_OK; +} + +/* Maintain a variable which stores the number of times + * the "/adder" URI has been visited */ +static unsigned visitors = 0; + + +httpd_handle_t start_webserver(void) +{ + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + // Start the httpd server + ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); + + if (httpd_start(&server, &config) == ESP_OK) { + // Set URI handlers + ESP_LOGI(TAG, "Registering URI handlers"); + httpd_register_uri_handler(server, &adder_get); + httpd_register_uri_handler(server, &adder_put); + httpd_register_uri_handler(server, &adder_post); + return server; + } + + ESP_LOGI(TAG, "Error starting server!"); + return NULL; +} + +void stop_webserver(httpd_handle_t server) +{ + // Stop the httpd server + httpd_stop(server); +} + + + + + + + +if(strstr(line, "GET / ")) { + netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY); + netconn_write(conn, index_html_start, index_html_end- index_html_start, NETCONN_NOCOPY); +} +else if(strstr(line, "GET /code.js ")) { + netconn_write(conn, http_js_hdr, sizeof(http_js_hdr) - 1, NETCONN_NOCOPY); + netconn_write(conn, code_js_start, code_js_end - code_js_start, NETCONN_NOCOPY); +} +else if(strstr(line, "GET /style.css ")) { + netconn_write(conn, http_css_hdr, sizeof(http_css_hdr) - 1, NETCONN_NOCOPY); + netconn_write(conn, style_css_start, style_css_end - style_css_start, NETCONN_NOCOPY); +} +else if(strstr(line, "GET /jquery.js ")) { + http_server_send_resource_file(conn,jquery_gz_start, jquery_gz_end, "text/javascript", "gzip" ); +} +else if(strstr(line, "GET /popper.js ")) { + http_server_send_resource_file(conn,popper_gz_start, popper_gz_end, "text/javascript", "gzip" ); +} +else if(strstr(line, "GET /bootstrap.js ")) { + http_server_send_resource_file(conn,bootstrap_js_gz_start, bootstrap_js_gz_end, "text/javascript", "gzip" ); +} +else if(strstr(line, "GET /bootstrap.css ")) { + http_server_send_resource_file(conn,bootstrap_css_gz_start, bootstrap_css_gz_end, "text/css", "gzip" ); +} + +//dynamic stuff +else if(strstr(line, "GET /scan.json ")) { + ESP_LOGI(TAG, "Starting wifi scan"); + wifi_manager_scan_async(); +} +else if(strstr(line, "GET /ap.json ")) { + /* if we can get the mutex, write the last version of the AP list */ + ESP_LOGI(TAG, "Processing ap.json request"); + if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); + char *buff = wifi_manager_alloc_get_ap_list_json(); + wifi_manager_unlock_json_buffer(); + if(buff!=NULL){ + netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); + free(buff); + } + else { + ESP_LOGD(TAG, "Error retrieving ap list json string. "); + netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); + } + } + else { + netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); + ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex"); + } + /* request a wifi scan */ + ESP_LOGI(TAG, "Starting wifi scan"); + wifi_manager_scan_async(); + ESP_LOGI(TAG, "Done serving ap.json"); +} +else if(strstr(line, "GET /config.json ")) { + ESP_LOGI(TAG, "Serving config.json"); + ESP_LOGI(TAG, "About to get config from flash"); + http_server_send_config_json(conn); + ESP_LOGD(TAG, "Done serving config.json"); +} +else if(strstr(line, "POST /config.json ")) { + ESP_LOGI(TAG, "Serving POST config.json"); + int lenA=0; + char * last_parm=save_ptr; + char * next_parm=save_ptr; + char * last_parm_name=NULL; + bool bErrorFound=false; + bool bOTA=false; + char * otaURL=NULL; + // todo: implement json body parsing + //http_server_process_config(conn,save_ptr); + + while(last_parm!=NULL) { + // Search will return + ESP_LOGD(TAG, "Getting parameters from X-Custom headers"); + last_parm = http_server_search_header(next_parm, "X-Custom-", &lenA, &last_parm_name,&next_parm,buf+buflen); + if(last_parm!=NULL && last_parm_name!=NULL) { + ESP_LOGI(TAG, "http_server_netconn_serve: POST config.json, config %s=%s", last_parm_name, last_parm); + if(strcmp(last_parm_name, "fwurl")==0) { + // we're getting a request to do an OTA from that URL + ESP_LOGW(TAG, "Found OTA request!"); + otaURL=strdup(last_parm); + bOTA=true; + } + else { + ESP_LOGV(TAG, "http_server_netconn_serve: POST config.json Storing parameter"); + if(config_set_value(NVS_TYPE_STR, last_parm_name , last_parm) != ESP_OK){ + ESP_LOGE(TAG, "Unable to save nvs value."); + } + } + } + if(last_parm_name!=NULL) { + free(last_parm_name); + last_parm_name=NULL; + } + } + if(bErrorFound) { + netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); //400 invalid request + } + else { + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok + if(bOTA) { + +#if RECOVERY_APPLICATION + ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); +#else + ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); +#endif + wifi_manager_reboot_ota(otaURL); + free(otaURL); + } + } + ESP_LOGI(TAG, "Done Serving POST config.json"); +} +else if(strstr(line, "POST /connect.json ")) { + ESP_LOGI(TAG, "http_server_netconn_serve: POST /connect.json"); + bool found = false; + int lenS = 0, lenP = 0, lenN = 0; + char *ssid = NULL, *password = NULL; + ssid = http_server_get_header(save_ptr, "X-Custom-ssid: ", &lenS); + password = http_server_get_header(save_ptr, "X-Custom-pwd: ", &lenP); + char * new_host_name_b = http_server_get_header(save_ptr, "X-Custom-host_name: ", &lenN); + if(lenN > 0){ + lenN++; + char * new_host_name = malloc(lenN); + strlcpy(new_host_name, new_host_name_b, lenN); + if(config_set_value(NVS_TYPE_STR, "host_name", new_host_name) != ESP_OK){ + ESP_LOGE(TAG, "Unable to save host name configuration"); + } + free(new_host_name); + } + + if(ssid && lenS <= MAX_SSID_SIZE && password && lenP <= MAX_PASSWORD_SIZE) { + wifi_config_t* config = wifi_manager_get_wifi_sta_config(); + memset(config, 0x00, sizeof(wifi_config_t)); + memcpy(config->sta.ssid, ssid, lenS); + memcpy(config->sta.password, password, lenP); + ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); + wifi_manager_connect_async(); + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok + found = true; + } + else{ + ESP_LOGE(TAG, "SSID or Password invalid"); + } + + + if(!found) { + /* bad request the authentification header is not complete/not the correct format */ + netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); + ESP_LOGE(TAG, "bad request the authentification header is not complete/not the correct format"); + } + + ESP_LOGI(TAG, "http_server_netconn_serve: done serving connect.json"); +} +else if(strstr(line, "DELETE /connect.json ")) { + ESP_LOGI(TAG, "http_server_netconn_serve: DELETE /connect.json"); + /* request a disconnection from wifi and forget about it */ + wifi_manager_disconnect_async(); + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ + ESP_LOGI(TAG, "http_server_netconn_serve: done serving DELETE /connect.json"); +} +else if(strstr(line, "POST /reboot_ota.json ")) { + ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot_ota.json"); + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ + wifi_manager_reboot(OTA); + ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot_ota.json"); +} +else if(strstr(line, "POST /reboot.json ")) { + ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot.json"); + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ + wifi_manager_reboot(RESTART); + ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot.json"); +} +else if(strstr(line, "POST /recovery.json ")) { + ESP_LOGI(TAG, "http_server_netconn_serve: POST recovery.json"); + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ + wifi_manager_reboot(RECOVERY); + ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST recovery.json"); +} +else if(strstr(line, "GET /status.json ")) { + ESP_LOGI(TAG, "Serving status.json"); + if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { + char *buff = wifi_manager_alloc_get_ip_info_json(); + wifi_manager_unlock_json_buffer(); + if(buff) { + netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); + netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); + free(buff); + } + else { + netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); + } + + } + else { + netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); + ESP_LOGE(TAG, "http_server_netconn_serve: GET /status failed to obtain mutex"); + } + ESP_LOGI(TAG, "Done Serving status.json"); +} +else { + netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); + ESP_LOGE(TAG, "bad request from host: %s, request %s",remote_address, line); +} +} +} +else { +ESP_LOGE(TAG, "URL not found processing for remote host : %s",remote_address); +netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY); +} +free(host); + +} diff --git a/main/config.c b/main/config.c index 9b46c1de..5dd5bcf2 100644 --- a/main/config.c +++ b/main/config.c @@ -704,6 +704,33 @@ esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){ return result; } +esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){ + esp_err_t result = ESP_OK; + if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){ + ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT); + result = ESP_FAIL; + } + cJSON * entry = config_set_value_safe(nvs_type, key, value); + if(entry == NULL){ + result = ESP_FAIL; + } + else{ + char * entry_str = cJSON_PrintUnformatted(entry); + if(entry_str!=NULL){ + ESP_LOGV(TAG,"config_set_value result: \n%s",entry_str); + free(entry_str); + } + else { + ESP_LOGV(TAG,"config_set_value completed"); + } + + } + config_unlock(); + return result; +} + + + IMPLEMENT_SET_DEFAULT(uint8_t,NVS_TYPE_U8); IMPLEMENT_SET_DEFAULT(int8_t,NVS_TYPE_I8); IMPLEMENT_SET_DEFAULT(uint16_t,NVS_TYPE_U16); diff --git a/main/config.h b/main/config.h index d0861321..b0cf3579 100644 --- a/main/config.h +++ b/main/config.h @@ -38,4 +38,6 @@ void * config_alloc_get(nvs_type_t nvs_type, const char *key) ; bool wait_for_commit(); char * config_alloc_get_json(bool bFormatted); esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value); +nvs_type_t config_get_item_type(cJSON * entry); +void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry); From 583f8249cb6abd3aec3c6282a6e6393aa4669afc Mon Sep 17 00:00:00 2001 From: Sebastien Date: Tue, 26 Nov 2019 08:29:38 -0500 Subject: [PATCH 02/46] WIP - migration to httpd --- .../wifi-manager/http_server_handlers.c | 148 ++++++++---------- 1 file changed, 65 insertions(+), 83 deletions(-) diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index dff9c39f..ad0a457a 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -611,89 +611,71 @@ esp_err_t status_post_handler(httpd_req_t *req){ -void http_server_netconn_serve(struct netconn *conn) { - - struct netbuf *inbuf; - char *buf = NULL; - u16_t buflen; - err_t err; - ip_addr_t remote_add; - u16_t port; - ESP_LOGV(TAG, "Serving page. Getting device AP address."); - const char new_line[2] = "\n"; - char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); - if(ap_ip_address==NULL){ - ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - netconn_close(conn); - return; - } - ESP_LOGV(TAG, "Getting remote device IP address."); - netconn_getaddr(conn, &remote_add, &port, 0); - char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); - ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); - err = netconn_recv(conn, &inbuf); - if(err == ERR_OK) { - ESP_LOGV(TAG, "Getting data buffer."); - netbuf_data(inbuf, (void**)&buf, &buflen); - dump_net_buffer(buf, buflen); - int lenH = 0; - /* extract the first line of the request */ - char *save_ptr = buf; - char *line = strtok_r(save_ptr, new_line, &save_ptr); - char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); - char * host = malloc(lenH+1); - memset(host,0x00,lenH+1); - if(lenH>0){ - strlcpy(host,temphost,lenH+1); - } - ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); - - if(line) { - - /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ - const char * host_name=NULL; - if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - } - else { - ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); - } - - /* determine if Host is from the STA IP address */ - wifi_manager_lock_sta_ip_string(portMAX_DELAY); - bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; - wifi_manager_unlock_sta_ip_string(); - bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); - - if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { - ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); - netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); - netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); - netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); - } - else { - //static stuff - -} +//void http_server_netconn_serve(struct netconn *conn) { +// +// struct netbuf *inbuf; +// char *buf = NULL; +// u16_t buflen; +// err_t err; +// ip_addr_t remote_add; +// u16_t port; +// ESP_LOGV(TAG, "Serving page. Getting device AP address."); +// const char new_line[2] = "\n"; +// char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); +// if(ap_ip_address==NULL){ +// ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); +// netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); +// netconn_close(conn); +// return; +// } +// ESP_LOGV(TAG, "Getting remote device IP address."); +// netconn_getaddr(conn, &remote_add, &port, 0); +// char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); +// ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); +// err = netconn_recv(conn, &inbuf); +// if(err == ERR_OK) { +// ESP_LOGV(TAG, "Getting data buffer."); +// netbuf_data(inbuf, (void**)&buf, &buflen); +// dump_net_buffer(buf, buflen); +// int lenH = 0; +// /* extract the first line of the request */ +// char *save_ptr = buf; +// char *line = strtok_r(save_ptr, new_line, &save_ptr); +// char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); +// char * host = malloc(lenH+1); +// memset(host,0x00,lenH+1); +// if(lenH>0){ +// strlcpy(host,temphost,lenH+1); +// } +// ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); +// +// if(line) { +// +// /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ +// const char * host_name=NULL; +// if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { +// ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); +// } +// else { +// ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); +// } +// +// /* determine if Host is from the STA IP address */ +// wifi_manager_lock_sta_ip_string(portMAX_DELAY); +// bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; +// wifi_manager_unlock_sta_ip_string(); +// bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); +// +// if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { +// ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); +// netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); +// netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); +// netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); +// } +// else { +// //static stuff +// +//} -void strreplace(char *src, char *str, char *rep) -{ - char *p = strstr(src, str); - if(p) - { - int len = strlen(src)+strlen(rep)-strlen(str); - char r[len]; - memset(r, 0, len); - if( p >= src ) { - strncpy(r, src, p-src); - r[p-src]='\0'; - strncat(r, rep, strlen(rep)); - strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); - strcpy(src, r); - strreplace(p+strlen(rep), str, rep); - } - } -} From 4b3fab563a2d7648210aa5f316b7a52c46a95be9 Mon Sep 17 00:00:00 2001 From: sle118 Date: Tue, 3 Dec 2019 09:29:24 -0500 Subject: [PATCH 03/46] wip httpd implementation --- components/wifi-manager/dns_server.c | 3 - .../wifi-manager/http_server_handlers.c | 130 ++++++++++++++++-- .../wifi-manager/http_server_handlers.h | 2 +- .../wifi-manager/wifi_manager_http_server.c | 75 +++++----- 4 files changed, 162 insertions(+), 48 deletions(-) diff --git a/components/wifi-manager/dns_server.c b/components/wifi-manager/dns_server.c index c231b701..47403ef5 100644 --- a/components/wifi-manager/dns_server.c +++ b/components/wifi-manager/dns_server.c @@ -75,9 +75,6 @@ void CODE_RAM_LOCATION dns_server_stop(){ void CODE_RAM_LOCATION dns_server(void *pvParameters) { - - - struct sockaddr_in sa, ra; /* Set redirection DNS hijack to the access point IP */ diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index ad0a457a..49412df1 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -201,7 +201,7 @@ static esp_err_t set_content_type_from_req(httpd_req_t *req) /* If name has trailing '/', respond with directory contents */ if (filename[strlen(filename) - 1] == '/') { - httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED, "Browsing files forbidden."); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Browsing files forbidden."); return ESP_FAIL; } return ESP_OK; @@ -240,7 +240,7 @@ esp_err_t resource_filehandler(httpd_req_t *req){ /* If name has trailing '/', respond with directory contents */ if (filename[strlen(filename) - 1] == '/') { - httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED, "Browsing files forbidden."); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Browsing files forbidden."); return ESP_FAIL; } @@ -321,7 +321,7 @@ esp_err_t ap_get_handler(httpd_req_t *req){ } } else { - httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "AP list unavailable"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "AP list unavailable"); ESP_LOGE(TAG, "GET /ap.json failed to obtain mutex"); } return err; @@ -338,7 +338,7 @@ esp_err_t config_get_handler(httpd_req_t *req){ char * json = config_alloc_get_json(false); if(json==NULL){ ESP_LOGD(TAG, "Error retrieving config json string. "); - httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "Error retrieving configuration object"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Error retrieving configuration object"); err=ESP_FAIL; } else { @@ -358,14 +358,14 @@ esp_err_t post_handler_buff_receive(httpd_req_t * req){ int received = 0; if (total_len >= SCRATCH_BUFSIZE) { /* Respond with 500 Internal Server Error */ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Content too long"); return ESP_FAIL; } while (cur_len < total_len) { received = httpd_req_recv(req, buf + cur_len, total_len); if (received <= 0) { /* Respond with 500 Internal Server Error */ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Failed to post control value"); return ESP_FAIL; } cur_len += received; @@ -379,7 +379,6 @@ esp_err_t config_post_handler(httpd_req_t *req){ char * otaURL=NULL; esp_err_t err = post_handler_buff_receive(req); if(err!=ESP_OK){ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); return err; } if(!is_user_authenticated(httpd_req_t *req)){ @@ -420,7 +419,7 @@ esp_err_t config_post_handler(httpd_req_t *req){ else { if(config_set_value(item_type, last_parm_name , last_parm) != ESP_OK){ ESP_LOGE(TAG,"Unable to store value for [%s]", prev_item->name); - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to store config value"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to store config value"); err = ESP_FAIL; } else { @@ -471,7 +470,6 @@ esp_err_t connect_post_handler(httpd_req_t *req){ set_content_type_from_req(req); esp_err_t err = post_handler_buff_receive(req); if(err!=ESP_OK){ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); return err; } char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; @@ -482,7 +480,7 @@ esp_err_t connect_post_handler(httpd_req_t *req){ cJSON *root = cJSON_Parse(buf); if(root==NULL){ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "JSON parsing error."); return ESP_FAIL; } @@ -592,18 +590,126 @@ esp_err_t status_post_handler(httpd_req_t *req){ free(buff); } else { - httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "Empty status object"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Empty status object"); } } else { - httpd_resp_send_err(req, HTTPD_503_NOT_FOUND, "Error retrieving status object"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object"); } return ESP_OK; } +esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){ + ESP_LOGI(TAG, "serving [%s]", req->uri); + char success[]=""; + if(!is_user_authenticated(httpd_req_t *req)){ + // todo: redirect to login page + // return ESP_OK; + } + if(error != HTTPD_404_NOT_FOUND){ + return httpd_resp_send_err(req, error, NULL); + } + + char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); + if(ap_ip_address==NULL){ + ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to retrieve default AP IP Address"); + return ESP_FAIL; + } + struct httpd_req_aux *ra = req->aux; + //UF_HOST + + + // ip_addr_t remote_add; + // err_t err; + + + // u16_t buflen; + // u16_t port; + + + // ESP_LOGV(TAG, "Getting remote device IP address."); + // netconn_getaddr(conn, &remote_add, &port, 0); + // char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); + // ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); + // err = netconn_recv(conn, &inbuf); + // if(err == ERR_OK) { + // ESP_LOGV(TAG, "Getting data buffer."); + // netbuf_data(inbuf, (void**)&buf, &buflen); + // dump_net_buffer(buf, buflen); + // int lenH = 0; + // /* extract the first line of the request */ + // char *save_ptr = buf; + // char *line = strtok_r(save_ptr, new_line, &save_ptr); + // char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); + // char * host = malloc(lenH+1); + // memset(host,0x00,lenH+1); + // if(lenH>0){ + // strlcpy(host,temphost,lenH+1); + // } + // ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); + // + // if(line) { + // + // /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ + // const char * host_name=NULL; + // if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { + // ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); + // } + // else { + // ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); + // } + // + // /* determine if Host is from the STA IP address */ + // wifi_manager_lock_sta_ip_string(portMAX_DELAY); + // bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; + // wifi_manager_unlock_sta_ip_string(); + // bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); + // + // if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { + // ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); + // netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); + // netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); + // netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + set_content_type_from_req(req); + httpd_resp_send(req, (const char *)NULL, 0); + wifi_manager_reboot(RECOVERY); + FREE_AND_NULL(ap_ip_address); + return ESP_OK; +} diff --git a/components/wifi-manager/http_server_handlers.h b/components/wifi-manager/http_server_handlers.h index a9cb5557..eee41611 100644 --- a/components/wifi-manager/http_server_handlers.h +++ b/components/wifi-manager/http_server_handlers.h @@ -79,7 +79,7 @@ esp_err_t reboot_post_handler(httpd_req_t *req); esp_err_t recovery_post_handler(httpd_req_t *req); esp_err_t status_post_handler(httpd_req_t *req); esp_err_t ap_scan_handler(httpd_req_t *req); - +esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error); diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 14905402..16cb1b0d 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -45,6 +45,43 @@ typedef struct rest_server_context { #define ESP_LOGD_LOC(t,str, ...) ESP_LOGD(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) + +void register_common_handlers(httpd_handle_t server){ + httpd_uri_t res_get = { .uri = "/res/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &res_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 }; + httpd_register_uri_handler(server, &root_get); + + httpd_uri_t ap_get = { .uri = "/ap.json", .method = HTTP_GET, .handler = ap_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &ap_get); + httpd_uri_t scan_get = { .uri = "/scan.json", .method = HTTP_GET, .handler = ap_scan_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &scan_get); + httpd_uri_t config_get = { .uri = "/config.json", .method = HTTP_GET, .handler = config_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &config_get); + httpd_uri_t status_get = { .uri = "/status.json", .method = HTTP_GET, .handler = status_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &status_get); + + httpd_uri_t config_post = { .uri = "/config.json", .method = HTTP_POST, .handler = config_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &config_post); + httpd_uri_t connect_post = { .uri = "/connect.json", .method = HTTP_POST, .handler = connect_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &connect_post); + + httpd_uri_t reboot_ota_post = { .uri = "/reboot_ota.json", .method = HTTP_POST, .handler = reboot_ota_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &reboot_ota_post); + + httpd_uri_t reboot_post = { .uri = "/reboot.json", .method = HTTP_POST, .handler = reboot_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &reboot_post); + + httpd_uri_t recovery_post = { .uri = "/recovery.json", .method = HTTP_POST, .handler = recovery_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &recovery_post); + + httpd_uri_t connect_delete = { .uri = "/connect.json", .method = HTTP_DELETE, .handler = connect_delete_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &connect_delete); +} + esp_err_t http_server_start() { ESP_LOGI(REST_TAG, "Initializing HTTP Server"); @@ -58,6 +95,8 @@ esp_err_t http_server_start() httpd_handle_t server = NULL; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.uri_match_fn = httpd_uri_match_wildcard; + //todo: use this to configure session token? + // config.open_fn ESP_LOGI(REST_TAG, "Starting HTTP Server"); esp_err_t err= httpd_start(&server, &config); @@ -66,39 +105,11 @@ esp_err_t http_server_start() } else { - httpd_uri_t root_get = { .uri = "/", .method = HTTP_GET, .handler = root_get_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &root_get); - httpd_uri_t res_get = { .uri = "/res/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &res_get); - - httpd_uri_t ap_get = { .uri = "/ap.json", .method = HTTP_GET, .handler = ap_get_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &ap_get); - httpd_uri_t scan_get = { .uri = "/scan.json", .method = HTTP_GET, .handler = ap_scan_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &scan_get); - httpd_uri_t config_get = { .uri = "/config.json", .method = HTTP_GET, .handler = config_get_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &config_get); - httpd_uri_t status_get = { .uri = "/status.json", .method = HTTP_GET, .handler = status_get_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &status_get); - - - httpd_uri_t config_post = { .uri = "/config.json", .method = HTTP_POST, .handler = config_post_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &config_post); - httpd_uri_t connect_post = { .uri = "/connect.json", .method = HTTP_POST, .handler = connect_post_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &connect_post); - - httpd_uri_t reboot_ota_post = { .uri = "/reboot_ota.json", .method = HTTP_POST, .handler = reboot_ota_post_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &reboot_ota_post); - - httpd_uri_t reboot_post = { .uri = "/reboot.json", .method = HTTP_POST, .handler = reboot_post_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &reboot_post); - - httpd_uri_t recovery_post = { .uri = "/recovery.json", .method = HTTP_POST, .handler = recovery_post_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &recovery_post); - - httpd_uri_t connect_delete = { .uri = "/connect.json", .method = HTTP_DELETE, .handler = connect_delete_handler, .user_ctx = rest_context }; - httpd_register_uri_handler(server, &connect_delete); - + register_common_handlers(server); + register_regular_handlers(server); } + register_err_handler(server, HTTPD_404_NOT_FOUND,&err_handler); + return err; } From 87255733a5591ae0b127e368e05f764f69115bf1 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 12 Dec 2019 11:33:58 -0500 Subject: [PATCH 04/46] WIP httpd - saving current work. likely won't compile right now! --- components/cmd_i2c/CMakeLists.txt | 9 +- components/cmd_i2c/component.mk | 7 +- components/wifi-manager/code.js | 103 ++- components/wifi-manager/component.mk | 4 +- .../wifi-manager/http_server_handlers.c | 791 +++++++++++------- .../wifi-manager/http_server_handlers.h | 28 +- components/wifi-manager/index.html | 20 +- components/wifi-manager/wifi_manager.c | 5 +- .../wifi-manager/wifi_manager_http_server.c | 201 +---- main/config.c | 51 +- main/config.h | 1 + 11 files changed, 694 insertions(+), 526 deletions(-) diff --git a/components/cmd_i2c/CMakeLists.txt b/components/cmd_i2c/CMakeLists.txt index 14069736..421e8fa7 100644 --- a/components/cmd_i2c/CMakeLists.txt +++ b/components/cmd_i2c/CMakeLists.txt @@ -1,5 +1,6 @@ -set(COMPONENT_SRCS "cmd_i2ctools.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_REQUIRES console spi_flash) +idf_component_register(SRCS "cmd_i2ctools.c" + INCLUDE_DIRS "." "../tools/" + REQUIRES esp_common + PRIV_REQUIRES freertos esp32 spi_flash newlib log console pthread +) -register_component() diff --git a/components/cmd_i2c/component.mk b/components/cmd_i2c/component.mk index 59d5335c..2215a6d8 100644 --- a/components/cmd_i2c/component.mk +++ b/components/cmd_i2c/component.mk @@ -1,4 +1,9 @@ # # Main Makefile. This is basically the same as a component makefile. # -COMPONENT_ADD_INCLUDEDIRS := . \ No newline at end of file +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG \ + -I$(COMPONENT_PATH)/../tools +COMPONENT_ADD_INCLUDEDIRS := . +COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools +COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../squeezelite-ota +COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index d14c2914..6521f3c2 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -10,6 +10,19 @@ if (!String.prototype.format) { }); }; } +var nvs_type_t = { + NVS_TYPE_U8 : 0x01, /*!< Type uint8_t */ + NVS_TYPE_I8 : 0x11, /*!< Type int8_t */ + NVS_TYPE_U16 : 0x02, /*!< Type uint16_t */ + NVS_TYPE_I16 : 0x12, /*!< Type int16_t */ + NVS_TYPE_U32 : 0x04, /*!< Type uint32_t */ + NVS_TYPE_I32 : 0x14, /*!< Type int32_t */ + NVS_TYPE_U64 : 0x08, /*!< Type uint64_t */ + NVS_TYPE_I64 : 0x18, /*!< Type int64_t */ + NVS_TYPE_STR : 0x21, /*!< Type string */ + NVS_TYPE_BLOB : 0x42, /*!< Type blob */ + NVS_TYPE_ANY : 0xff /*!< Must be last */ +} ; var releaseURL = 'https://api.github.com/repos/sle118/squeezelite-esp32/releases'; var recovery = false; @@ -189,16 +202,25 @@ $(document).ready(function(){ $("input#autoexec-cb").on("click", function() { var data = { 'timestamp': Date.now() }; autoexec = (this.checked)?1:0; - data['autoexec'] = autoexec; + data['config'] = {}; + data['config'] = { + autoexec : { + value : autoexec, + type : 33 + } + } + + showMessage('please wait for the ESP32 to reboot', 'WARNING'); $.ajax({ url: '/config.json', dataType: 'text', method: 'POST', cache: false, - headers: { "X-Custom-autoexec": autoexec }, +// headers: { "X-Custom-autoexec": autoexec }, contentType: 'application/json; charset=utf-8', - data: JSON.stringify(data), + data: JSON.stringify(data), + error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); @@ -232,14 +254,20 @@ $(document).ready(function(){ $("input#save-autoexec1").on("click", function() { var data = { 'timestamp': Date.now() }; autoexec1 = $("#autoexec1").val(); - data['autoexec1'] = autoexec1; + data['config'] = {}; + data['config'] = { + autoexec1 : { + value : autoexec1, + type : 33 + } + } $.ajax({ url: '/config.json', dataType: 'text', method: 'POST', cache: false, - headers: { "X-Custom-autoexec1": autoexec1 }, +// headers: { "X-Custom-autoexec1": autoexec1 }, contentType: 'application/json; charset=utf-8', data: JSON.stringify(data), error: function (xhr, ajaxOptions, thrownError) { @@ -254,15 +282,19 @@ $(document).ready(function(){ $("input#save-gpio").on("click", function() { var data = { 'timestamp': Date.now() }; + var config = {}; + var headers = {}; $("input.gpio").each(function() { var id = $(this)[0].id; var pin = $(this).val(); if (pin != '') { - headers["X-Custom-"+id] = pin; - data[id] = pin; + config[id] = {}; + config[id].value = pin; + config[id].type = nvs_type_t.NVS_TYPE_STR; } }); + data['config'] = config; $.ajax({ url: '/config.json', dataType: 'text', @@ -284,23 +316,40 @@ $(document).ready(function(){ $("#save-nvs").on("click", function() { var headers = {}; var data = { 'timestamp': Date.now() }; + var config = {}; $("input.nvs").each(function() { var key = $(this)[0].id; var val = $(this).val(); + var nvs_type = parseInt($(this)[0].attributes.nvs_type.nodeValue,10); if (key != '') { - headers["X-Custom-"+key] = val; - data[key] = {}; - data[key].value = val; - data[key].type = 33; + config[key] = {}; + if(nvs_type == nvs_type_t.NVS_TYPE_U8 + || nvs_type == nvs_type_t.NVS_TYPE_I8 + || nvs_type == nvs_type_t.NVS_TYPE_U16 + || nvs_type == nvs_type_t.NVS_TYPE_I16 + || nvs_type == nvs_type_t.NVS_TYPE_U32 + || nvs_type == nvs_type_t.NVS_TYPE_I32 + || nvs_type == nvs_type_t.NVS_TYPE_U64 + || nvs_type == nvs_type_t.NVS_TYPE_I64) { + config[key].value = parseInt(val); + } + else { + config[key].value = val; + } + + + config[key].type = nvs_type; } }); var key = $("#nvs-new-key").val(); var val = $("#nvs-new-value").val(); if (key != '') { - headers["X-Custom-"+key] = val; - data[key] = {}; - data[key].value = val; +// headers["X-Custom-" +key] = val; + config[key] = {}; + config[key].value = val; + config[key].type = 33; } + data['config'] = config; $.ajax({ url: '/config.json', dataType: 'text', @@ -308,7 +357,7 @@ $(document).ready(function(){ cache: false, headers: headers, contentType: 'application/json; charset=utf-8', - data: JSON.stringify(data), + data : JSON.stringify(data), error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); @@ -324,15 +373,21 @@ $(document).ready(function(){ if (blockFlashButton) return; blockFlashButton = true; var url = $("#fwurl").val(); - data['fwurl'] = url; + data['config'] = { + fwurl : { + value : url, + type : 33 + + } + }; + $.ajax({ url: '/config.json', dataType: 'text', method: 'POST', cache: false, - headers: { "X-Custom-fwurl": url }, contentType: 'application/json; charset=utf-8', - data: JSON.stringify(data), + data: JSON.stringify(data), error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); @@ -509,9 +564,13 @@ function performConnect(conntype){ dataType: 'text', method: 'POST', cache: false, - headers: { 'X-Custom-ssid': selectedSSID, 'X-Custom-pwd': pwd, 'X-Custom-host_name': dhcpname }, +// headers: { 'X-Custom-ssid': selectedSSID, 'X-Custom-pwd': pwd, 'X-Custom-host_name': dhcpname }, contentType: 'application/json; charset=utf-8', - data: { 'timestamp': Date.now()}, + data: JSON.stringify({ 'timestamp': Date.now(), + 'ssid' : selectedSSID, + 'pwd' : pwd, + 'host_name' : dhcpname + }), error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); @@ -737,7 +796,7 @@ function getConfig() { ""+ ""+key+""+ ""+ - ""+ + ""+ ""+ "" ); @@ -750,7 +809,7 @@ function getConfig() { ""+ ""+ ""+ - ""+ + ""+ // todo: provide a way to choose field type ""+ "" ); diff --git a/components/wifi-manager/component.mk b/components/wifi-manager/component.mk index d4559677..56b14191 100644 --- a/components/wifi-manager/component.mk +++ b/components/wifi-manager/component.mk @@ -8,8 +8,8 @@ # COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz #CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO \ - -I$(COMPONENT_PATH)/../tools +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG \ + -I$(COMPONENT_PATH)/../tools COMPONENT_ADD_INCLUDEDIRS := . COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../squeezelite-ota diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 49412df1..e770a7d3 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -45,30 +45,39 @@ function to process requests, decode URLs, serve files, etc. etc. #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "config.h" +#include "sys/param.h" +#include "esp_vfs.h" +#include "lwip/ip_addr.h" #define HTTP_STACK_SIZE (5*1024) #define FREE_AND_NULL(p) if(p!=NULL){ free(p); p=NULL;} - +const char str_na[]="N/A"; +#define STR_OR_NA(s) s?s:str_na /* @brief tag used for ESP serial console messages */ static const char TAG[] = "http_server"; /* @brief task handle for the http server */ -static TaskHandle_t task_http_server = NULL; -static StaticTask_t task_http_buffer; -#if RECOVERY_APPLICATION -static StackType_t task_http_stack[HTTP_STACK_SIZE]; -#else -static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE]; -#endif + SemaphoreHandle_t http_server_config_mutex = NULL; #define AUTH_TOKEN_SIZE 50 typedef struct session_context { char * auth_token; bool authenticated; + char * sess_ip_address; + u16_t port; } session_context_t; +union sockaddr_aligned { + struct sockaddr sa; + struct sockaddr_storage st; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +} aligned_sockaddr_t; +static const char redirect_payload1[]="Redirecting to Captive Portal

Please wait, refreshing. If page does not refresh, click here to login.

"; /** * @brief embedded binary data. @@ -103,40 +112,117 @@ extern const uint8_t index_html_end[] asm("_binary_index_html_end"); //const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://"; //const static char http_redirect_hdr_end[] = "/\n\n"; +char * alloc_get_http_header(httpd_req_t * req, const char * key){ + char* buf = NULL; + size_t buf_len; + + /* Get header value string length and allocate memory for length + 1, + * extra byte for null termination */ + buf_len = httpd_req_get_hdr_value_len(req, key) + 1; + if (buf_len > 1) { + buf = malloc(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); + } + } + return buf; +} + + +char * http_alloc_get_socket_address(httpd_req_t *req, u8_t local, in_port_t * portl) { + + socklen_t len; + union sockaddr_aligned addr; + len = sizeof(addr); + ip_addr_t * ip_addr=NULL; + char * ipstr = malloc(INET6_ADDRSTRLEN); + memset(ipstr,0x0,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) { + return strdup("httpd_req_to_sockfd error"); + } + ESP_LOGV_LOC(TAG,"httpd socket descriptor: %u", s); + + get_addr = local?&lwip_getsockname:&lwip_getpeername; + if(get_addr(s, (struct sockaddr *)&addr, &len) <0){ + ESP_LOGE_LOC(TAG,"Failed to retrieve socket address"); + sprintf(ipstr,"N/A (0.0.0.%u)",local); + } + else { + if (addr.sin.sin_family!= AF_INET) { + ip_addr = (ip_addr_t *)&(addr.sin6.sin6_addr); + inet_ntop(addr.sa.sa_family, ip_addr, ipstr, INET6_ADDRSTRLEN); + ESP_LOGV_LOC(TAG,"Processing an IPV6 address : %s", ipstr); + *portl = addr.sin6.sin6_port; + unmap_ipv4_mapped_ipv6(ip_2_ip4(ip_addr), ip_2_ip6(ip_addr)); + } + else { + ip_addr = (ip_addr_t *)&(addr.sin.sin_addr); + inet_ntop(addr.sa.sa_family, ip_addr, ipstr, INET6_ADDRSTRLEN); + ESP_LOGV_LOC(TAG,"Processing an IPV6 address : %s", ipstr); + *portl = addr.sin.sin_port; + } + inet_ntop(AF_INET, ip_addr, ipstr, INET6_ADDRSTRLEN); + ESP_LOGV_LOC(TAG,"Retrieved ip address:port = %s:%u",ipstr, *portl); + } + return ipstr; +} + /* Custom function to free context */ void free_ctx_func(void *ctx) { - if(ctx){ - if(ctx->auth_token) free(auth_token); - free(ctx); + session_context_t * context = (session_context_t *)ctx; + if(context){ + FREE_AND_NULL(context->auth_token); + FREE_AND_NULL(context->sess_ip_address); + free(context); } } -bool is_user_authenticated(httpd_req_t *req){ - if (! req->sess_ctx) { - req->sess_ctx = malloc(sizeof(session_context_t)); - memset(req->sess_ctx,0x00,sizeof(session_context_t)); - req->free_ctx = free_ctx_func; - } - session_context_t *ctx_data = (session_context_t*)req->sess_ctx; - if(ctx_data->authenticated){ - ESP_LOGD(TAG,"User is authenticated."); - return true; - } +session_context_t* get_session_context(httpd_req_t *req){ + if (! req->sess_ctx) { + req->sess_ctx = malloc(sizeof(session_context_t)); + memset(req->sess_ctx,0x00,sizeof(session_context_t)); + req->free_ctx = free_ctx_func; + // get the remote IP address only once per session + } + session_context_t *ctx_data = (session_context_t*)req->sess_ctx; + ctx_data->sess_ip_address = http_alloc_get_socket_address(req, 0, &ctx_data->port); + ESP_LOGI_LOC(TAG, "serving %s to peer %s port %u", req->uri, ctx_data->sess_ip_address , ctx_data->port); + return (session_context_t *)req->sess_ctx; +} - // todo: ask for user to authenticate - return false; +bool is_user_authenticated(httpd_req_t *req){ + session_context_t *ctx_data = get_session_context(req); + if(ctx_data->authenticated){ + ESP_LOGD_LOC(TAG,"User is authenticated."); + 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)); + + // todo: ask for user to authenticate + return false; } /* Copies the full path into destination buffer and returns - * pointer to path (skipping the preceding base path) */ -static const char* get_path_from_uri(char *dest, const char *base_path, const char *uri, size_t destsize) + * pointer to requested file name */ +static const char* get_path_from_uri(char *dest, const char *uri, size_t destsize) { - const size_t base_pathlen = strlen(base_path); size_t pathlen = strlen(uri); + memset(dest,0x0,destsize); const char *quest = strchr(uri, '?'); if (quest) { @@ -147,17 +233,29 @@ static const char* get_path_from_uri(char *dest, const char *base_path, const ch pathlen = MIN(pathlen, hash - uri); } - if (base_pathlen + pathlen + 1 > destsize) { + if ( pathlen + 1 > destsize) { /* Full path string won't fit into destination buffer */ return NULL; } - /* Construct full path (base + path) */ - strcpy(dest, base_path); - strlcpy(dest + base_pathlen, uri, pathlen + 1); + strlcpy(dest , uri, pathlen + 1); + + // strip trailing blanks + char * sr = dest+pathlen; + while(*sr== ' ') *sr-- = '\0'; + + char * last_fs = strchr(dest,'/'); + if(!last_fs) ESP_LOGD_LOC(TAG,"no / found in %s", dest); + char * p=last_fs; + while(p && *(++p)!='\0'){ + if(*p == '/') { + last_fs=p; + } + } + /* Return pointer to path, skipping the base */ - return dest + base_pathlen; + return last_fs? ++last_fs: dest; } #define IS_FILE_EXT(filename, ext) \ @@ -169,7 +267,7 @@ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filena if (IS_FILE_EXT(filename, ".pdf")) { return httpd_resp_set_type(req, "application/pdf"); } else if (IS_FILE_EXT(filename, ".html")) { - return httpd_resp_set_type(req, "text/html"); + return httpd_resp_set_type(req, HTTPD_TYPE_TEXT); } else if (IS_FILE_EXT(filename, ".jpeg")) { return httpd_resp_set_type(req, "image/jpeg"); } else if (IS_FILE_EXT(filename, ".ico")) { @@ -181,7 +279,7 @@ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filena } else if (IS_FILE_EXT(filename, ".js")) { return httpd_resp_set_type(req, "text/javascript"); } else if (IS_FILE_EXT(filename, ".json")) { - return httpd_resp_set_type(req, "application/json"); + return httpd_resp_set_type(req, HTTPD_TYPE_JSON); } /* This is a limited set only */ /* For any other type always set as plain text */ @@ -190,17 +288,16 @@ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filena static esp_err_t set_content_type_from_req(httpd_req_t *req) { char filepath[FILE_PATH_MAX]; - const char *filename = get_path_from_uri(filepath, "/" , - req->uri, sizeof(filepath)); + const char *filename = get_path_from_uri(filepath, req->uri, sizeof(filepath)); if (!filename) { - ESP_LOGE(TAG, "Filename is too long"); + ESP_LOGE_LOC(TAG, "Filename is too long"); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long"); return ESP_FAIL; } /* If name has trailing '/', respond with directory contents */ - if (filename[strlen(filename) - 1] == '/') { + if (filename[strlen(filename) - 1] == '/' && strlen(filename)>1) { httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Browsing files forbidden."); return ESP_FAIL; } @@ -209,11 +306,11 @@ static esp_err_t set_content_type_from_req(httpd_req_t *req) esp_err_t root_get_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); httpd_resp_set_hdr(req, "Accept-Encoding", "identity"); - if(!is_user_authenticated(httpd_req_t *req)){ + if(!is_user_authenticated(req)){ // todo: send password entry page and return } const size_t file_size = (index_html_end - index_html_start); @@ -226,13 +323,12 @@ esp_err_t root_get_handler(httpd_req_t *req){ esp_err_t resource_filehandler(httpd_req_t *req){ char filepath[FILE_PATH_MAX]; - ESP_LOGI(TAG, "serving [%s]", req->uri); + ESP_LOGI_LOC(TAG, "serving [%s]", req->uri); - const char *filename = get_path_from_uri(filepath, "/res/" , - req->uri, sizeof(filepath)); + const char *filename = get_path_from_uri(filepath, req->uri, sizeof(filepath)); if (!filename) { - ESP_LOGE(TAG, "Filename is too long"); + ESP_LOGE_LOC(TAG, "Filename is too long"); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long"); return ESP_FAIL; @@ -244,92 +340,92 @@ esp_err_t resource_filehandler(httpd_req_t *req){ return ESP_FAIL; } - if(strstr(line, "GET /code.js ")) { + if(strstr(filename, "code.js")) { const size_t file_size = (code_js_end - code_js_start); set_content_type_from_file(req, filename); httpd_resp_send(req, (const char *)code_js_start, file_size); } - else if(strstr(line, "GET /style.css ")) { + else if(strstr(filename, "style.css")) { set_content_type_from_file(req, filename); const size_t file_size = (style_css_end - style_css_start); httpd_resp_send(req, (const char *)style_css_start, file_size); - } else if(strstr(line, "GET /jquery.js ")) { + } else if(strstr(filename, "jquery.js")) { set_content_type_from_file(req, filename); httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); const size_t file_size = (jquery_gz_end - jquery_gz_start); httpd_resp_send(req, (const char *)jquery_gz_start, file_size); - }else if(strstr(line, "GET /popper.js")) { + }else if(strstr(filename, "popper.js")) { set_content_type_from_file(req, filename); httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); const size_t file_size = (popper_gz_end - popper_gz_start); httpd_resp_send(req, (const char *)popper_gz_start, file_size); } - else if(strstr(line, "GET /bootstrap.js ")) { + else if(strstr(filename, "bootstrap.js")) { set_content_type_from_file(req, filename); httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); const size_t file_size = (bootstrap_js_gz_end - bootstrap_js_gz_start); httpd_resp_send(req, (const char *)bootstrap_js_gz_start, file_size); } - else if(strstr(line, "GET /bootstrap.css")) { + else if(strstr(filename, "bootstrap.css")) { set_content_type_from_file(req, filename); httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); const size_t file_size = (bootstrap_css_gz_end - bootstrap_css_gz_start); httpd_resp_send(req, (const char *)bootstrap_css_gz_start, file_size); } else { - ESP_LOGE(TAG, "Unknown resource: %s", filepath); + ESP_LOGE_LOC(TAG, "Unknown resource [%s] from path [%s] ", filename,filepath); /* Respond with 404 Not Found */ httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist"); return ESP_FAIL; } - ESP_LOGI(TAG, "Resource sending complete"); + ESP_LOGI_LOC(TAG, "Resource sending complete"); return ESP_OK; } esp_err_t ap_scan_handler(httpd_req_t *req){ const char empty[] = "{}"; - ESP_LOGI(TAG, "serving [%s]", req->uri); - if(!is_user_authenticated(httpd_req_t *req)){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } wifi_manager_scan_async(); esp_err_t err = set_content_type_from_req(req); if(err == ESP_OK){ - httpd_resp_send(req, (const char *)empty, strlen(empty)); + httpd_resp_send(req, (const char *)empty, HTTPD_RESP_USE_STRLEN); } return err; } esp_err_t ap_get_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); - if(!is_user_authenticated(httpd_req_t *req)){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } /* 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 ) 10)){ + if( err == ESP_OK && wifi_manager_lock_json_buffer(( TickType_t ) 10)){ char *buff = wifi_manager_alloc_get_ap_list_json(); wifi_manager_unlock_json_buffer(); if(buff!=NULL){ - httpd_resp_send(req, (const char *)buff, strlen(buff)); + httpd_resp_send(req, (const char *)buff, HTTPD_RESP_USE_STRLEN); free(buff); } else { - ESP_LOGD(TAG, "Error retrieving ap list json string. "); + ESP_LOGD_LOC(TAG, "Error retrieving ap list json string. "); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to retrieve AP list"); } } else { httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "AP list unavailable"); - ESP_LOGE(TAG, "GET /ap.json failed to obtain mutex"); + ESP_LOGE_LOC(TAG, "GET /ap.json failed to obtain mutex"); } return err; } esp_err_t config_get_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); - if(!is_user_authenticated(httpd_req_t *req)){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } @@ -337,13 +433,13 @@ esp_err_t config_get_handler(httpd_req_t *req){ if(err == ESP_OK){ char * json = config_alloc_get_json(false); if(json==NULL){ - ESP_LOGD(TAG, "Error retrieving config json string. "); + ESP_LOGD_LOC(TAG, "Error retrieving config json string. "); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Error retrieving configuration object"); err=ESP_FAIL; } else { - ESP_LOGD(TAG, "config json : %s",json ); - httpd_resp_send(req, (const char *)json, strlen(json)); + ESP_LOGD_LOC(TAG, "config json : %s",json ); + httpd_resp_send(req, (const char *)json, HTTPD_RESP_USE_STRLEN); free(json); } } @@ -358,84 +454,122 @@ esp_err_t post_handler_buff_receive(httpd_req_t * req){ int received = 0; if (total_len >= SCRATCH_BUFSIZE) { /* Respond with 500 Internal Server Error */ + ESP_LOGE_LOC(TAG,"Received content was too long. "); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Content too long"); - return ESP_FAIL; + err = ESP_FAIL; } - while (cur_len < total_len) { + while (err == ESP_OK && cur_len < total_len) { received = httpd_req_recv(req, buf + cur_len, total_len); if (received <= 0) { /* Respond with 500 Internal Server Error */ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Failed to post control value"); - return ESP_FAIL; + ESP_LOGE_LOC(TAG,"Not all data was received. "); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Not all data was received"); + err = ESP_FAIL; + } + else { + cur_len += received; } - cur_len += received; } - buf[total_len] = '\0'; + if(err == ESP_OK) { + buf[total_len] = '\0'; + } + return err; } + esp_err_t config_post_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); bool bOTA=false; char * otaURL=NULL; esp_err_t err = post_handler_buff_receive(req); if(err!=ESP_OK){ return err; } - if(!is_user_authenticated(httpd_req_t *req)){ + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; cJSON *root = cJSON_Parse(buf); - cJSON *item=root->next; + if(root == NULL){ + ESP_LOGE_LOC(TAG, "Parsing config json failed. Received content was: %s",buf); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Unable to parse content."); + return ESP_FAIL; + } + + char * root_str = cJSON_Print(root); + if(root_str!=NULL){ + ESP_LOGE(TAG, "Processing config item: \n%s", root_str); + free(root_str); + } + + cJSON *item=cJSON_GetObjectItemCaseSensitive(root, "config"); + if(!item){ + ESP_LOGE_LOC(TAG, "Parsing config json failed. Received content was: %s",buf); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Unable to parse content."); + err = ESP_FAIL; + } + else{ + // navigate to the first child of the config structure + if(item->child) item=item->child; + } + while (item && err == ESP_OK) { cJSON *prev_item = item; item=item->next; - if(prev_item->name==NULL) { - ESP_LOGE(TAG,"Config value does not have a name"); + char * entry_str = cJSON_Print(prev_item); + if(entry_str!=NULL){ + ESP_LOGD_LOC(TAG, "Processing config item: \n%s", entry_str); + free(entry_str); + } + + if(prev_item->string==NULL) { + ESP_LOGD_LOC(TAG,"Config value does not have a name"); httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Value does not have a name."); err = ESP_FAIL; } if(err == ESP_OK){ - ESP_LOGI(TAG,"Found config value name [%s]", prev_item->name); + ESP_LOGI_LOC(TAG,"Found config value name [%s]", prev_item->string); nvs_type_t item_type= config_get_item_type(prev_item); if(item_type!=0){ void * val = config_safe_alloc_get_entry_value(item_type, prev_item); if(val!=NULL){ - if(strcmp(prev_item->name, "fwurl")==0) { + if(strcmp(prev_item->string, "fwurl")==0) { if(item_type!=NVS_TYPE_STR){ - ESP_LOGE(TAG,"Firmware url should be type %d. Found type %d instead.",NVS_TYPE_STR,item_type ); + ESP_LOGE_LOC(TAG,"Firmware url should be type %d. Found type %d instead.",NVS_TYPE_STR,item_type ); httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Wrong type for firmware URL."); err = ESP_FAIL; } else { // we're getting a request to do an OTA from that URL - ESP_LOGW(TAG, "Found OTA request!"); + ESP_LOGW_LOC(TAG, "Found OTA request!"); otaURL=strdup(val); bOTA=true; } } else { - if(config_set_value(item_type, last_parm_name , last_parm) != ESP_OK){ - ESP_LOGE(TAG,"Unable to store value for [%s]", prev_item->name); + if(config_set_value(item_type, prev_item->string , val) != ESP_OK){ + ESP_LOGE_LOC(TAG,"Unable to store value for [%s]", prev_item->string); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to store config value"); err = ESP_FAIL; } else { - ESP_LOGI(TAG,"Successfully set value for [%s]",prev_item->name); + ESP_LOGI_LOC(TAG,"Successfully set value for [%s]",prev_item->string); } } free(val); } else { - ESP_LOGE(TAG,"Value not found for [%s]", prev_item->name); - httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Missing value for entry."); + char messageBuffer[101]={}; + ESP_LOGE_LOC(TAG,"Value not found for [%s]", prev_item->string); + snprintf(messageBuffer,sizeof(messageBuffer),"Malformed config json. Missing value for entry %s.",prev_item->string); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, messageBuffer); err = ESP_FAIL; } } else { - ESP_LOGE(TAG,"Unable to determine the type of config value [%s]", prev_item->name); + ESP_LOGE_LOC(TAG,"Unable to determine the type of config value [%s]", prev_item->string); httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json. Missing value for entry."); err = ESP_FAIL; } @@ -445,15 +579,15 @@ esp_err_t config_post_handler(httpd_req_t *req){ if(err==ESP_OK){ set_content_type_from_req(req); - httpd_resp_sendstr(req, "{ok}"); + httpd_resp_sendstr(req, "{ \"result\" : \"OK\" }"); } cJSON_Delete(root); if(bOTA) { #if RECOVERY_APPLICATION - ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); + ESP_LOGW_LOC(TAG, "Starting process OTA for url %s",otaURL); #else - ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); + ESP_LOGW_LOC(TAG, "Restarting system to process OTA for url %s",otaURL); #endif wifi_manager_reboot_ota(otaURL); free(otaURL); @@ -462,18 +596,18 @@ esp_err_t config_post_handler(httpd_req_t *req){ } esp_err_t connect_post_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); char success[]="{}"; char * ssid=NULL; char * password=NULL; - char * host_name; + char * host_name=NULL; set_content_type_from_req(req); esp_err_t err = post_handler_buff_receive(req); if(err!=ESP_OK){ return err; } char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; - if(!is_user_authenticated(httpd_req_t *req)){ + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } @@ -486,32 +620,32 @@ esp_err_t connect_post_handler(httpd_req_t *req){ cJSON * ssid_object = cJSON_GetObjectItem(root, "ssid"); if(ssid_object !=NULL){ - ssid = (char *)config_safe_alloc_get_entry_value(ssid_object); + ssid = strdup(ssid_object->valuestring); } cJSON * password_object = cJSON_GetObjectItem(root, "pwd"); if(password_object !=NULL){ - password = (char *)config_safe_alloc_get_entry_value(password_object); + password = strdup(password_object->valuestring); } cJSON * host_name_object = cJSON_GetObjectItem(root, "host_name"); if(host_name_object !=NULL){ - host_name = (char *)config_safe_alloc_get_entry_value(host_name_object); + host_name = strdup(host_name_object->valuestring); } cJSON_Delete(root); if(host_name!=NULL){ if(config_set_value(NVS_TYPE_STR, "host_name", host_name) != ESP_OK){ - ESP_LOGW(TAG, "Unable to save host name configuration"); + ESP_LOGW_LOC(TAG, "Unable to save host name configuration"); } } 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(config->sta.ssid, ssid, sizeof(config->sta.ssid)+1); + strlcpy((char *)config->sta.ssid, ssid, sizeof(config->sta.ssid)+1); if(password){ - strlcpy(config->sta.password, password, sizeof(config->sta.password)+1); + strlcpy((char *)config->sta.password, password, sizeof(config->sta.password)+1); } - ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); + ESP_LOGD_LOC(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); wifi_manager_connect_async(); httpd_resp_send(req, (const char *)success, strlen(success)); } @@ -526,8 +660,8 @@ esp_err_t connect_post_handler(httpd_req_t *req){ } esp_err_t connect_delete_handler(httpd_req_t *req){ char success[]="{}"; - ESP_LOGI(TAG, "serving [%s]", req->uri); - if(!is_user_authenticated(httpd_req_t *req)){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } @@ -539,8 +673,8 @@ esp_err_t connect_delete_handler(httpd_req_t *req){ } esp_err_t reboot_ota_post_handler(httpd_req_t *req){ char success[]="{}"; - ESP_LOGI(TAG, "serving [%s]", req->uri); - if(!is_user_authenticated(httpd_req_t *req)){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } @@ -550,9 +684,9 @@ esp_err_t reboot_ota_post_handler(httpd_req_t *req){ return ESP_OK; } esp_err_t reboot_post_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); char success[]="{}"; - if(!is_user_authenticated(httpd_req_t *req)){ + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } @@ -562,9 +696,9 @@ esp_err_t reboot_post_handler(httpd_req_t *req){ return ESP_OK; } esp_err_t recovery_post_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); char success[]="{}"; - if(!is_user_authenticated(httpd_req_t *req)){ + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } @@ -573,10 +707,260 @@ esp_err_t recovery_post_handler(httpd_req_t *req){ wifi_manager_reboot(RECOVERY); return ESP_OK; } -esp_err_t status_post_handler(httpd_req_t *req){ - ESP_LOGI(TAG, "serving [%s]", req->uri); - char success[]="{}"; - if(!is_user_authenticated(httpd_req_t *req)){ + +bool is_captive_portal_host_name(http_req_t *req){ + const char * host_name=NULL; + const char * ap_host_name=NULL; + + ESP_LOGD_LOC(TAG, "Getting adapter host name"); + if((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { + ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); + } + else { + ESP_LOGD_LOC(TAG, "Host name is %s",host_name); + } + + ESP_LOGD_LOC(TAG, "Getting host name from request"); + char *req_host = alloc_get_http_header(req, "Host"); + + + + + + if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){ + ESP_LOGD_LOC(TAG, "Soft AP is enabled. getting ip info"); + // Access point is up and running. Get the current IP address + tcpip_adapter_ip_info_t ip_info; + esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info); + if(ap_ip_err != ESP_OK){ + ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err)); + } + else { + ESP_LOGD_LOC(TAG, "getting host name for TCPIP_ADAPTER_IF_AP"); + if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) { + ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err)); + err=err==ESP_OK?hn_err:err; + } + else { + ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name); + } + + ap_ip_address = malloc(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"); + ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX); + ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address); + } + } + + } + + + + + + + + + + + + + + + + + + + + if((request_contains_hostname = (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){ + ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host); + } + else if((request_contains_hostname = (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){ + ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host); + } + + FREE_AND_NULL(req_host); + + +} +esp_err_t redirect_200_ev_handler(httpd_req_t *req){ + esp_err_t err=ESP_OK; + const char location_prefix[] = "http://"; + char * ap_ip_address=NULL; + char * remote_ip=NULL; + const char * host_name=NULL; + in_port_t port=0; + + ESP_LOGD_LOC(TAG, "Getting adapter host name"); + if((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { + ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); + } + else { + ESP_LOGD_LOC(TAG, "Host name is %s",host_name); + } + + ESP_LOGD_LOC(TAG, "Getting remote socket address"); + 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); + snprintf(redirect, buf_size,"%s%s%s%s%s%s%s",redirect_payload1, location_prefix, ap_ip_address,redirect_payload2, location_prefix, ap_ip_address,redirect_payload3); + ESP_LOGI_LOC(TAG, "Redirecting host [%s] to %s",remote_ip, redirect); + httpd_resp_set_type(req, "text/plain"); + httpd_resp_set_hdr(req,"Cache-Control","no-cache"); + httpd_resp_set_status(req, "200 OK"); + httpd_resp_send(req, redirect, HTTPD_RESP_USE_STRLEN); + FREE_AND_NULL(redirect); + FREE_AND_NULL(ap_ip_address); + FREE_AND_NULL(remote_ip); + return ESP_OK; +} +esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ + esp_err_t err=ESP_OK; + + const char location_prefix[] = "http://"; + const char * host_name=NULL; + const char * ap_host_name=NULL; + char * user_agent=NULL; + char * remote_ip=NULL; + char * sta_ip_address=NULL; + char * ap_ip_address=NULL; + char * socket_local_address=NULL; + char * redirect = NULL; + bool request_contains_hostname = false; + bool request_contains_ap_ip_address = false; + bool request_is_sta_ip_address = false; + bool connected_to_ap_ip_interface = false; + bool connected_to_sta_ip_interface = false; + bool useragentiscaptivenetwork = false; + + ESP_LOGD_LOC(TAG, "serving [%s]", 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(); + } + else { + ESP_LOGE(TAG,"Unable to obtain local IP address from WiFi Manager."); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , NULL); + } + + in_port_t port=0; + ESP_LOGD_LOC(TAG, "Getting remote socket address"); + remote_ip = http_alloc_get_socket_address(req,0, &port); + + ESP_LOGD_LOC(TAG, "Getting host name from request"); + char *req_host = alloc_get_http_header(req, "Host"); + + user_agent = alloc_get_http_header(req,"User-Agent"); + if((useragentiscaptivenetwork = strcasestr(user_agent,"CaptiveNetworkSupport"))==true){ + ESP_LOGD_LOC(TAG,"Found user agent that supports captive networks! [%s]",user_agent); + } + + esp_err_t hn_err = ESP_OK; + ESP_LOGD_LOC(TAG, "Getting adapter host name"); + if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { + ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err)); + err=err==ESP_OK?hn_err:err; + } + else { + ESP_LOGD_LOC(TAG, "Host name is %s",host_name); + } + + + in_port_t loc_port=0; + ESP_LOGD_LOC(TAG, "Getting local socket address"); + socket_local_address= http_alloc_get_socket_address(req,1, &loc_port); + + ESP_LOGD_LOC(TAG, "checking if soft AP is enabled"); + if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){ + ESP_LOGD_LOC(TAG, "Soft AP is enabled. getting ip info"); + // Access point is up and running. Get the current IP address + tcpip_adapter_ip_info_t ip_info; + esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info); + if(ap_ip_err != ESP_OK){ + ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err)); + } + else { + ESP_LOGD_LOC(TAG, "getting host name for TCPIP_ADAPTER_IF_AP"); + if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) { + ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err)); + err=err==ESP_OK?hn_err:err; + } + else { + ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name); + } + + ap_ip_address = malloc(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"); + ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX); + ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address); + } + } + + } + + ESP_LOGD_LOC(TAG, "Peer IP: %s [port %u], System AP IP address: %s, System host: %s. Requested Host: [%s], uri [%s]",STR_OR_NA(remote_ip), port, STR_OR_NA(ap_ip_address), STR_OR_NA(host_name), STR_OR_NA(req_host), req->uri); + /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ + /* determine if Host is from the STA IP address */ + + if((request_contains_hostname = (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){ + ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host); + } + else if((request_contains_hostname = (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){ + ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host); + } + if((request_contains_ap_ip_address = (ap_ip_address!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_ip_address))== true){ + ESP_LOGD_LOC(TAG,"http request host is access point ip address %s", req_host); + } + if((connected_to_ap_ip_interface = (ap_ip_address!=NULL) && (socket_local_address!=NULL) && strcasestr(socket_local_address,ap_ip_address))==true){ + ESP_LOGD_LOC(TAG,"http request is connected to access point interface IP %s", ap_ip_address); + } + if((request_is_sta_ip_address = (sta_ip_address!=NULL) && (req_host!=NULL) && strcasestr(req_host,sta_ip_address))==true){ + ESP_LOGD_LOC(TAG,"http request host is WiFi client ip address %s", req_host); + } + if((connected_to_sta_ip_interface = (sta_ip_address!=NULL) && (socket_local_address!=NULL) && strcasestr(sta_ip_address,socket_local_address))==true){ + ESP_LOGD_LOC(TAG,"http request is connected to WiFi client ip address %s", sta_ip_address); + } + + if((error == 0) || (error == HTTPD_404_NOT_FOUND && connected_to_ap_ip_interface && !(request_contains_ap_ip_address || request_contains_hostname ))) { + + // known polling url's, send redirect 302 + size_t buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1; + redirect = malloc(buf_size); + snprintf(redirect, buf_size,"%s%s",location_prefix, ap_ip_address); + ESP_LOGI_LOC(TAG, "Redirecting host [%s] to %s",remote_ip, redirect); + httpd_resp_set_type(req, "text/plain"); + httpd_resp_set_status(req, "302 Found"); + httpd_resp_set_hdr(req,"Location",redirect); + httpd_resp_send(req, "", HTTPD_RESP_USE_STRLEN); + + } + else { + ESP_LOGD_LOC(TAG,"URL not found, and not processing captive portal so throw regular 404 error"); + httpd_resp_send_err(req, error, NULL); + } + + FREE_AND_NULL(socket_local_address); + FREE_AND_NULL(redirect); + FREE_AND_NULL(req_host); + FREE_AND_NULL(user_agent); + + FREE_AND_NULL(sta_ip_address); + FREE_AND_NULL(ap_ip_address); + FREE_AND_NULL(remote_ip); + return err; + +} +esp_err_t redirect_ev_handler(httpd_req_t *req){ + return redirect_processor(req,0); +} +esp_err_t status_get_handler(httpd_req_t *req){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } @@ -600,188 +984,21 @@ esp_err_t status_post_handler(httpd_req_t *req){ return ESP_OK; } + esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){ - ESP_LOGI(TAG, "serving [%s]", req->uri); - char success[]=""; - if(!is_user_authenticated(httpd_req_t *req)){ - // todo: redirect to login page - // return ESP_OK; - } + esp_err_t err = ESP_OK; + if(error != HTTPD_404_NOT_FOUND){ - return httpd_resp_send_err(req, error, NULL); + err = httpd_resp_send_err(req, error, NULL); + } + else { + err = redirect_processor(req,error); } - char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); - if(ap_ip_address==NULL){ - ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to retrieve default AP IP Address"); - return ESP_FAIL; - } - - struct httpd_req_aux *ra = req->aux; - //UF_HOST - - - // ip_addr_t remote_add; - // err_t err; - - - // u16_t buflen; - // u16_t port; - - - // ESP_LOGV(TAG, "Getting remote device IP address."); - // netconn_getaddr(conn, &remote_add, &port, 0); - // char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); - // ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); - // err = netconn_recv(conn, &inbuf); - // if(err == ERR_OK) { - // ESP_LOGV(TAG, "Getting data buffer."); - // netbuf_data(inbuf, (void**)&buf, &buflen); - // dump_net_buffer(buf, buflen); - // int lenH = 0; - // /* extract the first line of the request */ - // char *save_ptr = buf; - // char *line = strtok_r(save_ptr, new_line, &save_ptr); - // char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); - // char * host = malloc(lenH+1); - // memset(host,0x00,lenH+1); - // if(lenH>0){ - // strlcpy(host,temphost,lenH+1); - // } - // ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); - // - // if(line) { - // - // /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ - // const char * host_name=NULL; - // if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - // ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - // } - // else { - // ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); - // } - // - // /* determine if Host is from the STA IP address */ - // wifi_manager_lock_sta_ip_string(portMAX_DELAY); - // bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; - // wifi_manager_unlock_sta_ip_string(); - // bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); - // - // if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { - // ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); - // netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); - // netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); - // netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - set_content_type_from_req(req); - httpd_resp_send(req, (const char *)NULL, 0); - wifi_manager_reboot(RECOVERY); - FREE_AND_NULL(ap_ip_address); - return ESP_OK; + return err; } - - - -//void http_server_netconn_serve(struct netconn *conn) { -// -// struct netbuf *inbuf; -// char *buf = NULL; -// u16_t buflen; -// err_t err; -// ip_addr_t remote_add; -// u16_t port; -// ESP_LOGV(TAG, "Serving page. Getting device AP address."); -// const char new_line[2] = "\n"; -// char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); -// if(ap_ip_address==NULL){ -// ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); -// netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); -// netconn_close(conn); -// return; -// } -// ESP_LOGV(TAG, "Getting remote device IP address."); -// netconn_getaddr(conn, &remote_add, &port, 0); -// char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); -// ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); -// err = netconn_recv(conn, &inbuf); -// if(err == ERR_OK) { -// ESP_LOGV(TAG, "Getting data buffer."); -// netbuf_data(inbuf, (void**)&buf, &buflen); -// dump_net_buffer(buf, buflen); -// int lenH = 0; -// /* extract the first line of the request */ -// char *save_ptr = buf; -// char *line = strtok_r(save_ptr, new_line, &save_ptr); -// char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); -// char * host = malloc(lenH+1); -// memset(host,0x00,lenH+1); -// if(lenH>0){ -// strlcpy(host,temphost,lenH+1); -// } -// ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); -// -// if(line) { -// -// /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ -// const char * host_name=NULL; -// if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { -// ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); -// } -// else { -// ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); -// } -// -// /* determine if Host is from the STA IP address */ -// wifi_manager_lock_sta_ip_string(portMAX_DELAY); -// bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; -// wifi_manager_unlock_sta_ip_string(); -// bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); -// -// if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { -// ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); -// netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); -// netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); -// netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); -// } -// else { -// //static stuff -// -//} - - - diff --git a/components/wifi-manager/http_server_handlers.h b/components/wifi-manager/http_server_handlers.h index eee41611..93cdcac2 100644 --- a/components/wifi-manager/http_server_handlers.h +++ b/components/wifi-manager/http_server_handlers.h @@ -37,6 +37,7 @@ function to process requests, decode URLs, serve files, etc. etc. #include #include #include +#include "esp_http_server.h" #include "wifi_manager.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -58,10 +59,21 @@ function to process requests, decode URLs, serve files, etc. etc. #include "lwip/priv/api_msg.h" #include "lwip/priv/tcp_priv.h" #include "lwip/priv/tcpip_priv.h" +#include "esp_vfs.h" +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + #ifdef __cplusplus extern "C" { #endif + +#define ESP_LOGE_LOC(t,str, ...) ESP_LOGE(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define ESP_LOGI_LOC(t,str, ...) ESP_LOGI(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define ESP_LOGD_LOC(t,str, ...) ESP_LOGD(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define ESP_LOGW_LOC(t,str, ...) ESP_LOGW(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define ESP_LOGV_LOC(t,str, ...) ESP_LOGV(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) + + esp_err_t root_get_handler(httpd_req_t *req); esp_err_t resource_filehandler(httpd_req_t *req); esp_err_t resource_filehandler(httpd_req_t *req); @@ -77,12 +89,20 @@ esp_err_t connect_delete_handler(httpd_req_t *req); esp_err_t reboot_ota_post_handler(httpd_req_t *req); esp_err_t reboot_post_handler(httpd_req_t *req); esp_err_t recovery_post_handler(httpd_req_t *req); -esp_err_t status_post_handler(httpd_req_t *req); +esp_err_t status_get_handler(httpd_req_t *req); esp_err_t ap_scan_handler(httpd_req_t *req); +esp_err_t redirect_ev_handler(httpd_req_t *req); +esp_err_t redirect_200_ev_handler(httpd_req_t *req); + + esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error); +#define SCRATCH_BUFSIZE (10240) +#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128) - - +typedef struct rest_server_context { + char base_path[ESP_VFS_PATH_MAX + 1]; + char scratch[SCRATCH_BUFSIZE]; +} rest_server_context_t; /** * @brief RTOS task for the HTTP server. Do not start manually. * @see void http_server_start() @@ -93,7 +113,7 @@ void CODE_RAM_LOCATION http_server(void *pvParameters); void CODE_RAM_LOCATION http_server_netconn_serve(struct netconn *conn); /* @brief create the task for the http server */ -void CODE_RAM_LOCATION http_server_start(); +esp_err_t CODE_RAM_LOCATION http_server_start(); /** * @brief gets a char* pointer to the first occurence of header_name withing the complete http request request. diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index 6bfe8c6d..26b03523 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -5,19 +5,19 @@ - - - - - - + + + + + + - - - + + + - + esp32-wifi-manager diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c index 44766880..ff7b3b4c 100644 --- a/components/wifi-manager/wifi_manager.c +++ b/components/wifi-manager/wifi_manager.c @@ -63,6 +63,7 @@ Contains the freeRTOS task and all necessary support #include "cmd_system.h" #include "http_server_handlers.h" + #ifndef RECOVERY_APPLICATION #define RECOVERY_APPLICATION 0 #endif @@ -509,7 +510,7 @@ char * get_mac_string(uint8_t mac[6]){ char * macStr=malloc(LOCAL_MAC_SIZE); memset(macStr, 0x00, LOCAL_MAC_SIZE); - snprintf(macStr, LOCAL_MAC_SIZE-1,MACSTR, MAC2STR(mac)); + snprintf(macStr, LOCAL_MAC_SIZE,MACSTR, MAC2STR(mac)); return macStr; } @@ -1093,7 +1094,7 @@ void wifi_manager( void * pvParameters ){ BaseType_t xStatus; EventBits_t uxBits; uint8_t retries = 0; - esp_err_t err=ESP_OK; + /* start http server */ http_server_start(); diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 16cb1b0d..c80f9123 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -18,7 +18,7 @@ * along with this program. If not, see . * */ -#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + #include "http_server_handlers.h" #include "esp_log.h" #include "esp_http_server.h" @@ -32,19 +32,8 @@ static const char TAG[] = "http_server"; -static httpd_handle_t server = NULL; -#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128) -#define SCRATCH_BUFSIZE (10240) - -typedef struct rest_server_context { - char base_path[ESP_VFS_PATH_MAX + 1]; - char scratch[SCRATCH_BUFSIZE]; -} rest_server_context_t; -#define ESP_LOGE_LOC(t,str, ...) ESP_LOGE(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define ESP_LOGI_LOC(t,str, ...) ESP_LOGI(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define ESP_LOGD_LOC(t,str, ...) ESP_LOGD(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__) - - +static httpd_handle_t _server = NULL; +rest_server_context_t *rest_context = NULL; void register_common_handlers(httpd_handle_t server){ httpd_uri_t res_get = { .uri = "/res/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context }; @@ -80,43 +69,71 @@ void register_regular_handlers(httpd_handle_t server){ httpd_uri_t connect_delete = { .uri = "/connect.json", .method = HTTP_DELETE, .handler = connect_delete_handler, .user_ctx = rest_context }; httpd_register_uri_handler(server, &connect_delete); + + + // from https://github.com/tripflex/wifi-captive-portal/blob/master/src/mgos_wifi_captive_portal.c + // https://unix.stackexchange.com/questions/432190/why-isnt-androids-captive-portal-detection-triggering-a-browser-window + // Known HTTP GET requests to check for Captive Portal + + ///kindle-wifi/wifiredirect.html Kindle when requested with com.android.captiveportallogin + ///kindle-wifi/wifistub.html Kindle before requesting with captive portal login window (maybe for detection?) + + + httpd_uri_t connect_redirect_1 = { .uri = "/mobile/status.php", .method = HTTP_GET, .handler = redirect_200_ev_handler, .user_ctx = rest_context };// Android 8.0 (Samsung s9+) + httpd_register_uri_handler(server, &connect_redirect_1); + httpd_uri_t connect_redirect_2 = { .uri = "/generate_204", .method = HTTP_GET, .handler = redirect_200_ev_handler, .user_ctx = rest_context };// Android + httpd_register_uri_handler(server, &connect_redirect_2); + httpd_uri_t connect_redirect_3 = { .uri = "/gen_204", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// Android 9.0 + httpd_register_uri_handler(server, &connect_redirect_3); + httpd_uri_t connect_redirect_4 = { .uri = "/ncsi.txt", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// Windows + httpd_register_uri_handler(server, &connect_redirect_4); + httpd_uri_t connect_redirect_5 = { .uri = "/hotspot-detect.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context }; // iOS 8/9 + httpd_register_uri_handler(server, &connect_redirect_5); + httpd_uri_t connect_redirect_6 = { .uri = "/library/test/success.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// iOS 8/9 + httpd_register_uri_handler(server, &connect_redirect_6); + httpd_uri_t connect_redirect_7 = { .uri = "/hotspotdetect.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context }; // iOS + httpd_register_uri_handler(server, &connect_redirect_7); + httpd_uri_t connect_redirect_8 = { .uri = "/success.txt", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context }; // OSX + httpd_register_uri_handler(server, &connect_redirect_8); + + + ESP_LOGD(TAG,"Registering default error handler for 404"); + httpd_register_err_handler(server, HTTPD_404_NOT_FOUND,&err_handler); + } esp_err_t http_server_start() { - ESP_LOGI(REST_TAG, "Initializing HTTP Server"); - rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t)); + ESP_LOGI(TAG, "Initializing HTTP Server"); + rest_context = calloc(1, 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_handle_t server = NULL; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.max_uri_handlers = 20; + config.max_open_sockets = 8; config.uri_match_fn = httpd_uri_match_wildcard; - //todo: use this to configure session token? + //todo: use the endpoint below to configure session token? // config.open_fn - ESP_LOGI(REST_TAG, "Starting HTTP Server"); - esp_err_t err= httpd_start(&server, &config); + ESP_LOGI(TAG, "Starting HTTP Server"); + esp_err_t err= httpd_start(&_server, &config); if(err != ESP_OK){ ESP_LOGE_LOC(TAG,"Start server failed"); } else { - register_common_handlers(server); - register_regular_handlers(server); + register_common_handlers(_server); + register_regular_handlers(_server); } - register_err_handler(server, HTTPD_404_NOT_FOUND,&err_handler); - return err; } - - /* Function to free context */ void adder_free_func(void *ctx) { @@ -124,135 +141,6 @@ void adder_free_func(void *ctx) free(ctx); } -/* This handler keeps accumulating data that is posted to it into a per - * socket/session context. And returns the result. - */ -esp_err_t adder_post_handler(httpd_req_t *req) -{ - /* Log total visitors */ - unsigned *visitors = (unsigned *)req->user_ctx; - ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors)); - - char buf[10]; - char outbuf[50]; - int ret; - - /* Read data received in the request */ - ret = httpd_req_recv(req, buf, sizeof(buf)); - if (ret <= 0) { - if (ret == HTTPD_SOCK_ERR_TIMEOUT) { - httpd_resp_send_408(req); - } - return ESP_FAIL; - } - - buf[ret] = '\0'; - int val = atoi(buf); - ESP_LOGI(TAG, "/adder handler read %d", val); - - /* Create session's context if not already available */ - if (! req->sess_ctx) { - ESP_LOGI(TAG, "/adder allocating new session"); - req->sess_ctx = malloc(sizeof(int)); - req->free_ctx = adder_free_func; - *(int *)req->sess_ctx = 0; - } - - /* Add the received data to the context */ - int *adder = (int *)req->sess_ctx; - *adder += val; - - /* Respond with the accumulated value */ - snprintf(outbuf, sizeof(outbuf),"%d", *adder); - httpd_resp_send(req, outbuf, strlen(outbuf)); - return ESP_OK; -} - -/* This handler gets the present value of the accumulator */ -esp_err_t adder_get_handler(httpd_req_t *req) -{ - /* Log total visitors */ - unsigned *visitors = (unsigned *)req->user_ctx; - ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors)); - - char outbuf[50]; - - /* Create session's context if not already available */ - if (! req->sess_ctx) { - ESP_LOGI(TAG, "/adder GET allocating new session"); - req->sess_ctx = malloc(sizeof(int)); - req->free_ctx = adder_free_func; - *(int *)req->sess_ctx = 0; - } - ESP_LOGI(TAG, "/adder GET handler send %d", *(int *)req->sess_ctx); - - /* Respond with the accumulated value */ - snprintf(outbuf, sizeof(outbuf),"%d", *((int *)req->sess_ctx)); - httpd_resp_send(req, outbuf, strlen(outbuf)); - return ESP_OK; -} - -/* This handler resets the value of the accumulator */ -esp_err_t adder_put_handler(httpd_req_t *req) -{ - /* Log total visitors */ - unsigned *visitors = (unsigned *)req->user_ctx; - ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors)); - - char buf[10]; - char outbuf[50]; - int ret; - - /* Read data received in the request */ - ret = httpd_req_recv(req, buf, sizeof(buf)); - if (ret <= 0) { - if (ret == HTTPD_SOCK_ERR_TIMEOUT) { - httpd_resp_send_408(req); - } - return ESP_FAIL; - } - - buf[ret] = '\0'; - int val = atoi(buf); - ESP_LOGI(TAG, "/adder PUT handler read %d", val); - - /* Create session's context if not already available */ - if (! req->sess_ctx) { - ESP_LOGI(TAG, "/adder PUT allocating new session"); - req->sess_ctx = malloc(sizeof(int)); - req->free_ctx = adder_free_func; - } - *(int *)req->sess_ctx = val; - - /* Respond with the reset value */ - snprintf(outbuf, sizeof(outbuf),"%d", *((int *)req->sess_ctx)); - httpd_resp_send(req, outbuf, strlen(outbuf)); - return ESP_OK; -} - -/* Maintain a variable which stores the number of times - * the "/adder" URI has been visited */ -static unsigned visitors = 0; - - -httpd_handle_t start_webserver(void) -{ - httpd_config_t config = HTTPD_DEFAULT_CONFIG(); - // Start the httpd server - ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); - - if (httpd_start(&server, &config) == ESP_OK) { - // Set URI handlers - ESP_LOGI(TAG, "Registering URI handlers"); - httpd_register_uri_handler(server, &adder_get); - httpd_register_uri_handler(server, &adder_put); - httpd_register_uri_handler(server, &adder_post); - return server; - } - - ESP_LOGI(TAG, "Error starting server!"); - return NULL; -} void stop_webserver(httpd_handle_t server) { @@ -264,7 +152,7 @@ void stop_webserver(httpd_handle_t server) - +#if 0 if(strstr(line, "GET / ")) { netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY); @@ -481,3 +369,4 @@ netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY); free(host); } +#endif diff --git a/main/config.c b/main/config.c index 5dd5bcf2..7d0fa9ca 100644 --- a/main/config.c +++ b/main/config.c @@ -70,30 +70,30 @@ void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag); void * pval = config_alloc_get(nt, key);\ if(pval!=NULL){ *value = *(t * )pval; free(pval); return ESP_OK; }\ return ESP_FAIL;} -#ifdef RECOVERY_APPLICATION +#ifndef RECOVERY_APPLICATION static void * malloc_fn(size_t sz){ - void * ptr = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM); if(ptr==NULL){ ESP_LOGE(TAG,"malloc_fn: unable to allocate memory!"); } return ptr; } -static void * free_fn(void * ptr){ - if(ptr!=NULL){ - free(ptr); - } - else { - ESP_LOGW(TAG,"free_fn: Cannot free null pointer!"); - } - return NULL; -} +//static void * free_fn(void * ptr){ +// if(ptr!=NULL){ +// free(ptr); +// } +// else { +// ESP_LOGW(TAG,"free_fn: Cannot free null pointer!"); +// } +// return NULL; +//} #endif void init_cJSON(){ + +#ifndef RECOVERY_APPLICATION static cJSON_Hooks hooks; // initialize cJSON hooks it uses SPIRAM memory // as opposed to IRAM -#ifndef RECOVERY_APPLICATION // In squeezelite mode, allocate memory from PSRAM. Otherwise allocate from internal RAM // as recovery will lock flash access when erasing FLASH or writing to OTA partition. hooks.malloc_fn=&malloc_fn; @@ -320,7 +320,7 @@ void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry){ } nvs_type_t type = config_get_entry_type(entry); - if(nvs_type != type){ + if (nvs_type != type){ // requested value type different than the stored type char * entry_str = cJSON_PrintUnformatted(entry); if(entry_str!=NULL){ @@ -704,31 +704,6 @@ esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){ return result; } -esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){ - esp_err_t result = ESP_OK; - if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){ - ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT); - result = ESP_FAIL; - } - cJSON * entry = config_set_value_safe(nvs_type, key, value); - if(entry == NULL){ - result = ESP_FAIL; - } - else{ - char * entry_str = cJSON_PrintUnformatted(entry); - if(entry_str!=NULL){ - ESP_LOGV(TAG,"config_set_value result: \n%s",entry_str); - free(entry_str); - } - else { - ESP_LOGV(TAG,"config_set_value completed"); - } - - } - config_unlock(); - return result; -} - IMPLEMENT_SET_DEFAULT(uint8_t,NVS_TYPE_U8); diff --git a/main/config.h b/main/config.h index b0cf3579..6308793f 100644 --- a/main/config.h +++ b/main/config.h @@ -3,6 +3,7 @@ #include #include "esp_system.h" #include "nvs_utilities.h" +#include "cJSON.h" #ifdef __cplusplus extern "C" { From 5b1abf0fc908d127f5ece7fdbc73bf7096ded21c Mon Sep 17 00:00:00 2001 From: Sebastien Date: Wed, 22 Jan 2020 19:49:20 -0500 Subject: [PATCH 05/46] httpd wip --- components/config/config.c | 2 +- components/config/config.h | 4 +- components/wifi-manager/http_server.c | 655 ------------------ .../wifi-manager/wifi_manager_http_server.c | 2 +- main/esp_app_main.c | 1 - 5 files changed, 5 insertions(+), 659 deletions(-) delete mode 100644 components/wifi-manager/http_server.c diff --git a/components/config/config.c b/components/config/config.c index 74c22f0f..c167a186 100644 --- a/components/config/config.c +++ b/components/config/config.c @@ -578,7 +578,7 @@ void config_delete_key(const char *key){ ESP_LOGD(TAG, "Deleting nvs entry for [%s]", key); if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){ ESP_LOGE(TAG, "Unable to lock config for delete"); - return false; + return ; } esp_err_t err = nvs_open_from_partition(settings_partition, current_namespace, NVS_READWRITE, &nvs); if (err == ESP_OK) { diff --git a/components/config/config.h b/components/config/config.h index f83c7276..4fa9014a 100644 --- a/components/config/config.h +++ b/components/config/config.h @@ -2,6 +2,7 @@ #include #include #include "nvs.h" +#include "cJSON.h" #ifdef __cplusplus extern "C" { @@ -37,4 +38,5 @@ void * config_alloc_get(nvs_type_t nvs_type, const char *key) ; bool wait_for_commit(); char * config_alloc_get_json(bool bFormatted); esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value); - +nvs_type_t config_get_item_type(cJSON * entry); +void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry); diff --git a/components/wifi-manager/http_server.c b/components/wifi-manager/http_server.c deleted file mode 100644 index d0d071b8..00000000 --- a/components/wifi-manager/http_server.c +++ /dev/null @@ -1,655 +0,0 @@ -/* -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 -*/ - -#include "http_server.h" -#include "cmd_system.h" -#include -#include "squeezelite-ota.h" -#include "nvs_utilities.h" -#include -#include -#include "cJSON.h" -#include "esp_system.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "config.h" - -#define HTTP_STACK_SIZE (5*1024) - -/* @brief tag used for ESP serial console messages */ -static const char TAG[] = "http_server"; -/* @brief task handle for the http server */ -static TaskHandle_t task_http_server = NULL; -static StaticTask_t task_http_buffer; -#if RECOVERY_APPLICATION -static StackType_t task_http_stack[HTTP_STACK_SIZE]; -#else -static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE]; -#endif -SemaphoreHandle_t http_server_config_mutex = NULL; - -/** - * @brief embedded binary data. - * @see file "component.mk" - * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data - */ -extern const uint8_t style_css_start[] asm("_binary_style_css_start"); -extern const uint8_t style_css_end[] asm("_binary_style_css_end"); -extern const uint8_t jquery_gz_start[] asm("_binary_jquery_min_js_gz_start"); -extern const uint8_t jquery_gz_end[] asm("_binary_jquery_min_js_gz_end"); -extern const uint8_t popper_gz_start[] asm("_binary_popper_min_js_gz_start"); -extern const uint8_t popper_gz_end[] asm("_binary_popper_min_js_gz_end"); -extern const uint8_t bootstrap_js_gz_start[] asm("_binary_bootstrap_min_js_gz_start"); -extern const uint8_t bootstrap_js_gz_end[] asm("_binary_bootstrap_min_js_gz_end"); -extern const uint8_t bootstrap_css_gz_start[] asm("_binary_bootstrap_min_css_gz_start"); -extern const uint8_t bootstrap_css_gz_end[] asm("_binary_bootstrap_min_css_gz_end"); -extern const uint8_t code_js_start[] asm("_binary_code_js_start"); -extern const uint8_t code_js_end[] asm("_binary_code_js_end"); -extern const uint8_t index_html_start[] asm("_binary_index_html_start"); -extern const uint8_t index_html_end[] asm("_binary_index_html_end"); - - -/* const http headers stored in ROM */ -const static char http_hdr_template[] = "HTTP/1.1 200 OK\nContent-type: %s\nAccept-Ranges: bytes\nContent-Length: %d\nContent-Encoding: %s\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_html_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/html\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_css_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/css\nCache-Control: public, max-age=31536000\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_js_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_svg_hdr[] = "HTTP/1.1 200 OK\nContent-type: image/svg+xml\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_400_hdr[] = "HTTP/1.1 400 Bad Request\nContent-Length: 0\n\n"; -const static char http_404_hdr[] = "HTTP/1.1 404 Not Found\nContent-Length: 0\n\n"; -const static char http_503_hdr[] = "HTTP/1.1 503 Service Unavailable\nContent-Length: 0\n\n"; -const static char http_ok_json_no_cache_hdr[] = "HTTP/1.1 200 OK\nContent-type: application/json\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://"; -const static char http_redirect_hdr_end[] = "/\n\n"; - - -void http_server_start() { - ESP_LOGD(TAG, "http_server_start "); - if(task_http_server == NULL) { - task_http_server = xTaskCreateStatic( (TaskFunction_t) &http_server, "http_server", HTTP_STACK_SIZE, NULL, - WIFI_MANAGER_TASK_PRIORITY, task_http_stack, &task_http_buffer); - } -} -void http_server(void *pvParameters) { - http_server_config_mutex = xSemaphoreCreateMutex(); - struct netconn *conn, *newconn; - err_t err; - conn = netconn_new(NETCONN_TCP); - netconn_bind(conn, IP_ADDR_ANY, 80); - netconn_listen(conn); - ESP_LOGI(TAG, "HTTP Server listening on 80/tcp"); - do { - err = netconn_accept(conn, &newconn); - if(err == ERR_OK) { - http_server_netconn_serve(newconn); - netconn_delete(newconn); - } - else - { - ESP_LOGE(TAG, "Error accepting new connection. Terminating HTTP server"); - } - taskYIELD(); /* allows the freeRTOS scheduler to take over if needed. */ - } while(err == ERR_OK); - - netconn_close(conn); - netconn_delete(conn); - vSemaphoreDelete(http_server_config_mutex); - http_server_config_mutex = NULL; - vTaskDelete( NULL ); -} - - -char* http_server_get_header(char *request, char *header_name, int *len) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - - ptr = strstr(request, header_name); - if(ptr) { - ret = ptr + strlen(header_name); - ptr = ret; - while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') { - (*len)++; - ptr++; - } - return ret; - } - return NULL; -} -char* http_server_search_header(char *request, char *header_name, int *len, char ** parm_name, char ** next_position, char * bufEnd) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - int currentLength=0; - - ESP_LOGV(TAG, "searching for header name: [%s]", header_name); - ptr = strstr(request, header_name); - - - if(ptr!=NULL && ptr0) { - ESP_LOGD(TAG, "Found Header Line %s ", last); - //Content-Type: application/json - } - else { - ESP_LOGD(TAG, "Found end of headers"); - bHeaders = false; - } - last=ptr; - } - else { - //ESP_LOGD(TAG, "Body content: %s", last); - //cJSON * json = cJSON_Parse(last); - //cJSON_Delete(json); - //todo: implement body json parsing - // right now, body is coming as compressed, so we need some type of decompression to happen. - return; - } - } - return ; - -} - -void dump_net_buffer(void * buf, u16_t buflen) { - char * curbuf = malloc(buflen+1); - ESP_LOGV(TAG, "netconn buffer, length=%u",buflen); - if(curbuf==NULL) { - ESP_LOGE(TAG, "Unable to show netconn buffer. Malloc failed"); - } - memset(curbuf,0x0, buflen+1); - memcpy(curbuf,buf,buflen); - ESP_LOGV(TAG, "netconn buffer content:\n%s",curbuf); - free(curbuf); -} - -void http_server_netconn_serve(struct netconn *conn) { - - struct netbuf *inbuf; - char *buf = NULL; - u16_t buflen = 0; - err_t err; - ip_addr_t remote_add; - u16_t port; - ESP_LOGV(TAG, "Serving page. Getting device AP address."); - const char new_line[2] = "\n"; - char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); - if(ap_ip_address==NULL){ - ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - netconn_close(conn); - return; - } - ESP_LOGV(TAG, "Getting remote device IP address."); - netconn_getaddr(conn, &remote_add, &port, 0); - char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); - ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); - - u16_t bufsize = 0; - netconn_set_recvtimeout(conn, 50); - while (netconn_recv(conn, &inbuf) == ERR_OK) { - do { - u8_t *rcvbuf; - u16_t rcvlen; - netbuf_data(inbuf, (void**)&rcvbuf, &rcvlen); - dump_net_buffer(rcvbuf, rcvlen); - if (buflen + rcvlen > bufsize) { - bufsize += 2048; - buf = realloc(buf, bufsize); - } - memcpy(buf + buflen, rcvbuf, rcvlen); - buflen += rcvlen; - ESP_LOGI(TAG, "received netbuf of %hu", rcvlen); - } while (netbuf_next(inbuf) != -1); - netbuf_delete(inbuf); - } - - if(buflen) { - ESP_LOGV(TAG, "Getting data buffer."); - int lenH = 0; - /* extract the first line of the request */ - char *save_ptr = buf; - char *line = strtok_r(save_ptr, new_line, &save_ptr); - char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); - char * host = malloc(lenH+1); - memset(host,0x00,lenH+1); - if(lenH>0){ - strlcpy(host,temphost,lenH+1); - } - ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); - - if(line) { - - /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ - const char * host_name=NULL; - if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - } - else { - ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); - } - - /* determine if Host is from the STA IP address */ - wifi_manager_lock_sta_ip_string(portMAX_DELAY); - bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; - wifi_manager_unlock_sta_ip_string(); - bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); - - if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { - ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); - netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); - netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); - netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); - } - else { - //static stuff - /* default page */ - if(strstr(line, "GET / ")) { - netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, index_html_start, index_html_end- index_html_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /code.js ")) { - netconn_write(conn, http_js_hdr, sizeof(http_js_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, code_js_start, code_js_end - code_js_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /style.css ")) { - netconn_write(conn, http_css_hdr, sizeof(http_css_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, style_css_start, style_css_end - style_css_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /jquery.js ")) { - http_server_send_resource_file(conn,jquery_gz_start, jquery_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /popper.js ")) { - http_server_send_resource_file(conn,popper_gz_start, popper_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.js ")) { - http_server_send_resource_file(conn,bootstrap_js_gz_start, bootstrap_js_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.css ")) { - http_server_send_resource_file(conn,bootstrap_css_gz_start, bootstrap_css_gz_end, "text/css", "gzip" ); - } - - //dynamic stuff - else if(strstr(line, "GET /scan.json ")) { - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - } - else if(strstr(line, "GET /ap.json ")) { - /* if we can get the mutex, write the last version of the AP list */ - ESP_LOGI(TAG, "Processing ap.json request"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - char *buff = wifi_manager_alloc_get_ap_list_json(); - wifi_manager_unlock_json_buffer(); - if(buff!=NULL){ - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - ESP_LOGD(TAG, "Error retrieving ap list json string. "); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex"); - } - /* request a wifi scan */ - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - ESP_LOGI(TAG, "Done serving ap.json"); - } - else if(strstr(line, "GET /config.json ")) { - ESP_LOGI(TAG, "Serving config.json"); - ESP_LOGI(TAG, "About to get config from flash"); - http_server_send_config_json(conn); - ESP_LOGD(TAG, "Done serving config.json"); - } - else if(strstr(line, "POST /config.json ")) { - ESP_LOGI(TAG, "Serving POST config.json"); - int lenA=0; - char * last_parm=save_ptr; - char * next_parm=save_ptr; - char * last_parm_name=NULL; - bool bErrorFound=false; - bool bOTA=false; - char * otaURL=NULL; - // todo: implement json body parsing - //http_server_process_config(conn,save_ptr); - - while(last_parm!=NULL) { - // Search will return - ESP_LOGD(TAG, "Getting parameters from X-Custom headers"); - last_parm = http_server_search_header(next_parm, "X-Custom-", &lenA, &last_parm_name,&next_parm,buf+buflen); - if(last_parm!=NULL && last_parm_name!=NULL) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST config.json, config %s=%s", last_parm_name, last_parm); - if(strcmp(last_parm_name, "fwurl")==0) { - // we're getting a request to do an OTA from that URL - ESP_LOGW(TAG, "Found OTA request!"); - otaURL=strdup(last_parm); - bOTA=true; - } - else { - ESP_LOGV(TAG, "http_server_netconn_serve: POST config.json Storing parameter"); - if(config_set_value(NVS_TYPE_STR, last_parm_name , last_parm) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save nvs value."); - } - } - } - if(last_parm_name!=NULL) { - free(last_parm_name); - last_parm_name=NULL; - } - } - if(bErrorFound) { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); //400 invalid request - } - else { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - if(bOTA) { - -#if RECOVERY_APPLICATION - ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); -#else - ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); -#endif - wifi_manager_reboot_ota(otaURL); - free(otaURL); - } - } - ESP_LOGI(TAG, "Done Serving POST config.json"); - } - else if(strstr(line, "POST /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST /connect.json"); - bool found = false; - int lenS = 0, lenP = 0, lenN = 0; - char *ssid = NULL, *password = NULL; - ssid = http_server_get_header(save_ptr, "X-Custom-ssid: ", &lenS); - password = http_server_get_header(save_ptr, "X-Custom-pwd: ", &lenP); - char * new_host_name_b = http_server_get_header(save_ptr, "X-Custom-host_name: ", &lenN); - if(lenN > 0){ - lenN++; - char * new_host_name = malloc(lenN); - strlcpy(new_host_name, new_host_name_b, lenN); - if(config_set_value(NVS_TYPE_STR, "host_name", new_host_name) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save host name configuration"); - } - free(new_host_name); - } - - if(ssid && lenS <= MAX_SSID_SIZE && password && lenP <= MAX_PASSWORD_SIZE) { - wifi_config_t* config = wifi_manager_get_wifi_sta_config(); - memset(config, 0x00, sizeof(wifi_config_t)); - memcpy(config->sta.ssid, ssid, lenS); - memcpy(config->sta.password, password, lenP); - ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); - wifi_manager_connect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - found = true; - } - else{ - ESP_LOGE(TAG, "SSID or Password invalid"); - } - - - if(!found) { - /* bad request the authentification header is not complete/not the correct format */ - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request the authentification header is not complete/not the correct format"); - } - - ESP_LOGI(TAG, "http_server_netconn_serve: done serving connect.json"); - } - else if(strstr(line, "DELETE /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: DELETE /connect.json"); - /* request a disconnection from wifi and forget about it */ - wifi_manager_disconnect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - ESP_LOGI(TAG, "http_server_netconn_serve: done serving DELETE /connect.json"); - } - else if(strstr(line, "POST /reboot_ota.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot_ota.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(OTA); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot_ota.json"); - } - else if(strstr(line, "POST /reboot.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RESTART); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot.json"); - } - else if(strstr(line, "POST /recovery.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST recovery.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RECOVERY); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST recovery.json"); - } - else if(strstr(line, "GET /status.json ")) { - ESP_LOGI(TAG, "Serving status.json"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - char *buff = wifi_manager_alloc_get_ip_info_json(); - wifi_manager_unlock_json_buffer(); - if(buff) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /status failed to obtain mutex"); - } - ESP_LOGI(TAG, "Done Serving status.json"); - } - else { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request from host: %s, request %s",remote_address, line); - } - } - } - else { - ESP_LOGE(TAG, "URL not found processing for remote host : %s",remote_address); - netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY); - } - free(host); - free(buf); - } - - free(ap_ip_address); - free(remote_address); - netconn_close(conn); - /* free the buffer */ - -} - -bool http_server_lock_json_object(TickType_t xTicksToWait) { - ESP_LOGD(TAG, "Locking config json object"); - if(http_server_config_mutex) { - if( xSemaphoreTake( http_server_config_mutex, xTicksToWait ) == pdTRUE ) { - ESP_LOGV(TAG, "config Json object locked!"); - return true; - } - else { - ESP_LOGW(TAG, "Semaphore take failed. Unable to lock config Json object mutex"); - return false; - } - } - else { - ESP_LOGW(TAG, "Unable to lock config Json object mutex"); - return false; - } - -} - -void http_server_unlock_json_object() { - ESP_LOGD(TAG, "Unlocking json buffer!"); - xSemaphoreGive( http_server_config_mutex ); -} - -void strreplace(char *src, char *str, char *rep) -{ - char *p = strstr(src, str); - if(p) - { - int len = strlen(src)+strlen(rep)-strlen(str); - char r[len]; - memset(r, 0, len); - if( p >= src ) { - strncpy(r, src, p-src); - r[p-src]='\0'; - strncat(r, rep, strlen(rep)); - strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); - strcpy(src, r); - strreplace(p+strlen(rep), str, rep); - } - } -} - diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index c80f9123..92c7820c 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -114,7 +114,7 @@ esp_err_t http_server_start() httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.max_uri_handlers = 20; - config.max_open_sockets = 8; + config.max_open_sockets = 5; config.uri_match_fn = httpd_uri_match_wildcard; //todo: use the endpoint below to configure session token? // config.open_fn diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 9a5de0d7..118db2ab 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -40,7 +40,6 @@ #include "lwip/err.h" #include "lwip/netdb.h" #include "nvs_utilities.h" -#include "http_server.h" #include "trace.h" #include "wifi_manager.h" #include "squeezelite-ota.h" From 0cdb34032e8e46f42b377b6621af41fcd9d1ce0f Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 23 Jan 2020 18:01:25 -0500 Subject: [PATCH 06/46] more attempts to support automatic redirection on connect --- .../wifi-manager/http_server_handlers.c | 237 +++++++++--------- .../wifi-manager/wifi_manager_http_server.c | 4 +- 2 files changed, 118 insertions(+), 123 deletions(-) diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index a32b8892..67c24773 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -111,6 +111,8 @@ extern const uint8_t index_html_end[] asm("_binary_index_html_end"); //const static char http_ok_json_no_cache_hdr[] = "HTTP/1.1 200 OK\nContent-type: application/json\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; //const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://"; //const static char http_redirect_hdr_end[] = "/\n\n"; +esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error); + char * alloc_get_http_header(httpd_req_t * req, const char * key){ char* buf = NULL; @@ -172,7 +174,65 @@ char * http_alloc_get_socket_address(httpd_req_t *req, u8_t local, in_port_t * p } return ipstr; } +bool is_captive_portal_host_name(httpd_req_t *req){ + const char * host_name=NULL; + const char * ap_host_name=NULL; + char * ap_ip_address=NULL; + bool request_contains_hostname = false; + esp_err_t hn_err =ESP_OK, err=ESP_OK; + ESP_LOGD_LOC(TAG, "Getting adapter host name"); + if((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { + ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); + } + else { + ESP_LOGD_LOC(TAG, "Host name is %s",host_name); + } + ESP_LOGD_LOC(TAG, "Getting host name from request"); + char *req_host = alloc_get_http_header(req, "Host"); + + if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){ + ESP_LOGD_LOC(TAG, "Soft AP is enabled. getting ip info"); + // Access point is up and running. Get the current IP address + tcpip_adapter_ip_info_t ip_info; + esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info); + if(ap_ip_err != ESP_OK){ + ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err)); + } + else { + ESP_LOGD_LOC(TAG, "getting host name for TCPIP_ADAPTER_IF_AP"); + if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) { + ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err)); + err=err==ESP_OK?hn_err:err; + } + else { + ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name); + } + + ap_ip_address = malloc(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"); + ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX); + ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address); + } + } + + } + + + if((request_contains_hostname = (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){ + ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host); + } + else if((request_contains_hostname = (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){ + ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host); + } + + FREE_AND_NULL(ap_ip_address); + FREE_AND_NULL(req_host); + + return request_contains_hostname; +} /* Custom function to free context */ void free_ctx_func(void *ctx) @@ -200,6 +260,7 @@ session_context_t* get_session_context(httpd_req_t *req){ bool is_user_authenticated(httpd_req_t *req){ session_context_t *ctx_data = get_session_context(req); + if(ctx_data->authenticated){ ESP_LOGD_LOC(TAG,"User is authenticated."); return true; @@ -252,8 +313,6 @@ static const char* get_path_from_uri(char *dest, const char *uri, size_t destsiz last_fs=p; } } - - /* Return pointer to path, skipping the base */ return last_fs? ++last_fs: dest; } @@ -708,109 +767,83 @@ esp_err_t recovery_post_handler(httpd_req_t *req){ return ESP_OK; } -bool is_captive_portal_host_name(httpd_req_t *req){ - const char * host_name=NULL; - const char * ap_host_name=NULL; - char * ap_ip_address=NULL; - bool request_contains_hostname = false; - esp_err_t hn_err =ESP_OK, err=ESP_OK; - ESP_LOGD_LOC(TAG, "Getting adapter host name"); - if((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - } - else { - ESP_LOGD_LOC(TAG, "Host name is %s",host_name); - } +char * get_ap_ip_address(){ + static char ap_ip_address[IP4ADDR_STRLEN_MAX]={}; - ESP_LOGD_LOC(TAG, "Getting host name from request"); - char *req_host = alloc_get_http_header(req, "Host"); + tcpip_adapter_ip_info_t ip_info; + esp_err_t err=ESP_OK; + memset(ap_ip_address, 0x00, sizeof(ap_ip_address)); + ESP_LOGD_LOC(TAG, "checking if soft AP is enabled"); if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){ ESP_LOGD_LOC(TAG, "Soft AP is enabled. getting ip info"); // Access point is up and running. Get the current IP address - tcpip_adapter_ip_info_t ip_info; - esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info); - if(ap_ip_err != ESP_OK){ - ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err)); + err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info); + if(err != ESP_OK){ + ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(err)); } else { - ESP_LOGD_LOC(TAG, "getting host name for TCPIP_ADAPTER_IF_AP"); - if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) { - ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err)); - err=err==ESP_OK?hn_err:err; - } - else { - ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name); - } - - ap_ip_address = malloc(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"); - ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX); - ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address); - } + ESP_LOGV_LOC(TAG, "Converting soft ip address to string"); + ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX); + ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address); } - } - - - if((request_contains_hostname = (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){ - ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host); - } - else if((request_contains_hostname = (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){ - ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host); - } - - FREE_AND_NULL(ap_ip_address); - FREE_AND_NULL(req_host); - - return request_contains_hostname; + else{ + ESP_LOGD_LOC(TAG,"AP Is not enabled. Returning blank string"); + } + return ap_ip_address; } -esp_err_t redirect_200_ev_handler(httpd_req_t *req){ - esp_err_t err=ESP_OK; +esp_err_t process_redirect(httpd_req_t *req, const char * status){ const char location_prefix[] = "http://"; - char * ap_ip_address=NULL; + char * ap_ip_address=get_ap_ip_address(); char * remote_ip=NULL; - const char * host_name=NULL; in_port_t port=0; - ESP_LOGD_LOC(TAG, "Getting adapter host name"); - if((err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - } - else { - ESP_LOGD_LOC(TAG, "Host name is %s",host_name); - } - - ESP_LOGD_LOC(TAG, "Getting remote socket address"); - remote_ip = http_alloc_get_socket_address(req,0, &port); + ESP_LOGD_LOC(TAG, "Getting remote socket address"); + 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); - snprintf(redirect, buf_size,"%s%s%s%s%s%s%s",redirect_payload1, location_prefix, ap_ip_address,redirect_payload2, location_prefix, ap_ip_address,redirect_payload3); - ESP_LOGI_LOC(TAG, "Redirecting host [%s] to %s",remote_ip, redirect); - httpd_resp_set_type(req, "text/plain"); + + if(strcasestr(status,"302")){ + size_t url_buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1; + char * redirect_url = malloc(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); + httpd_resp_set_hdr(req,"Location",redirect_url); + snprintf(redirect, buf_size,"OK"); + FREE_AND_NULL(redirect_url); + } + else { + + snprintf(redirect, buf_size,"%s%s%s%s%s%s%s",redirect_payload1, location_prefix, ap_ip_address,redirect_payload2, location_prefix, ap_ip_address,redirect_payload3); + ESP_LOGW_LOC(TAG, "Responding to host [%s] (from uri %s) with redirect html page %s",remote_ip, req->uri,redirect); + } + + httpd_resp_set_type(req, HTTPD_TYPE_TEXT); httpd_resp_set_hdr(req,"Cache-Control","no-cache"); - httpd_resp_set_status(req, "200 OK"); + httpd_resp_set_status(req, status); httpd_resp_send(req, redirect, HTTPD_RESP_USE_STRLEN); FREE_AND_NULL(redirect); - FREE_AND_NULL(ap_ip_address); FREE_AND_NULL(remote_ip); + + return ESP_OK; +} +esp_err_t redirect_200_ev_handler(httpd_req_t *req){ + ESP_LOGD_LOC(TAG,"Processing known redirect url %s",req->uri); + process_redirect(req,"200 OK"); return ESP_OK; } esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ esp_err_t err=ESP_OK; - - const char location_prefix[] = "http://"; const char * host_name=NULL; const char * ap_host_name=NULL; char * user_agent=NULL; char * remote_ip=NULL; char * sta_ip_address=NULL; - char * ap_ip_address=NULL; + char * ap_ip_address=get_ap_ip_address(); char * socket_local_address=NULL; - char * redirect = NULL; bool request_contains_hostname = false; bool request_contains_ap_ip_address = false; bool request_is_sta_ip_address = false; @@ -818,7 +851,7 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ bool connected_to_sta_ip_interface = false; bool useragentiscaptivenetwork = false; - ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + ESP_LOGW_LOC(TAG, "Invalid URL requested: [%s]", 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(); @@ -829,61 +862,33 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ } in_port_t port=0; - ESP_LOGD_LOC(TAG, "Getting remote socket address"); + ESP_LOGV_LOC(TAG, "Getting remote socket address"); remote_ip = http_alloc_get_socket_address(req,0, &port); - ESP_LOGD_LOC(TAG, "Getting host name from request"); + ESP_LOGV_LOC(TAG, "Getting host name from request"); char *req_host = alloc_get_http_header(req, "Host"); user_agent = alloc_get_http_header(req,"User-Agent"); if((useragentiscaptivenetwork = strcasestr(user_agent,"CaptiveNetworkSupport"))==true){ - ESP_LOGD_LOC(TAG,"Found user agent that supports captive networks! [%s]",user_agent); + ESP_LOGW_LOC(TAG,"Found user agent that supports captive networks! [%s]",user_agent); } esp_err_t hn_err = ESP_OK; - ESP_LOGD_LOC(TAG, "Getting adapter host name"); + ESP_LOGV_LOC(TAG, "Getting adapter host name"); if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err)); err=err==ESP_OK?hn_err:err; } else { - ESP_LOGD_LOC(TAG, "Host name is %s",host_name); + ESP_LOGV_LOC(TAG, "Host name is %s",host_name); } in_port_t loc_port=0; - ESP_LOGD_LOC(TAG, "Getting local socket address"); + ESP_LOGV_LOC(TAG, "Getting local socket address"); socket_local_address= http_alloc_get_socket_address(req,1, &loc_port); - ESP_LOGD_LOC(TAG, "checking if soft AP is enabled"); - if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){ - ESP_LOGD_LOC(TAG, "Soft AP is enabled. getting ip info"); - // Access point is up and running. Get the current IP address - tcpip_adapter_ip_info_t ip_info; - esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info); - if(ap_ip_err != ESP_OK){ - ESP_LOGE_LOC(TAG, "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err)); - } - else { - ESP_LOGD_LOC(TAG, "getting host name for TCPIP_ADAPTER_IF_AP"); - if((hn_err = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) { - ESP_LOGE_LOC(TAG, "Unable to get host name. Error: %s",esp_err_to_name(hn_err)); - err=err==ESP_OK?hn_err:err; - } - else { - ESP_LOGD_LOC(TAG, "Soft AP Host name is %s",ap_host_name); - } - ap_ip_address = malloc(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"); - ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX); - ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address); - } - } - - } ESP_LOGD_LOC(TAG, "Peer IP: %s [port %u], System AP IP address: %s, System host: %s. Requested Host: [%s], uri [%s]",STR_OR_NA(remote_ip), port, STR_OR_NA(ap_ip_address), STR_OR_NA(host_name), STR_OR_NA(req_host), req->uri); /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ @@ -909,16 +914,7 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ } if((error == 0) || (error == HTTPD_404_NOT_FOUND && connected_to_ap_ip_interface && !(request_contains_ap_ip_address || request_contains_hostname ))) { - - // known polling url's, send redirect 302 - size_t buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1; - redirect = malloc(buf_size); - snprintf(redirect, buf_size,"%s%s",location_prefix, ap_ip_address); - ESP_LOGI_LOC(TAG, "Redirecting host [%s] to %s",remote_ip, redirect); - httpd_resp_set_type(req, "text/plain"); - httpd_resp_set_status(req, "302 Found"); - httpd_resp_set_hdr(req,"Location",redirect); - httpd_resp_send(req, "", HTTPD_RESP_USE_STRLEN); + process_redirect(req,"302 Found"); } else { @@ -927,12 +923,11 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ } FREE_AND_NULL(socket_local_address); - FREE_AND_NULL(redirect); + FREE_AND_NULL(req_host); FREE_AND_NULL(user_agent); FREE_AND_NULL(sta_ip_address); - FREE_AND_NULL(ap_ip_address); FREE_AND_NULL(remote_ip); return err; diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 92c7820c..3286d1c4 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -85,8 +85,8 @@ void register_regular_handlers(httpd_handle_t server){ httpd_register_uri_handler(server, &connect_redirect_2); httpd_uri_t connect_redirect_3 = { .uri = "/gen_204", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// Android 9.0 httpd_register_uri_handler(server, &connect_redirect_3); - httpd_uri_t connect_redirect_4 = { .uri = "/ncsi.txt", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// Windows - httpd_register_uri_handler(server, &connect_redirect_4); +// httpd_uri_t connect_redirect_4 = { .uri = "/ncsi.txt", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// Windows +// httpd_register_uri_handler(server, &connect_redirect_4); httpd_uri_t connect_redirect_5 = { .uri = "/hotspot-detect.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context }; // iOS 8/9 httpd_register_uri_handler(server, &connect_redirect_5); httpd_uri_t connect_redirect_6 = { .uri = "/library/test/success.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// iOS 8/9 From dd594245f6ee81e9a834bebd8b2895f6375dee23 Mon Sep 17 00:00:00 2001 From: sebastien Date: Wed, 5 Feb 2020 20:58:17 -0500 Subject: [PATCH 07/46] Merge master --- Makefile | 1 + components/raop/component.mk | 2 +- components/raop/raop.c | 2 +- components/services/monitor.c | 1 + components/telnet/telnet.c | 2 +- components/wifi-manager/http_server.c | 654 -------------------------- 6 files changed, 5 insertions(+), 657 deletions(-) delete mode 100644 components/wifi-manager/http_server.c diff --git a/Makefile b/Makefile index 566e6447..2c004921 100644 --- a/Makefile +++ b/Makefile @@ -14,3 +14,4 @@ PROJECT_NAME?=squeezelite include $(IDF_PATH)/make/project.mk +CFLAGS += -Wno-error=format-overflow -Wno-error=stringop-truncation \ No newline at end of file diff --git a/components/raop/component.mk b/components/raop/component.mk index 9614efb8..e06d07e7 100644 --- a/components/raop/component.mk +++ b/components/raop/component.mk @@ -7,7 +7,7 @@ # please read the SDK documents if you need to do this. # -CFLAGS += -fstack-usage \ +CFLAGS += -fstack-usage\ -I$(COMPONENT_PATH)/../tools \ -I$(COMPONENT_PATH)/../codecs/inc/alac \ -I$(PROJECT_PATH)/main/ diff --git a/components/raop/raop.c b/components/raop/raop.c index 565e281c..41981f0a 100644 --- a/components/raop/raop.c +++ b/components/raop/raop.c @@ -933,7 +933,7 @@ static unsigned int token_decode(const char *token) val += pos(token[i]); } if (marker > 2) - return DECODE_ERROR; + return DECODE_ERROR; return (marker << 24) | val; } diff --git a/components/services/monitor.c b/components/services/monitor.c index 09a4b008..75cb3dd6 100644 --- a/components/services/monitor.c +++ b/components/services/monitor.c @@ -20,6 +20,7 @@ #include "led.h" #include "globdefs.h" #include "config.h" +#include "accessors.h" #define MONITOR_TIMER (10*1000) diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index 7f46bc0e..f1343702 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -311,7 +311,7 @@ static void handleLogBuffer(int partnerSocket, UBaseType_t count){ UBaseType_t uxItemsWaiting; UBaseType_t uxBytesToSend=count; - vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, &uxItemsWaiting); + vRingbufferGetInfo(buf_handle, NULL, NULL, NULL,NULL, &uxItemsWaiting); if( partnerSocket ==0 && (uxItemsWaiting*100 / log_buf_size) <75){ // We still have some room in the ringbuffer and there's no telnet // connection yet, so bail out for now. diff --git a/components/wifi-manager/http_server.c b/components/wifi-manager/http_server.c deleted file mode 100644 index 44d233a7..00000000 --- a/components/wifi-manager/http_server.c +++ /dev/null @@ -1,654 +0,0 @@ -/* -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 -*/ - -#include "http_server.h" -#include "cmd_system.h" -#include -#include "squeezelite-ota.h" -#include "nvs_utilities.h" -#include -#include -#include "cJSON.h" -#include "esp_system.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "config.h" - -#define HTTP_STACK_SIZE (5*1024) - -/* @brief tag used for ESP serial console messages */ -static const char TAG[] = "http_server"; -/* @brief task handle for the http server */ -static TaskHandle_t task_http_server = NULL; -static StaticTask_t task_http_buffer; -#if RECOVERY_APPLICATION -static StackType_t task_http_stack[HTTP_STACK_SIZE]; -#else -static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE]; -#endif -SemaphoreHandle_t http_server_config_mutex = NULL; - -/** - * @brief embedded binary data. - * @see file "component.mk" - * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data - */ -extern const uint8_t style_css_start[] asm("_binary_style_css_start"); -extern const uint8_t style_css_end[] asm("_binary_style_css_end"); -extern const uint8_t jquery_gz_start[] asm("_binary_jquery_min_js_gz_start"); -extern const uint8_t jquery_gz_end[] asm("_binary_jquery_min_js_gz_end"); -extern const uint8_t popper_gz_start[] asm("_binary_popper_min_js_gz_start"); -extern const uint8_t popper_gz_end[] asm("_binary_popper_min_js_gz_end"); -extern const uint8_t bootstrap_js_gz_start[] asm("_binary_bootstrap_min_js_gz_start"); -extern const uint8_t bootstrap_js_gz_end[] asm("_binary_bootstrap_min_js_gz_end"); -extern const uint8_t bootstrap_css_gz_start[] asm("_binary_bootstrap_min_css_gz_start"); -extern const uint8_t bootstrap_css_gz_end[] asm("_binary_bootstrap_min_css_gz_end"); -extern const uint8_t code_js_start[] asm("_binary_code_js_start"); -extern const uint8_t code_js_end[] asm("_binary_code_js_end"); -extern const uint8_t index_html_start[] asm("_binary_index_html_start"); -extern const uint8_t index_html_end[] asm("_binary_index_html_end"); - - -/* const http headers stored in ROM */ -const static char http_hdr_template[] = "HTTP/1.1 200 OK\nContent-type: %s\nAccept-Ranges: bytes\nContent-Length: %d\nContent-Encoding: %s\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_html_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/html\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_css_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/css\nCache-Control: public, max-age=31536000\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_js_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_400_hdr[] = "HTTP/1.1 400 Bad Request\nContent-Length: 0\n\n"; -const static char http_404_hdr[] = "HTTP/1.1 404 Not Found\nContent-Length: 0\n\n"; -const static char http_503_hdr[] = "HTTP/1.1 503 Service Unavailable\nContent-Length: 0\n\n"; -const static char http_ok_json_no_cache_hdr[] = "HTTP/1.1 200 OK\nContent-type: application/json\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://"; -const static char http_redirect_hdr_end[] = "/\n\n"; - - -void http_server_start() { - ESP_LOGD(TAG, "http_server_start "); - if(task_http_server == NULL) { - task_http_server = xTaskCreateStatic( (TaskFunction_t) &http_server, "http_server", HTTP_STACK_SIZE, NULL, - WIFI_MANAGER_TASK_PRIORITY, task_http_stack, &task_http_buffer); - } -} -void http_server(void *pvParameters) { - http_server_config_mutex = xSemaphoreCreateMutex(); - struct netconn *conn, *newconn; - err_t err; - conn = netconn_new(NETCONN_TCP); - netconn_bind(conn, IP_ADDR_ANY, 80); - netconn_listen(conn); - ESP_LOGI(TAG, "HTTP Server listening on 80/tcp"); - do { - err = netconn_accept(conn, &newconn); - if(err == ERR_OK) { - http_server_netconn_serve(newconn); - netconn_delete(newconn); - } - else - { - ESP_LOGE(TAG, "Error accepting new connection. Terminating HTTP server"); - } - taskYIELD(); /* allows the freeRTOS scheduler to take over if needed. */ - } while(err == ERR_OK); - - netconn_close(conn); - netconn_delete(conn); - vSemaphoreDelete(http_server_config_mutex); - http_server_config_mutex = NULL; - vTaskDelete( NULL ); -} - - -char* http_server_get_header(char *request, char *header_name, int *len) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - - ptr = strstr(request, header_name); - if(ptr) { - ret = ptr + strlen(header_name); - ptr = ret; - while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') { - (*len)++; - ptr++; - } - return ret; - } - return NULL; -} -char* http_server_search_header(char *request, char *header_name, int *len, char ** parm_name, char ** next_position, char * bufEnd) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - int currentLength=0; - - ESP_LOGV(TAG, "searching for header name: [%s]", header_name); - ptr = strstr(request, header_name); - - - if(ptr!=NULL && ptr0) { - ESP_LOGD(TAG, "Found Header Line %s ", last); - //Content-Type: application/json - } - else { - ESP_LOGD(TAG, "Found end of headers"); - bHeaders = false; - } - last=ptr; - } - else { - //ESP_LOGD(TAG, "Body content: %s", last); - //cJSON * json = cJSON_Parse(last); - //cJSON_Delete(json); - //todo: implement body json parsing - // right now, body is coming as compressed, so we need some type of decompression to happen. - return; - } - } - return ; - -} - -void dump_net_buffer(void * buf, u16_t buflen) { - char * curbuf = malloc(buflen+1); - ESP_LOGV(TAG, "netconn buffer, length=%u",buflen); - if(curbuf==NULL) { - ESP_LOGE(TAG, "Unable to show netconn buffer. Malloc failed"); - } - memset(curbuf,0x0, buflen+1); - memcpy(curbuf,buf,buflen); - ESP_LOGV(TAG, "netconn buffer content:\n%s",curbuf); - free(curbuf); -} - -void http_server_netconn_serve(struct netconn *conn) { - - struct netbuf *inbuf; - char *buf = NULL; - u16_t buflen = 0; - err_t err; - ip_addr_t remote_add; - u16_t port; - ESP_LOGV(TAG, "Serving page. Getting device AP address."); - const char new_line[2] = "\n"; - char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); - if(ap_ip_address==NULL){ - ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - netconn_close(conn); - return; - } - ESP_LOGV(TAG, "Getting remote device IP address."); - netconn_getaddr(conn, &remote_add, &port, 0); - char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); - ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); - - u16_t bufsize = 0; - netconn_set_recvtimeout(conn, 50); - while (netconn_recv(conn, &inbuf) == ERR_OK) { - do { - u8_t *rcvbuf; - u16_t rcvlen; - netbuf_data(inbuf, (void**)&rcvbuf, &rcvlen); - dump_net_buffer(rcvbuf, rcvlen); - if (buflen + rcvlen > bufsize) { - bufsize += 2048; - buf = realloc(buf, bufsize); - } - memcpy(buf + buflen, rcvbuf, rcvlen); - buflen += rcvlen; - ESP_LOGI(TAG, "received netbuf of %hu", rcvlen); - } while (netbuf_next(inbuf) != -1); - netbuf_delete(inbuf); - } - - if(buflen) { - ESP_LOGV(TAG, "Getting data buffer."); - int lenH = 0; - /* extract the first line of the request */ - char *save_ptr = buf; - char *line = strtok_r(save_ptr, new_line, &save_ptr); - char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); - char * host = malloc(lenH+1); - memset(host,0x00,lenH+1); - if(lenH>0){ - strlcpy(host,temphost,lenH+1); - } - ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); - - if(line) { - - /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ - const char * host_name=NULL; - if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - } - else { - ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); - } - - /* determine if Host is from the STA IP address */ - wifi_manager_lock_sta_ip_string(portMAX_DELAY); - bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; - wifi_manager_unlock_sta_ip_string(); - bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); - - if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { - ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); - netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); - netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); - netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); - } - else { - //static stuff - /* default page */ - if(strstr(line, "GET / ")) { - netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, index_html_start, index_html_end- index_html_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /code.js ")) { - netconn_write(conn, http_js_hdr, sizeof(http_js_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, code_js_start, code_js_end - code_js_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /style.css ")) { - netconn_write(conn, http_css_hdr, sizeof(http_css_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, style_css_start, style_css_end - style_css_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /jquery.js ")) { - http_server_send_resource_file(conn,jquery_gz_start, jquery_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /popper.js ")) { - http_server_send_resource_file(conn,popper_gz_start, popper_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.js ")) { - http_server_send_resource_file(conn,bootstrap_js_gz_start, bootstrap_js_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.css ")) { - http_server_send_resource_file(conn,bootstrap_css_gz_start, bootstrap_css_gz_end, "text/css", "gzip" ); - } - - //dynamic stuff - else if(strstr(line, "GET /scan.json ")) { - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - } - else if(strstr(line, "GET /ap.json ")) { - /* if we can get the mutex, write the last version of the AP list */ - ESP_LOGI(TAG, "Processing ap.json request"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - char *buff = wifi_manager_alloc_get_ap_list_json(); - wifi_manager_unlock_json_buffer(); - if(buff!=NULL){ - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - ESP_LOGD(TAG, "Error retrieving ap list json string. "); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex"); - } - /* request a wifi scan */ - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - ESP_LOGI(TAG, "Done serving ap.json"); - } - else if(strstr(line, "GET /config.json ")) { - ESP_LOGI(TAG, "Serving config.json"); - ESP_LOGI(TAG, "About to get config from flash"); - http_server_send_config_json(conn); - ESP_LOGD(TAG, "Done serving config.json"); - } - else if(strstr(line, "POST /config.json ")) { - ESP_LOGI(TAG, "Serving POST config.json"); - int lenA=0; - char * last_parm=save_ptr; - char * next_parm=save_ptr; - char * last_parm_name=NULL; - bool bErrorFound=false; - bool bOTA=false; - char * otaURL=NULL; - // todo: implement json body parsing - //http_server_process_config(conn,save_ptr); - - while(last_parm!=NULL) { - // Search will return - ESP_LOGD(TAG, "Getting parameters from X-Custom headers"); - last_parm = http_server_search_header(next_parm, "X-Custom-", &lenA, &last_parm_name,&next_parm,buf+buflen); - if(last_parm!=NULL && last_parm_name!=NULL) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST config.json, config %s=%s", last_parm_name, last_parm); - if(strcmp(last_parm_name, "fwurl")==0) { - // we're getting a request to do an OTA from that URL - ESP_LOGW(TAG, "Found OTA request!"); - otaURL=strdup(last_parm); - bOTA=true; - } - else { - ESP_LOGV(TAG, "http_server_netconn_serve: POST config.json Storing parameter"); - if(config_set_value(NVS_TYPE_STR, last_parm_name , last_parm) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save nvs value."); - } - } - } - if(last_parm_name!=NULL) { - free(last_parm_name); - last_parm_name=NULL; - } - } - if(bErrorFound) { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); //400 invalid request - } - else { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - if(bOTA) { - -#if RECOVERY_APPLICATION - ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); -#else - ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); -#endif - wifi_manager_reboot_ota(otaURL); - free(otaURL); - } - } - ESP_LOGI(TAG, "Done Serving POST config.json"); - } - else if(strstr(line, "POST /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST /connect.json"); - bool found = false; - int lenS = 0, lenP = 0, lenN = 0; - char *ssid = NULL, *password = NULL; - ssid = http_server_get_header(save_ptr, "X-Custom-ssid: ", &lenS); - password = http_server_get_header(save_ptr, "X-Custom-pwd: ", &lenP); - char * new_host_name_b = http_server_get_header(save_ptr, "X-Custom-host_name: ", &lenN); - if(lenN > 0){ - lenN++; - char * new_host_name = malloc(lenN); - strlcpy(new_host_name, new_host_name_b, lenN); - if(config_set_value(NVS_TYPE_STR, "host_name", new_host_name) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save host name configuration"); - } - free(new_host_name); - } - - if(ssid && lenS <= MAX_SSID_SIZE && password && lenP <= MAX_PASSWORD_SIZE) { - wifi_config_t* config = wifi_manager_get_wifi_sta_config(); - memset(config, 0x00, sizeof(wifi_config_t)); - memcpy(config->sta.ssid, ssid, lenS); - memcpy(config->sta.password, password, lenP); - ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); - wifi_manager_connect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - found = true; - } - else{ - ESP_LOGE(TAG, "SSID or Password invalid"); - } - - - if(!found) { - /* bad request the authentification header is not complete/not the correct format */ - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request the authentification header is not complete/not the correct format"); - } - - ESP_LOGI(TAG, "http_server_netconn_serve: done serving connect.json"); - } - else if(strstr(line, "DELETE /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: DELETE /connect.json"); - /* request a disconnection from wifi and forget about it */ - wifi_manager_disconnect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - ESP_LOGI(TAG, "http_server_netconn_serve: done serving DELETE /connect.json"); - } - else if(strstr(line, "POST /reboot_ota.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot_ota.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(OTA); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot_ota.json"); - } - else if(strstr(line, "POST /reboot.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RESTART); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot.json"); - } - else if(strstr(line, "POST /recovery.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST recovery.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RECOVERY); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST recovery.json"); - } - else if(strstr(line, "GET /status.json ")) { - ESP_LOGI(TAG, "Serving status.json"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - char *buff = wifi_manager_alloc_get_ip_info_json(); - wifi_manager_unlock_json_buffer(); - if(buff) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /status failed to obtain mutex"); - } - ESP_LOGI(TAG, "Done Serving status.json"); - } - else { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request from host: %s, request %s",remote_address, line); - } - } - } - else { - ESP_LOGE(TAG, "URL not found processing for remote host : %s",remote_address); - netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY); - } - free(host); - free(buf); - } - - free(ap_ip_address); - free(remote_address); - netconn_close(conn); - /* free the buffer */ - -} - -bool http_server_lock_json_object(TickType_t xTicksToWait) { - ESP_LOGD(TAG, "Locking config json object"); - if(http_server_config_mutex) { - if( xSemaphoreTake( http_server_config_mutex, xTicksToWait ) == pdTRUE ) { - ESP_LOGV(TAG, "config Json object locked!"); - return true; - } - else { - ESP_LOGW(TAG, "Semaphore take failed. Unable to lock config Json object mutex"); - return false; - } - } - else { - ESP_LOGW(TAG, "Unable to lock config Json object mutex"); - return false; - } - -} - -void http_server_unlock_json_object() { - ESP_LOGD(TAG, "Unlocking json buffer!"); - xSemaphoreGive( http_server_config_mutex ); -} - -void strreplace(char *src, char *str, char *rep) -{ - char *p = strstr(src, str); - if(p) - { - int len = strlen(src)+strlen(rep)-strlen(str); - char r[len]; - memset(r, 0, len); - if( p >= src ) { - strncpy(r, src, p-src); - r[p-src]='\0'; - strncat(r, rep, strlen(rep)); - strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); - strcpy(src, r); - strreplace(p+strlen(rep), str, rep); - } - } -} - From 4963579e20eb0d271d2925d7b9c40c12d9aa0a56 Mon Sep 17 00:00:00 2001 From: sebastien Date: Thu, 6 Feb 2020 13:08:21 -0500 Subject: [PATCH 08/46] telnet refactor --- components/telnet/telnet.c | 144 ++++++++++++++++--------------------- components/telnet/telnet.h | 4 +- 2 files changed, 64 insertions(+), 84 deletions(-) diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index f1343702..5f455694 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -49,12 +49,8 @@ static size_t log_buf_size=2000; //32-bit aligned size static bool bIsEnabled=false; const static char tag[] = "telnet"; -int _log_vprintf(const char *fmt, va_list args); -void telnet_esp32_listenForClients(); -int telnet_esp32_vprintf(const char *fmt, va_list va); - static void telnetTask(void *data); - +static void doTelnet(int partnerSocket) ; static int uart_fd=0; @@ -68,21 +64,50 @@ struct telnetUserData { int sockfd; }; - - static void telnetTask(void *data) { ESP_LOGD(tag, ">> telnetTask"); - telnet_esp32_listenForClients(); + int serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + struct sockaddr_in serverAddr; + serverAddr.sin_family = AF_INET; + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); + serverAddr.sin_port = htons(23); + + int rc = bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); + if (rc < 0) { + ESP_LOGE(tag, "bind: %d (%s)", errno, strerror(errno)); + return; + } + + rc = listen(serverSocket, 5); + if (rc < 0) { + ESP_LOGE(tag, "listen: %d (%s)", errno, strerror(errno)); + return; + } + + while(1) { + socklen_t len = sizeof(serverAddr); + rc = accept(serverSocket, (struct sockaddr *)&serverAddr, &len); + if (rc < 0 ){ + ESP_LOGE(tag, "accept: %d (%s)", errno, strerror(errno)); + return; + } + else { + int partnerSocket = rc; + ESP_LOGD(tag, "We have a new client connection!"); + doTelnet(partnerSocket); + ESP_LOGD(tag, "Telnet connection terminated"); + } + } ESP_LOGD(tag, "<< telnetTask"); vTaskDelete(NULL); } void start_telnet(void * pvParameter){ static bool isStarted=false; - StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - StackType_t *xStack = malloc(TELNET_STACK_SIZE); - if(!isStarted && bIsEnabled) { + StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + StackType_t *xStack = malloc(TELNET_STACK_SIZE); xTaskCreateStatic( (TaskFunction_t) &telnetTask, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, xTaskBuffer); isStarted=true; } @@ -117,6 +142,25 @@ static ssize_t stdout_write(int fd, const void * data, size_t size) { } return write(uart_fd, data, size); } +static ssize_t uart_v_write(const char *fmt, va_list va) { + ssize_t required=vsnprintf(NULL,0,fmt,va); + if(required>0){ + char * buf=malloc(required); + vsprintf(buf,fmt,va); + required=write(uart_fd, buf,required); + free(buf); + } + return required; +} +static ssize_t uart_printf(const char *fmt, ...) { + ssize_t printed=0; + va_list args; + va_start(args, fmt); + uart_v_write(fmt,args); + va_end(args); + return printed; +} + static ssize_t stdout_read(int fd, void* data, size_t size) { return read(fd, data, size); @@ -136,7 +180,7 @@ static int stdout_fstat(int fd, struct stat * st) { } -void kchal_stdout_register() { +void stdout_register() { const esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, .write = &stdout_write, @@ -149,7 +193,7 @@ void kchal_stdout_register() { ESP_ERROR_CHECK(esp_vfs_register("/dev/pkspstdout", &vfs, NULL)); freopen("/dev/pkspstdout", "w", stdout); freopen("/dev/pkspstdout", "w", stderr); - //printf("8bkc_hal_stdout_register: Custom stdout/stderr handler installed.\n"); + } /********************************* * Telnet Support @@ -195,9 +239,8 @@ void init_telnet(){ return; } - ESP_LOGI(tag, "***Redirecting log output to telnet"); - //esp_log_set_vprintf(&_log_vprintf); - kchal_stdout_register(); + ESP_LOGI(tag, "***Redirecting stdout and stderr output to telnet"); + stdout_register(); } /** * Convert a telnet event type to its string representation. @@ -238,27 +281,6 @@ static char *eventToString(telnet_event_type_t type) { return "Unknown type"; } // eventToString - -/** - * Send data to the telnet partner. - */ -void telnet_esp32_sendData(uint8_t *buffer, size_t size) { - if (tnHandle != NULL) { - telnet_send(tnHandle, (char *)buffer, size); - } -} // telnet_esp32_sendData - - -/** - * Send a vprintf formatted output to the telnet partner. - */ -int telnet_esp32_vprintf(const char *fmt, va_list va) { - if (tnHandle == NULL) { - return 0; - } - return telnet_vprintf(tnHandle, fmt, va); -} // telnet_esp32_vprintf - /** * Telnet handler. */ @@ -299,7 +321,7 @@ static void telnetHandler( break; default: - printf("telnet event: %s\n", eventToString(event->type)); + printf("%s()=>telnet event: %s\n", __FUNCTION__, eventToString(event->type)); break; } // End of switch event type } // myTelnetHandler @@ -325,10 +347,8 @@ static void handleLogBuffer(int partnerSocket, UBaseType_t count){ if (item != NULL) { uxBytesToSend-=item_size; - if(partnerSocket!=0) - telnet_esp32_sendData((uint8_t *)item, item_size); - else{ - //printf("%s() flushing %u bytes from log buffer\n", __FUNCTION__, item_size); + if(partnerSocket!=0 && tnHandle != NULL){ + telnet_send(tnHandle, (char *)item, item_size); } //Return Item vRingbufferReturnItem(buf_handle, (void *)item); @@ -377,43 +397,3 @@ static void doTelnet(int partnerSocket) { } } // doTelnet - -/** - * Listen for telnet clients and handle them. - */ -void telnet_esp32_listenForClients() { - //ESP_LOGD(tag, ">> telnet_listenForClients"); - int serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - struct sockaddr_in serverAddr; - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); - serverAddr.sin_port = htons(23); - - int rc = bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); - if (rc < 0) { - ESP_LOGE(tag, "bind: %d (%s)", errno, strerror(errno)); - return; - } - - rc = listen(serverSocket, 5); - if (rc < 0) { - ESP_LOGE(tag, "listen: %d (%s)", errno, strerror(errno)); - return; - } - - while(1) { - socklen_t len = sizeof(serverAddr); - rc = accept(serverSocket, (struct sockaddr *)&serverAddr, &len); - if (rc < 0 ){ - ESP_LOGE(tag, "accept: %d (%s)", errno, strerror(errno)); - return; - } - else { - int partnerSocket = rc; - ESP_LOGD(tag, "We have a new client connection!"); - doTelnet(partnerSocket); - ESP_LOGD(tag, "Telnet connection terminated"); - } - } -} // listenForNewClient diff --git a/components/telnet/telnet.h b/components/telnet/telnet.h index db619f08..bdf20bb3 100644 --- a/components/telnet/telnet.h +++ b/components/telnet/telnet.h @@ -1,4 +1,4 @@ - +static ssize_t uart_printf(const char *fmt, ...); void init_telnet(); void start_telnet(void * pvParameter); -void telnet_esp32_sendData(uint8_t *buffer, size_t size); + From 730b6d38a5bab5aa516bf54275e4e7ba8ae3f1d8 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Mon, 10 Feb 2020 19:17:16 -0500 Subject: [PATCH 09/46] HTTPd WIP --- Makefile | 2 +- components/telnet/telnet.c | 1 + components/wifi-manager/http_server_handlers.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index e3948648..f209bfed 100644 --- a/Makefile +++ b/Makefile @@ -15,5 +15,5 @@ PROJECT_NAME?=squeezelite include $(IDF_PATH)/make/project.mk -CFLAGS += -Wno-error=format-overflow -Wno-error=stringop-truncation +# for future gcc version, this could be needed: CPPFLAGS+= -Wno-error=format-overflow -Wno-error=stringop-truncation CPPFLAGS+= -Wno-error=maybe-uninitialized diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index 5f455694..b90d594b 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -362,6 +362,7 @@ static void handleLogBuffer(int partnerSocket, UBaseType_t count){ static void doTelnet(int partnerSocket) { //ESP_LOGD(tag, ">> doTelnet"); static const telnet_telopt_t my_telopts[] = { + { TELNET_TELOPT_ECHO, TELNET_WILL, TELNET_DONT }, { TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT }, { TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DO }, diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 67c24773..a0ae6bb3 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -54,7 +54,7 @@ function to process requests, decode URLs, serve files, etc. etc. const char str_na[]="N/A"; #define STR_OR_NA(s) s?s:str_na /* @brief tag used for ESP serial console messages */ -static const char TAG[] = "http_server"; +static const char TAG[] = "httpd_handlers"; /* @brief task handle for the http server */ SemaphoreHandle_t http_server_config_mutex = NULL; @@ -558,7 +558,7 @@ esp_err_t config_post_handler(httpd_req_t *req){ char * root_str = cJSON_Print(root); if(root_str!=NULL){ - ESP_LOGE(TAG, "Processing config item: \n%s", root_str); + ESP_LOGD(TAG, "Processing config item: \n%s", root_str); free(root_str); } From b80faf911af59ba56701b2fd13459bc09daf71ef Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 13 Feb 2020 16:22:51 -0500 Subject: [PATCH 10/46] fine tuning of httpd implementation --- components/cmd_i2c/cmd_i2ctools.c | 2 +- components/cmd_i2c/component.mk | 2 +- components/cmd_nvs/cmd_nvs.c | 2 +- components/cmd_system/cmd_system.c | 2 +- components/config/config.c | 1 - components/config/nvs_utilities.c | 1 - components/services/audio_controls.c | 1 - components/squeezelite-ota/component.mk | 2 +- components/squeezelite-ota/squeezelite-ota.c | 3 --- components/wifi-manager/component.mk | 3 +-- components/wifi-manager/http_server_handlers.c | 10 +++++----- components/wifi-manager/http_server_handlers.h | 1 - main/component.mk | 1 - main/esp_app_main.c | 2 +- 14 files changed, 12 insertions(+), 21 deletions(-) diff --git a/components/cmd_i2c/cmd_i2ctools.c b/components/cmd_i2c/cmd_i2ctools.c index 5ec0a53d..1ef62307 100644 --- a/components/cmd_i2c/cmd_i2ctools.c +++ b/components/cmd_i2c/cmd_i2ctools.c @@ -6,7 +6,7 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ -#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + #include #include "cmd_i2ctools.h" #include "argtable3/argtable3.h" diff --git a/components/cmd_i2c/component.mk b/components/cmd_i2c/component.mk index 2215a6d8..0b379962 100644 --- a/components/cmd_i2c/component.mk +++ b/components/cmd_i2c/component.mk @@ -1,7 +1,7 @@ # # Main Makefile. This is basically the same as a component makefile. # -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG \ +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO \ -I$(COMPONENT_PATH)/../tools COMPONENT_ADD_INCLUDEDIRS := . COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools diff --git a/components/cmd_nvs/cmd_nvs.c b/components/cmd_nvs/cmd_nvs.c index 9d2f1470..57f03187 100644 --- a/components/cmd_nvs/cmd_nvs.c +++ b/components/cmd_nvs/cmd_nvs.c @@ -6,7 +6,7 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ -//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE + #ifdef __cplusplus extern "C" { #endif diff --git a/components/cmd_system/cmd_system.c b/components/cmd_system/cmd_system.c index 4b8b7b82..02f6e0ad 100644 --- a/components/cmd_system/cmd_system.c +++ b/components/cmd_system/cmd_system.c @@ -6,7 +6,7 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ -#define LOG_LOCAL_LEVEL ESP_LOG_INFO + #include #include #include diff --git a/components/config/config.c b/components/config/config.c index c167a186..def9c9d2 100644 --- a/components/config/config.c +++ b/components/config/config.c @@ -18,7 +18,6 @@ * along with this program. If not, see . * */ -//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE #include "config.h" #include "nvs_utilities.h" diff --git a/components/config/nvs_utilities.c b/components/config/nvs_utilities.c index 8627ed75..040743cf 100644 --- a/components/config/nvs_utilities.c +++ b/components/config/nvs_utilities.c @@ -1,4 +1,3 @@ -//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE #include "nvs_utilities.h" #include diff --git a/components/services/audio_controls.c b/components/services/audio_controls.c index 8bcd9887..995c2043 100644 --- a/components/services/audio_controls.c +++ b/components/services/audio_controls.c @@ -18,7 +18,6 @@ * along with this program. If not, see . * */ -//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include #include #include diff --git a/components/squeezelite-ota/component.mk b/components/squeezelite-ota/component.mk index 35902feb..7f4b4f39 100644 --- a/components/squeezelite-ota/component.mk +++ b/components/squeezelite-ota/component.mk @@ -9,5 +9,5 @@ COMPONENT_ADD_INCLUDEDIRS += include COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/components/tools CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO -DCONFIG_OTA_ALLOW_HTTP=1 -#CFLAGS += -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCONFIG_OTA_ALLOW_HTTP=1 + diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index ef840ab5..b9d76a7e 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -6,9 +6,6 @@ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ -#ifndef LOG_LOCAL_LEVEL -#define LOG_LOCAL_LEVEL ESP_LOG_INFO -#endif #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" diff --git a/components/wifi-manager/component.mk b/components/wifi-manager/component.mk index 58cbe8da..9b6972bb 100644 --- a/components/wifi-manager/component.mk +++ b/components/wifi-manager/component.mk @@ -8,8 +8,7 @@ # COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz -#CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG \ +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO \ -I$(COMPONENT_PATH)/../tools COMPONENT_ADD_INCLUDEDIRS := . COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index a0ae6bb3..56b27aa0 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -254,7 +254,7 @@ session_context_t* get_session_context(httpd_req_t *req){ } session_context_t *ctx_data = (session_context_t*)req->sess_ctx; ctx_data->sess_ip_address = http_alloc_get_socket_address(req, 0, &ctx_data->port); - ESP_LOGI_LOC(TAG, "serving %s to peer %s port %u", req->uri, ctx_data->sess_ip_address , ctx_data->port); + ESP_LOGD_LOC(TAG, "serving %s to peer %s port %u", req->uri, ctx_data->sess_ip_address , ctx_data->port); return (session_context_t *)req->sess_ctx; } @@ -382,7 +382,7 @@ esp_err_t root_get_handler(httpd_req_t *req){ esp_err_t resource_filehandler(httpd_req_t *req){ char filepath[FILE_PATH_MAX]; - ESP_LOGI_LOC(TAG, "serving [%s]", req->uri); + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); const char *filename = get_path_from_uri(filepath, req->uri, sizeof(filepath)); @@ -437,7 +437,7 @@ esp_err_t resource_filehandler(httpd_req_t *req){ httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist"); return ESP_FAIL; } - ESP_LOGI_LOC(TAG, "Resource sending complete"); + ESP_LOGD_LOC(TAG, "Resource sending complete"); return ESP_OK; } @@ -589,7 +589,7 @@ esp_err_t config_post_handler(httpd_req_t *req){ err = ESP_FAIL; } if(err == ESP_OK){ - ESP_LOGI_LOC(TAG,"Found config value name [%s]", prev_item->string); + ESP_LOGD_LOC(TAG,"Found config value name [%s]", prev_item->string); nvs_type_t item_type= config_get_item_type(prev_item); if(item_type!=0){ void * val = config_safe_alloc_get_entry_value(item_type, prev_item); @@ -614,7 +614,7 @@ esp_err_t config_post_handler(httpd_req_t *req){ err = ESP_FAIL; } else { - ESP_LOGI_LOC(TAG,"Successfully set value for [%s]",prev_item->string); + ESP_LOGD_LOC(TAG,"Successfully set value for [%s]",prev_item->string); } } free(val); diff --git a/components/wifi-manager/http_server_handlers.h b/components/wifi-manager/http_server_handlers.h index 93cdcac2..82a10560 100644 --- a/components/wifi-manager/http_server_handlers.h +++ b/components/wifi-manager/http_server_handlers.h @@ -60,7 +60,6 @@ function to process requests, decode URLs, serve files, etc. etc. #include "lwip/priv/tcp_priv.h" #include "lwip/priv/tcpip_priv.h" #include "esp_vfs.h" -#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #ifdef __cplusplus diff --git a/main/component.mk b/main/component.mk index 4226d6c1..dc5314b1 100644 --- a/main/component.mk +++ b/main/component.mk @@ -6,7 +6,6 @@ # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, # please read the SDK documents if you need to do this. # -#CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO -DMODEL_NAME=SqueezeESP32 COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools \ $(COMPONENT_PATH)/../config diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 12fa0284..e8921048 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -18,7 +18,7 @@ * along with this program. If not, see . * */ -#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + #include "platform_esp32.h" #include "led.h" #include From 69120bb4de7cb15feda12e1d85fae36eaa4aa0c6 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 13 Feb 2020 16:39:14 -0500 Subject: [PATCH 11/46] increase http header max length to 1024 bytes CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 from CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 --- build-scripts/ESP32-A1S-sdkconfig.defaults | 2 +- build-scripts/I2S-4MFlash-sdkconfig.defaults | 2 +- build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults | 2 +- build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults | 2 +- build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults | 2 +- build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults | 2 +- sdkconfig.defaults | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build-scripts/ESP32-A1S-sdkconfig.defaults b/build-scripts/ESP32-A1S-sdkconfig.defaults index 4c23a8fe..b75b271f 100644 --- a/build-scripts/ESP32-A1S-sdkconfig.defaults +++ b/build-scripts/ESP32-A1S-sdkconfig.defaults @@ -507,7 +507,7 @@ CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 41a0b935..371b2e2b 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -506,7 +506,7 @@ CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 diff --git a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults b/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults index a783b563..73bc9c95 100644 --- a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults @@ -507,7 +507,7 @@ CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 diff --git a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults index 4fa041ad..f033b338 100644 --- a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults +++ b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults @@ -507,7 +507,7 @@ CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 diff --git a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults index 6038d934..5bef5a79 100644 --- a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults @@ -507,7 +507,7 @@ CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 diff --git a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults index f0a45d9a..1215be8b 100644 --- a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults @@ -501,7 +501,7 @@ CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index a556b39c..b1611792 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -469,7 +469,7 @@ CONFIG_ESP_EVENT_POST_FROM_ISR=y CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_URI_LEN=512 CONFIG_HTTPD_ERR_RESP_NO_DELAY=y CONFIG_HTTPD_PURGE_BUF_LEN=32 From 8c3a52d40c0bc4143e175f4ad6172834c630b3a8 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 14 Feb 2020 13:33:50 -0500 Subject: [PATCH 12/46] added ability to upload new firmware from the browser. --- .cproject | 8 +- .settings/language.settings.xml | 8 +- .settings/org.eclipse.cdt.codan.core.prefs | 89 +++++++ .settings/org.eclipse.cdt.core.prefs | 12 + components/config/config.h | 4 +- components/squeezelite-ota/cmd_ota.c | 5 +- components/squeezelite-ota/squeezelite-ota.c | 243 +++++++++++------- components/squeezelite-ota/squeezelite-ota.h | 3 +- components/wifi-manager/code.js | 31 ++- .../wifi-manager/http_server_handlers.c | 125 ++++++++- .../wifi-manager/http_server_handlers.h | 3 + components/wifi-manager/index.html | 17 +- components/wifi-manager/wifi_manager.c | 3 +- components/wifi-manager/wifi_manager.h | 1 - .../wifi-manager/wifi_manager_http_server.c | 229 +---------------- main/esp_app_main.c | 2 +- 16 files changed, 432 insertions(+), 351 deletions(-) create mode 100644 .settings/org.eclipse.cdt.codan.core.prefs diff --git a/.cproject b/.cproject index f2ba4b3b..e4d56c6d 100644 --- a/.cproject +++ b/.cproject @@ -199,12 +199,6 @@ - - - - - - @@ -239,7 +233,7 @@ - + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index f2d1fea7..cbee2f3c 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -77,7 +77,7 @@ - + diff --git a/.settings/org.eclipse.cdt.codan.core.prefs b/.settings/org.eclipse.cdt.codan.core.prefs new file mode 100644 index 00000000..9a577d2b --- /dev/null +++ b/.settings/org.eclipse.cdt.codan.core.prefs @@ -0,0 +1,89 @@ +eclipse.preferences.version=1 +org.eclipse.cdt.codan.checkers.errnoreturn=Warning +org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return\\")",implicit\=>false} +org.eclipse.cdt.codan.checkers.errreturnvalue=Error +org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused return value\\")"} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Nesting comments\\")"} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Line comments\\")"} +org.eclipse.cdt.codan.checkers.noreturn=Error +org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return value\\")",implicit\=>false} +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Abstract class cannot be instantiated\\")"} +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Ambiguous problem\\")"} +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment in condition\\")"} +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment to itself\\")"} +org.eclipse.cdt.codan.internal.checkers.CStyleCastProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.CStyleCastProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"C-Style cast instead of C++ cast\\")"} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No break at end of case\\")",no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false,enable_fallthrough_quickfix_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning +org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Catching by reference is recommended\\")",unknown\=>false,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Circular inheritance\\")"} +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class members should be properly initialized\\")",skip\=>true} +org.eclipse.cdt.codan.internal.checkers.CopyrightProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.CopyrightProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Lack of copyright information\\")",regex\=>".*Copyright.*"} +org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem=Error +org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid 'decltype(auto)' specifier\\")"} +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Field cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Function cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.GotoStatementProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.GotoStatementProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Goto statement used\\")"} +org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error +org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid arguments\\")"} +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid template argument\\")"} +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Label statement not found\\")"} +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Member declaration not found\\")"} +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Method cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.MissCaseProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.MissCaseProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing cases in switch\\")"} +org.eclipse.cdt.codan.internal.checkers.MissDefaultProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.MissDefaultProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing default in switch\\")",defaultWithAllEnums\=>false} +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Name convention for function\\")",pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class has a virtual method and non-virtual destructor\\")"} +org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error +org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid overload\\")"} +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redeclaration\\")"} +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redefinition\\")"} +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Return with parenthesis\\")"} +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Format String Vulnerability\\")"} +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Statement has no effect\\")",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suggested parenthesis around expression\\")",paramNot\=>false} +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suspicious semicolon\\")",else\=>false,afterelse\=>false} +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Type cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused function declaration\\")",macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused static function\\")",macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused variable declaration in file scope\\")",macro\=>true,exceptions\=>("@(\#)","$Id")} +org.eclipse.cdt.codan.internal.checkers.UsingInHeaderProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.UsingInHeaderProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Using directive in header\\")"} +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Symbol is not resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.VirtualMethodCallProblem=-Error +org.eclipse.cdt.codan.internal.checkers.VirtualMethodCallProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Virtual method call in constructor/destructor\\")"} +org.eclipse.cdt.qt.core.qtproblem=Warning +org.eclipse.cdt.qt.core.qtproblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_ON_FILE_OPEN\=>true,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>null} diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs index 2dd6626d..d5d56fd7 100644 --- a/.settings/org.eclipse.cdt.core.prefs +++ b/.settings/org.eclipse.cdt.core.prefs @@ -27,6 +27,9 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1476804786/appendC environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/BATCH_BUILD/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/BATCH_BUILD/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/BATCH_BUILD/value=1 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/EXTRA_CPPFLAGS/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/EXTRA_CPPFLAGS/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=0 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/IDF_PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/IDF_PATH/operation=replace environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/IDF_PATH/value=C\:/msys32/opt/esp-idf @@ -44,6 +47,9 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.16039962 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/BATCH_BUILD/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/BATCH_BUILD/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/BATCH_BUILD/value=1 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=1 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/operation=replace environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/value=C\:/msys32/opt/esp-idf @@ -61,6 +67,9 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.16039962 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/BATCH_BUILD/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/BATCH_BUILD/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/BATCH_BUILD/value=1 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/EXTRA_CPPFLAGS/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/EXTRA_CPPFLAGS/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=1 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/IDF_PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/IDF_PATH/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.839256934/IDF_PATH/value=/var/opt/esp-idf/ @@ -78,6 +87,9 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.83925693 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/BATCH_BUILD/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/BATCH_BUILD/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/BATCH_BUILD/value=1 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/EXTRA_CPPFLAGS/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/EXTRA_CPPFLAGS/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=0 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/IDF_PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/IDF_PATH/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/IDF_PATH/value=/var/opt/esp-idf/ diff --git a/components/config/config.h b/components/config/config.h index 4fa9014a..b6c192ce 100644 --- a/components/config/config.h +++ b/components/config/config.h @@ -12,7 +12,9 @@ extern "C" { #endif #define DECLARE_SET_DEFAULT(t) void config_set_default_## t (const char *key, t value); #define DECLARE_GET_NUM(t) esp_err_t config_get_## t (const char *key, t * value); - +#ifndef FREE_RESET +#define FREE_RESET(p) if(p!=NULL) { free(p); p=NULL; } +#endif DECLARE_SET_DEFAULT(uint8_t); DECLARE_SET_DEFAULT(uint16_t); diff --git a/components/squeezelite-ota/cmd_ota.c b/components/squeezelite-ota/cmd_ota.c index 4bf283db..91133e72 100644 --- a/components/squeezelite-ota/cmd_ota.c +++ b/components/squeezelite-ota/cmd_ota.c @@ -17,6 +17,7 @@ #include "esp_system.h" #include "esp_sleep.h" #include "esp_spi_flash.h" +#include "squeezelite-ota.h" #include "driver/rtc_io.h" #include "driver/uart.h" #include "argtable3/argtable3.h" @@ -27,7 +28,7 @@ #include "sdkconfig.h" static const char * TAG = "ota"; -extern esp_err_t start_ota(const char * bin_url); + static struct { struct arg_str *url; struct arg_end *end; @@ -45,7 +46,7 @@ static int perform_ota_update(int argc, char **argv) esp_err_t err=ESP_OK; ESP_LOGI(TAG, "Starting ota: %s", url); - start_ota(url); + start_ota(url, NULL, 0); if (err != ESP_OK) { ESP_LOGE(TAG, "%s", esp_err_to_name(err)); diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index b9d76a7e..7488d355 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -32,20 +32,38 @@ #include "esp_ota_ops.h" extern const char * get_certificate(); +#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 +#define OTA_CORE 0 +#else +#define OTA_CORE 1 +#endif + static const char *TAG = "squeezelite-ota"; char * ota_write_data = NULL; esp_http_client_handle_t ota_http_client = NULL; #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1 #define BUFFSIZE 4096 #define HASH_LEN 32 /* SHA-256 digest length */ - - +typedef struct { + char * url; + char * bin; + uint32_t length; +} ota_thread_parms_t ; +static ota_thread_parms_t ota_thread_parms; +typedef enum { + OTA_TYPE_HTTP, + OTA_TYPE_BUFFER, + OTA_TYPE_INVALID +} ota_type_t; static struct { char status_text[81]; - uint32_t ota_actual_len; - uint32_t ota_total_len; + uint32_t actual_image_len; + uint32_t total_image_len; + uint32_t remain_image_len; char * redirected_url; char * current_url; + ota_type_t ota_type; + char * bin; bool bOTAStarted; bool bInitialized; uint8_t lastpct; @@ -92,8 +110,8 @@ const char * ota_get_status(){ return ota_status.status_text; } uint8_t ota_get_pct_complete(){ - return ota_status.ota_total_len==0?0: - (uint8_t)((float)ota_status.ota_actual_len/(float)ota_status.ota_total_len*100.0f); + return ota_status.total_image_len==0?0: + (uint8_t)((float)ota_status.actual_image_len/(float)ota_status.total_image_len*100.0f); } static void __attribute__((noreturn)) task_fatal_error(void) @@ -105,7 +123,7 @@ static void __attribute__((noreturn)) task_fatal_error(void) ; } } -#define FREE_RESET(p) if(p!=NULL) { free(p); p=NULL; } + esp_err_t _http_event_handler(esp_http_client_event_t *evt) { // -------------- @@ -134,9 +152,10 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); if(ota_status.bOTAStarted) triggerStatusJsonRefresh(true,"Installing..."); - ota_status.ota_total_len=0; - ota_status.ota_actual_len=0; + ota_status.total_image_len=0; + ota_status.actual_image_len=0; ota_status.lastpct=0; + ota_status.remain_image_len=0; ota_status.newpct=0; gettimeofday(&ota_status.OTA_start, NULL); @@ -152,8 +171,8 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) ESP_LOGW(TAG,"OTA will redirect to url: %s",ota_status.redirected_url); } if (strcasecmp(evt->header_key, "content-length") == 0) { - ota_status.ota_total_len = atol(evt->header_value); - ESP_LOGW(TAG, "Content length found: %s, parsed to %d", evt->header_value, ota_status.ota_total_len); + ota_status.total_image_len = atol(evt->header_value); + ESP_LOGW(TAG, "Content length found: %s, parsed to %d", evt->header_value, ota_status.total_image_len); } break; case HTTP_EVENT_ON_DATA: @@ -171,29 +190,51 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) return ESP_OK; } -esp_err_t init_config(char * url){ +esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ memset(&ota_config, 0x00, sizeof(ota_config)); ota_status.bInitialized = true; triggerStatusJsonRefresh(true,"Initializing..."); - if(url==NULL || strlen(url)==0){ - ESP_LOGE(TAG,"HTTP OTA called without a url"); + ota_status.ota_type= OTA_TYPE_INVALID; + if(p_ota_thread_parms->url !=NULL && strlen(p_ota_thread_parms->url)>0 ){ + ota_status.ota_type= OTA_TYPE_HTTP; + } + else if(p_ota_thread_parms->bin!=NULL && p_ota_thread_parms->length > 0) { + ota_status.ota_type= OTA_TYPE_BUFFER; + } + + if( ota_status.ota_type== OTA_TYPE_INVALID ){ + ESP_LOGE(TAG,"HTTP OTA called without a url or a binary buffer"); + return ESP_ERR_INVALID_ARG; + } + + switch (ota_status.ota_type) { + case OTA_TYPE_HTTP: + ota_status.current_url= p_ota_thread_parms->url; + ota_config.cert_pem =get_certificate(); + ota_config.event_handler = _http_event_handler; + ota_config.buffer_size = BUFFSIZE; + ota_config.disable_auto_redirect=false; + ota_config.skip_cert_common_name_check = false; + ota_config.url = strdup(ota_status.current_url); + ota_config.max_redirection_count = 3; + ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + //ota_write_data = malloc(ota_config.buffer_size+1); + if(ota_write_data== NULL){ + ESP_LOGE(TAG,"Error allocating the ota buffer"); + return ESP_ERR_NO_MEM; + } + + break; + case OTA_TYPE_BUFFER: + ota_status.bin = p_ota_thread_parms->bin; + ota_status.total_image_len = p_ota_thread_parms->length; + + break; + default: return ESP_FAIL; + break; } - ota_status.current_url= url; - ota_config.cert_pem =get_certificate(); - ota_config.event_handler = _http_event_handler; - ota_config.buffer_size = BUFFSIZE; - //ota_config.disable_auto_redirect=true; - ota_config.disable_auto_redirect=false; - ota_config.skip_cert_common_name_check = false; - ota_config.url = strdup(url); - ota_config.max_redirection_count = 3; - ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - //ota_write_data = malloc(ota_config.buffer_size+1); - if(ota_write_data== NULL){ - ESP_LOGE(TAG,"Error allocating the ota buffer"); - return ESP_ERR_NO_MEM; - } + return ESP_OK; } esp_partition_t * _get_ota_partition(esp_partition_subtype_t subtype){ @@ -252,7 +293,6 @@ esp_err_t _erase_last_boot_app_partition(esp_partition_t *ota_partition) ESP_LOGD(TAG,"Pass %d of %d, with chunks of %d bytes, from %d to %d", i+1, num_passes,single_pass_size,i*single_pass_size,i*single_pass_size+single_pass_size); err=esp_partition_erase_range(ota_partition, i*single_pass_size, single_pass_size); if(err!=ESP_OK) return err; -// triggerStatusJsonRefresh(i%10==0?true:false,"Erasing flash (%u/%u)",i,num_passes); if(i%2) { triggerStatusJsonRefresh(false,"Erasing flash (%u/%u)",i,num_passes); } @@ -352,15 +392,16 @@ static esp_err_t _http_connect(esp_http_client_handle_t http_client) void ota_task_cleanup(const char * message, ...){ ota_status.bOTAThreadStarted=false; if(message!=NULL){ - va_list args; va_start(args, message); triggerStatusJsonRefresh(true,message, args); va_end(args); ESP_LOGE(TAG, "%s",ota_status.status_text); } + FREE_RESET(ota_status.redirected_url); FREE_RESET(ota_status.current_url); + FREE_RESET(ota_status.bin); FREE_RESET(ota_write_data); if(ota_http_client!=NULL) { esp_http_client_cleanup(ota_http_client); @@ -404,6 +445,12 @@ void ota_task(void *pvParameter) ota_task_cleanup("Error: OTA application partition not found. (%s)",esp_err_to_name(err)); return; } + if(ota_status.ota_type == OTA_TYPE_BUFFER){ + if(ota_status.total_image_len > ota_partition->size){ + ota_task_cleanup("Error: Image size too large to fit in partition."); + return; + } + } _printMemStats(); err=_erase_last_boot_app_partition(ota_partition); if(err!=ESP_OK){ @@ -414,28 +461,44 @@ void ota_task(void *pvParameter) _printMemStats(); ota_status.bOTAStarted = true; triggerStatusJsonRefresh(true,"Starting OTA..."); - ota_http_client = esp_http_client_init(&ota_config); - if (ota_http_client == NULL) { - ota_task_cleanup("Error: Failed to initialize HTTP connection."); - return; - } - _printMemStats(); - // Open the http connection and follow any redirection - err = _http_connect(ota_http_client); - if (err != ESP_OK) { - ota_task_cleanup("Error: HTTP Start read failed. (%s)",esp_err_to_name(err)); - return; - } - - _printMemStats(); + if (ota_status.ota_type == OTA_TYPE_HTTP){ + ota_http_client = esp_http_client_init(&ota_config); + if (ota_http_client == NULL) { + ota_task_cleanup("Error: Failed to initialize HTTP connection."); + return; + } + _printMemStats(); + // Open the http connection and follow any redirection + err = _http_connect(ota_http_client); + if (err != ESP_OK) { + ota_task_cleanup("Error: HTTP Start read failed. (%s)",esp_err_to_name(err)); + return; + } + } + else { + ota_write_data = ota_status.bin; + gettimeofday(&ota_status.OTA_start, NULL); + } + _printMemStats(); esp_ota_handle_t update_handle = 0 ; - int binary_file_length = 0; - /*deal with all receive packet*/ bool image_header_was_checked = false; + int data_read = 0; + while (1) { - int data_read = esp_http_client_read(ota_http_client, ota_write_data, buffer_size); + ota_status.remain_image_len =ota_status.total_image_len -ota_status.actual_image_len; + + if (ota_status.ota_type == OTA_TYPE_HTTP){ + data_read = esp_http_client_read(ota_http_client, ota_write_data, buffer_size); + } + else { + if(ota_status.remain_image_len >buffer_size){ + data_read = buffer_size; + } else { + data_read = ota_status.remain_image_len; + } + } if (data_read < 0) { ota_task_cleanup("Error: Data read error"); return; @@ -458,22 +521,11 @@ void ota_task(void *pvParameter) ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version); } - // check current version with last invalid partition -// if (last_invalid_app != NULL) { -// if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) { -// ESP_LOGW(TAG, "New version is the same as invalid version."); -// ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version); -// ESP_LOGW(TAG, "The firmware has been rolled back to the previous version."); -// ota_task_cleanup("esp_ota_begin failed (%s)", esp_err_to_name(err)); -// } -// } - if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) { ESP_LOGW(TAG, "Current running version is the same as a new."); } image_header_was_checked = true; - // Call OTA Begin with a small partition size - this drives the erase operation which was already done; err = esp_ota_begin(ota_partition, 512, &update_handle); if (err != ESP_OK) { @@ -491,27 +543,30 @@ void ota_task(void *pvParameter) ota_task_cleanup("Error: OTA Partition write failure. (%s)",esp_err_to_name(err)); return; } - binary_file_length += data_read; - ESP_LOGD(TAG, "Written image length %d", binary_file_length); - ota_status.ota_actual_len=binary_file_length; + ota_status.actual_image_len += data_read; + if(ota_status.ota_type == OTA_TYPE_BUFFER){ + // position the ota buffer in the next buffer chunk + ota_write_data+= data_read; + } + ESP_LOGD(TAG, "Written image length %d", ota_status.actual_image_len); if(ota_get_pct_complete()%5 == 0) ota_status.newpct = ota_get_pct_complete(); if(ota_status.lastpct!=ota_status.newpct ) { gettimeofday(&tv, NULL); uint32_t elapsed_ms= (tv.tv_sec-ota_status.OTA_start.tv_sec )*1000+(tv.tv_usec-ota_status.OTA_start.tv_usec)/1000; - ESP_LOGI(TAG,"OTA progress : %d/%d (%d pct), %d KB/s", ota_status.ota_actual_len, ota_status.ota_total_len, ota_status.newpct, elapsed_ms>0?ota_status.ota_actual_len*1000/elapsed_ms/1024:0); - triggerStatusJsonRefresh(true,"Downloading & writing update."); + ESP_LOGI(TAG,"OTA progress : %d/%d (%d pct), %d KB/s", ota_status.actual_image_len, ota_status.total_image_len, ota_status.newpct, elapsed_ms>0?ota_status.actual_image_len*1000/elapsed_ms/1024:0); + triggerStatusJsonRefresh(true,ota_status.ota_type == OTA_TYPE_HTTP?"Downloading & writing update.":"Writing binary file."); ota_status.lastpct=ota_status.newpct; } taskYIELD(); } else if (data_read == 0) { - ESP_LOGI(TAG, "Connection closed"); + ESP_LOGI(TAG, "End of OTA data stream"); break; } } - ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length); - if (ota_status.ota_total_len != binary_file_length) { + ESP_LOGI(TAG, "Total Write binary data length: %d", ota_status.actual_image_len); + if (ota_status.total_image_len != ota_status.actual_image_len) { ota_task_cleanup("Error: Error in receiving complete file"); return; } @@ -537,7 +592,7 @@ void ota_task(void *pvParameter) return; } -esp_err_t process_recovery_ota(const char * bin_url){ +esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length){ int ret = 0; uint16_t stack_size, task_priority; if(ota_status.bOTAThreadStarted){ @@ -546,18 +601,17 @@ esp_err_t process_recovery_ota(const char * bin_url){ } memset(&ota_status, 0x00, sizeof(ota_status)); ota_status.bOTAThreadStarted=true; - char * urlPtr=strdup(bin_url); - // the first thing we need to do here is to erase the firmware url - // to avoid a boot loop -#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 -#define OTA_CORE 0 -#warning "OTA will run on core 0" -#else -#pragma message "OTA will run on core 1" -#define OTA_CORE 1 -#endif - ESP_LOGI(TAG, "Starting ota on core %u for : %s", OTA_CORE,urlPtr); + if(bin_url){ + ota_thread_parms.url =strdup(bin_url); + ESP_LOGI(TAG, "Starting ota on core %u for : %s", OTA_CORE,bin_url); + } + else { + ota_thread_parms.bin = bin_buffer; + ota_thread_parms.length = length; + ESP_LOGI(TAG, "Starting ota on core %u for file upload", OTA_CORE); + } + char * num_buffer=config_alloc_get(NVS_TYPE_STR, "ota_stack"); if(num_buffer!=NULL) { stack_size= atol(num_buffer); @@ -578,9 +632,9 @@ esp_err_t process_recovery_ota(const char * bin_url){ ESP_LOGW(TAG,"OTA task priority not found"); task_priority= OTA_TASK_PRIOTITY; } + ESP_LOGD(TAG,"OTA task stack size %d, priority %d (%d %s ESP_TASK_MAIN_PRIO)",stack_size , task_priority, abs(task_priority-ESP_TASK_MAIN_PRIO), task_priority-ESP_TASK_MAIN_PRIO>0?"above":"below"); - ret=xTaskCreatePinnedToCore(&ota_task, "ota_task", stack_size , (void *)urlPtr, task_priority, NULL, OTA_CORE); - //ret=xTaskCreate(&ota_task, "ota_task", 1024*20, (void *)urlPtr, ESP_TASK_MAIN_PRIO+2, NULL); + ret=xTaskCreatePinnedToCore(&ota_task, "ota_task", stack_size , (void *)&ota_thread_parms, task_priority, NULL, OTA_CORE); if (ret != pdPASS) { ESP_LOGI(TAG, "create thread %s failed", "ota_task"); return ESP_FAIL; @@ -588,23 +642,26 @@ esp_err_t process_recovery_ota(const char * bin_url){ return ESP_OK; } -esp_err_t start_ota(const char * bin_url) +esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length) { -// uint8_t * config_alloc_get_default(NVS_TYPE_BLOB, "certs", server_cert_pem_start , server_cert_pem_end-server_cert_pem_start); #if RECOVERY_APPLICATION - return process_recovery_ota(bin_url); + return process_recovery_ota(bin_url,bin_buffer,length); #else - ESP_LOGW(TAG, "Called to update the firmware from url: %s",bin_url); - if(config_set_value(NVS_TYPE_STR, "fwurl", bin_url) != ESP_OK){ - ESP_LOGE(TAG,"Failed to save the OTA url into nvs cache"); - return ESP_FAIL; - } + if(!bin_url){ + ESP_LOGE(TAG,"missing URL parameter. Unable to start OTA"); + return ESP_ERR_INVALID_ARG; + } + ESP_LOGW(TAG, "Called to update the firmware from url: %s",bin_url); + if(config_set_value(NVS_TYPE_STR, "fwurl", bin_url) != ESP_OK){ + ESP_LOGE(TAG,"Failed to save the OTA url into nvs cache"); + return ESP_FAIL; + } - if(!wait_for_commit()){ - ESP_LOGW(TAG,"Unable to commit configuration. "); - } + if(!wait_for_commit()){ + ESP_LOGW(TAG,"Unable to commit configuration. "); + } - ESP_LOGW(TAG, "Rebooting to recovery to complete the installation"); + ESP_LOGW(TAG, "Rebooting to recovery to complete the installation"); return guided_factory(); return ESP_OK; #endif diff --git a/components/squeezelite-ota/squeezelite-ota.h b/components/squeezelite-ota/squeezelite-ota.h index 8e51ee74..2ae4dc43 100644 --- a/components/squeezelite-ota/squeezelite-ota.h +++ b/components/squeezelite-ota/squeezelite-ota.h @@ -9,6 +9,7 @@ #include "esp_attr.h" #include "esp_image_format.h" #include "esp_ota_ops.h" +#include "sys/param.h" #if RECOVERY_APPLICATION #define CODE_RAM_LOCATION @@ -35,7 +36,7 @@ // tasks #define OTA_TASK_PRIOTITY 6 -esp_err_t start_ota(const char * bin_url); +esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length); const char * ota_get_status(); uint8_t ota_get_pct_complete(); diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index 06eefd02..d3d10638 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -367,7 +367,31 @@ $(document).ready(function(){ console.log('sent config JSON with headers:', JSON.stringify(headers)); console.log('sent config JSON with data:', JSON.stringify(data)); }); - + $("#fwUpload").on("click", function() { + + var upload_path = "/flash.json"; + var fileInput = document.getElementById("flashfilename").files; + if (fileInput.length == 0) { + alert("No file selected!"); + } else { + var file = fileInput[0]; + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (xhttp.readyState == 4) { + if (xhttp.status == 200) { + showMessage(xhttp.responseText, 'INFO') + } else if (xhttp.status == 0) { + showMessage("Upload connection was closed abruptly!", 'ERROR'); + } else { + showMessage(xhttp.status + " Error!\n" + xhttp.responseText, 'ERROR'); + } + } + }; + xhttp.open("POST", upload_path, true); + xhttp.send(file); + } + enableStatusTimer = true; + }); $("#flash").on("click", function() { var data = { 'timestamp': Date.now() }; if (blockFlashButton) return; @@ -732,6 +756,8 @@ function checkStatus(){ $("footer.footer").addClass('sl'); $("#boot-button").html('Recovery'); $("#boot-form").attr('action', '/recovery.json'); + $('#uploaddiv"]').hide(); + enableStatusTimer = false; } } @@ -874,3 +900,6 @@ function showMessage(message, severity) { function inRange(x, min, max) { return ((x-min)*(x-max) <= 0); } + + + diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 56b27aa0..b7b305ea 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -41,6 +41,7 @@ function to process requests, decode URLs, serve files, etc. etc. #include #include #include "cJSON.h" +#include "config.h" #include "esp_system.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -323,7 +324,10 @@ static const char* get_path_from_uri(char *dest, const char *uri, size_t destsiz /* Set HTTP response content type according to file extension */ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename) { - if (IS_FILE_EXT(filename, ".pdf")) { + if(strlen(filename) ==0){ + // for root page, etc. + return httpd_resp_set_type(req, HTTPD_TYPE_TEXT); + } else if (IS_FILE_EXT(filename, ".pdf")) { return httpd_resp_set_type(req, "application/pdf"); } else if (IS_FILE_EXT(filename, ".html")) { return httpd_resp_set_type(req, HTTPD_TYPE_TEXT); @@ -340,6 +344,7 @@ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filena } else if (IS_FILE_EXT(filename, ".json")) { return httpd_resp_set_type(req, HTTPD_TYPE_JSON); } + /* This is a limited set only */ /* For any other type always set as plain text */ return httpd_resp_set_type(req, "text/plain"); @@ -360,6 +365,7 @@ static esp_err_t set_content_type_from_req(httpd_req_t *req) httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Browsing files forbidden."); return ESP_FAIL; } + set_content_type_from_file(req, filename); return ESP_OK; } @@ -548,6 +554,11 @@ esp_err_t config_post_handler(httpd_req_t *req){ // todo: redirect to login page // return ESP_OK; } + err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } + char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; cJSON *root = cJSON_Parse(buf); if(root == NULL){ @@ -637,7 +648,6 @@ esp_err_t config_post_handler(httpd_req_t *req){ if(err==ESP_OK){ - set_content_type_from_req(req); httpd_resp_sendstr(req, "{ \"result\" : \"OK\" }"); } cJSON_Delete(root); @@ -660,11 +670,16 @@ esp_err_t connect_post_handler(httpd_req_t *req){ char * ssid=NULL; char * password=NULL; char * host_name=NULL; - set_content_type_from_req(req); + esp_err_t err = post_handler_buff_receive(req); if(err!=ESP_OK){ return err; } + err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } + char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; if(!is_user_authenticated(req)){ // todo: redirect to login page @@ -724,7 +739,10 @@ esp_err_t connect_delete_handler(httpd_req_t *req){ // todo: redirect to login page // return ESP_OK; } - set_content_type_from_req(req); + esp_err_t err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } httpd_resp_send(req, (const char *)success, strlen(success)); wifi_manager_disconnect_async(); @@ -737,7 +755,11 @@ esp_err_t reboot_ota_post_handler(httpd_req_t *req){ // todo: redirect to login page // return ESP_OK; } - set_content_type_from_req(req); + esp_err_t err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } + httpd_resp_send(req, (const char *)success, strlen(success)); wifi_manager_reboot(OTA); return ESP_OK; @@ -749,7 +771,10 @@ esp_err_t reboot_post_handler(httpd_req_t *req){ // todo: redirect to login page // return ESP_OK; } - set_content_type_from_req(req); + esp_err_t err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } httpd_resp_send(req, (const char *)success, strlen(success)); wifi_manager_reboot(RESTART); return ESP_OK; @@ -761,12 +786,91 @@ esp_err_t recovery_post_handler(httpd_req_t *req){ // todo: redirect to login page // return ESP_OK; } - set_content_type_from_req(req); + esp_err_t err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } httpd_resp_send(req, (const char *)success, strlen(success)); wifi_manager_reboot(RECOVERY); return ESP_OK; } +#if RECOVERY_APPLICATION +esp_err_t flash_post_handler(httpd_req_t *req){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + char success[]="File uploaded. Flashing started."; + if(!is_user_authenticated(req)){ + // todo: redirect to login page + // return ESP_OK; + } + esp_err_t err = httpd_resp_set_type(req, HTTPD_TYPE_TEXT); + if(err != ESP_OK){ + return err; + } + char * binary_buffer = malloc(req->content_len); + if(binary_buffer == NULL){ + ESP_LOGE(TAG, "File too large : %d bytes", req->content_len); + /* Respond with 400 Bad Request */ + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, + "Binary file too large. Unable to allocate memory!"); + return ESP_FAIL; + } + ESP_LOGI(TAG, "Receiving ota binary file"); + /* Retrieve the pointer to scratch buffer for temporary storage */ + char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; + + char *head=binary_buffer; + int received; + + /* Content length of the request gives + * the size of the file being uploaded */ + int remaining = req->content_len; + + while (remaining > 0) { + + ESP_LOGI(TAG, "Remaining size : %d", remaining); + /* Receive the file part by part into a buffer */ + if ((received = httpd_req_recv(req, buf, MIN(remaining, SCRATCH_BUFSIZE))) <= 0) { + if (received == HTTPD_SOCK_ERR_TIMEOUT) { + /* Retry if timeout occurred */ + continue; + } + FREE_RESET(binary_buffer); + ESP_LOGE(TAG, "File reception failed!"); + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file"); + err = ESP_FAIL; + goto bail_out; + } + + /* Write buffer content to file on storage */ + if (received ) { + memcpy(head,buf,received ); + head+=received; + } + + /* Keep track of remaining size of + * the file left to be uploaded */ + remaining -= received; + } + + /* Close file upon upload completion */ + ESP_LOGI(TAG, "File reception complete. Invoking OTA process."); + err = start_ota(NULL, binary_buffer, req->content_len); + if(err!=ESP_OK){ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "OTA processing failed"); + goto bail_out; + } + + //todo: handle this in ajax. For now, just send the root page + httpd_resp_send(req, (const char *)success, strlen(success)); + +bail_out: + + return err; +} + +#endif char * get_ap_ip_address(){ static char ap_ip_address[IP4ADDR_STRLEN_MAX]={}; @@ -869,7 +973,7 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ char *req_host = alloc_get_http_header(req, "Host"); user_agent = alloc_get_http_header(req,"User-Agent"); - if((useragentiscaptivenetwork = strcasestr(user_agent,"CaptiveNetworkSupport"))==true){ + if((useragentiscaptivenetwork = (user_agent!=NULL && strcasestr(user_agent,"CaptiveNetworkSupport"))==true)){ ESP_LOGW_LOC(TAG,"Found user agent that supports captive networks! [%s]",user_agent); } @@ -941,7 +1045,10 @@ esp_err_t status_get_handler(httpd_req_t *req){ // todo: redirect to login page // return ESP_OK; } - set_content_type_from_req(req); + esp_err_t err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { char *buff = wifi_manager_alloc_get_ip_info_json(); diff --git a/components/wifi-manager/http_server_handlers.h b/components/wifi-manager/http_server_handlers.h index 82a10560..d672933b 100644 --- a/components/wifi-manager/http_server_handlers.h +++ b/components/wifi-manager/http_server_handlers.h @@ -88,6 +88,9 @@ esp_err_t connect_delete_handler(httpd_req_t *req); esp_err_t reboot_ota_post_handler(httpd_req_t *req); esp_err_t reboot_post_handler(httpd_req_t *req); esp_err_t recovery_post_handler(httpd_req_t *req); +#if RECOVERY_APPLICATION +esp_err_t flash_post_handler(httpd_req_t *req); +#endif esp_err_t status_get_handler(httpd_req_t *req); esp_err_t ap_scan_handler(httpd_req_t *req); esp_err_t redirect_ev_handler(httpd_req_t *req); diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index c40eef68..36022538 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -345,21 +345,20 @@

Firmware URL:

- -
- -
+
diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c index bf44abfa..4fabda05 100644 --- a/components/wifi-manager/wifi_manager.c +++ b/components/wifi-manager/wifi_manager.c @@ -66,6 +66,7 @@ Contains the freeRTOS task and all necessary support #include "globdefs.h" #ifndef RECOVERY_APPLICATION +#pragma warning "Defaulting to squeezelite build" #define RECOVERY_APPLICATION 0 #endif @@ -1470,7 +1471,7 @@ void wifi_manager( void * pvParameters ){ break; case ORDER_RESTART_OTA_URL: ESP_LOGD(TAG, "Calling start_ota."); - start_ota(msg.param); + start_ota(msg.param, NULL, 0); free(msg.param); break; diff --git a/components/wifi-manager/wifi_manager.h b/components/wifi-manager/wifi_manager.h index 5b260e1c..459a48c2 100644 --- a/components/wifi-manager/wifi_manager.h +++ b/components/wifi-manager/wifi_manager.h @@ -48,7 +48,6 @@ extern "C" { #if RECOVERY_APPLICATION==1 #elif RECOVERY_APPLICATION==0 -#pragma message "compiling for squeezelite." #else #error "unknown configuration" #endif diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 3286d1c4..523352eb 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -19,7 +19,7 @@ * */ -#include "http_server_handlers.h" +#include "http_server_handlers.h" #include "esp_log.h" #include "esp_http_server.h" #include @@ -70,6 +70,12 @@ void register_regular_handlers(httpd_handle_t server){ httpd_uri_t connect_delete = { .uri = "/connect.json", .method = HTTP_DELETE, .handler = connect_delete_handler, .user_ctx = rest_context }; httpd_register_uri_handler(server, &connect_delete); +#if RECOVERY_APPLICATION + + httpd_uri_t flash_post = { .uri = "/flash.json", .method = HTTP_POST, .handler = flash_post_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &flash_post); +#endif + // from https://github.com/tripflex/wifi-captive-portal/blob/master/src/mgos_wifi_captive_portal.c // https://unix.stackexchange.com/questions/432190/why-isnt-androids-captive-portal-detection-triggering-a-browser-window @@ -97,6 +103,7 @@ void register_regular_handlers(httpd_handle_t server){ httpd_register_uri_handler(server, &connect_redirect_8); + ESP_LOGD(TAG,"Registering default error handler for 404"); httpd_register_err_handler(server, HTTPD_404_NOT_FOUND,&err_handler); @@ -150,223 +157,3 @@ void stop_webserver(httpd_handle_t server) - - -#if 0 - -if(strstr(line, "GET / ")) { - netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, index_html_start, index_html_end- index_html_start, NETCONN_NOCOPY); -} -else if(strstr(line, "GET /code.js ")) { - netconn_write(conn, http_js_hdr, sizeof(http_js_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, code_js_start, code_js_end - code_js_start, NETCONN_NOCOPY); -} -else if(strstr(line, "GET /style.css ")) { - netconn_write(conn, http_css_hdr, sizeof(http_css_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, style_css_start, style_css_end - style_css_start, NETCONN_NOCOPY); -} -else if(strstr(line, "GET /jquery.js ")) { - http_server_send_resource_file(conn,jquery_gz_start, jquery_gz_end, "text/javascript", "gzip" ); -} -else if(strstr(line, "GET /popper.js ")) { - http_server_send_resource_file(conn,popper_gz_start, popper_gz_end, "text/javascript", "gzip" ); -} -else if(strstr(line, "GET /bootstrap.js ")) { - http_server_send_resource_file(conn,bootstrap_js_gz_start, bootstrap_js_gz_end, "text/javascript", "gzip" ); -} -else if(strstr(line, "GET /bootstrap.css ")) { - http_server_send_resource_file(conn,bootstrap_css_gz_start, bootstrap_css_gz_end, "text/css", "gzip" ); -} - -//dynamic stuff -else if(strstr(line, "GET /scan.json ")) { - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); -} -else if(strstr(line, "GET /ap.json ")) { - /* if we can get the mutex, write the last version of the AP list */ - ESP_LOGI(TAG, "Processing ap.json request"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - char *buff = wifi_manager_alloc_get_ap_list_json(); - wifi_manager_unlock_json_buffer(); - if(buff!=NULL){ - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - ESP_LOGD(TAG, "Error retrieving ap list json string. "); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex"); - } - /* request a wifi scan */ - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - ESP_LOGI(TAG, "Done serving ap.json"); -} -else if(strstr(line, "GET /config.json ")) { - ESP_LOGI(TAG, "Serving config.json"); - ESP_LOGI(TAG, "About to get config from flash"); - http_server_send_config_json(conn); - ESP_LOGD(TAG, "Done serving config.json"); -} -else if(strstr(line, "POST /config.json ")) { - ESP_LOGI(TAG, "Serving POST config.json"); - int lenA=0; - char * last_parm=save_ptr; - char * next_parm=save_ptr; - char * last_parm_name=NULL; - bool bErrorFound=false; - bool bOTA=false; - char * otaURL=NULL; - // todo: implement json body parsing - //http_server_process_config(conn,save_ptr); - - while(last_parm!=NULL) { - // Search will return - ESP_LOGD(TAG, "Getting parameters from X-Custom headers"); - last_parm = http_server_search_header(next_parm, "X-Custom-", &lenA, &last_parm_name,&next_parm,buf+buflen); - if(last_parm!=NULL && last_parm_name!=NULL) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST config.json, config %s=%s", last_parm_name, last_parm); - if(strcmp(last_parm_name, "fwurl")==0) { - // we're getting a request to do an OTA from that URL - ESP_LOGW(TAG, "Found OTA request!"); - otaURL=strdup(last_parm); - bOTA=true; - } - else { - ESP_LOGV(TAG, "http_server_netconn_serve: POST config.json Storing parameter"); - if(config_set_value(NVS_TYPE_STR, last_parm_name , last_parm) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save nvs value."); - } - } - } - if(last_parm_name!=NULL) { - free(last_parm_name); - last_parm_name=NULL; - } - } - if(bErrorFound) { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); //400 invalid request - } - else { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - if(bOTA) { - -#if RECOVERY_APPLICATION - ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); -#else - ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); -#endif - wifi_manager_reboot_ota(otaURL); - free(otaURL); - } - } - ESP_LOGI(TAG, "Done Serving POST config.json"); -} -else if(strstr(line, "POST /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST /connect.json"); - bool found = false; - int lenS = 0, lenP = 0, lenN = 0; - char *ssid = NULL, *password = NULL; - ssid = http_server_get_header(save_ptr, "X-Custom-ssid: ", &lenS); - password = http_server_get_header(save_ptr, "X-Custom-pwd: ", &lenP); - char * new_host_name_b = http_server_get_header(save_ptr, "X-Custom-host_name: ", &lenN); - if(lenN > 0){ - lenN++; - char * new_host_name = malloc(lenN); - strlcpy(new_host_name, new_host_name_b, lenN); - if(config_set_value(NVS_TYPE_STR, "host_name", new_host_name) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save host name configuration"); - } - free(new_host_name); - } - - if(ssid && lenS <= MAX_SSID_SIZE && password && lenP <= MAX_PASSWORD_SIZE) { - wifi_config_t* config = wifi_manager_get_wifi_sta_config(); - memset(config, 0x00, sizeof(wifi_config_t)); - memcpy(config->sta.ssid, ssid, lenS); - memcpy(config->sta.password, password, lenP); - ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); - wifi_manager_connect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - found = true; - } - else{ - ESP_LOGE(TAG, "SSID or Password invalid"); - } - - - if(!found) { - /* bad request the authentification header is not complete/not the correct format */ - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request the authentification header is not complete/not the correct format"); - } - - ESP_LOGI(TAG, "http_server_netconn_serve: done serving connect.json"); -} -else if(strstr(line, "DELETE /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: DELETE /connect.json"); - /* request a disconnection from wifi and forget about it */ - wifi_manager_disconnect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - ESP_LOGI(TAG, "http_server_netconn_serve: done serving DELETE /connect.json"); -} -else if(strstr(line, "POST /reboot_ota.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot_ota.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(OTA); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot_ota.json"); -} -else if(strstr(line, "POST /reboot.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RESTART); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot.json"); -} -else if(strstr(line, "POST /recovery.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST recovery.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RECOVERY); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST recovery.json"); -} -else if(strstr(line, "GET /status.json ")) { - ESP_LOGI(TAG, "Serving status.json"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - char *buff = wifi_manager_alloc_get_ip_info_json(); - wifi_manager_unlock_json_buffer(); - if(buff) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /status failed to obtain mutex"); - } - ESP_LOGI(TAG, "Done Serving status.json"); -} -else { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request from host: %s, request %s",remote_address, line); -} -} -} -else { -ESP_LOGE(TAG, "URL not found processing for remote host : %s",remote_address); -netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY); -} -free(host); - -} -#endif diff --git a/main/esp_app_main.c b/main/esp_app_main.c index e8921048..3d2f35cb 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -421,7 +421,7 @@ void app_main() taskYIELD(); } ESP_LOGI(TAG,"Updating firmware from link: %s",fwurl); - start_ota(fwurl); + start_ota(fwurl, NULL, 0); #else ESP_LOGE(TAG,"Restarted to application partition. We're not going to perform OTA!"); #endif From c9fab19ce887912b098440140437d4335326b955 Mon Sep 17 00:00:00 2001 From: Christian Herzog Date: Sun, 16 Feb 2020 17:09:09 +0100 Subject: [PATCH 13/46] fix test css/js --- components/wifi-manager/index.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index 36022538..1ea702c8 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -4,20 +4,20 @@ - - + + - - - - + + + + esp32-wifi-manager From 0809a6e70cad7ada7f43ba07c2b3d4a729c7df37 Mon Sep 17 00:00:00 2001 From: Christian Herzog Date: Sun, 16 Feb 2020 19:42:48 +0100 Subject: [PATCH 14/46] tweak FW upload UI --- components/wifi-manager/code.js | 1 - components/wifi-manager/http_server_handlers.c | 4 ++-- components/wifi-manager/index.html | 17 +++++++---------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index d3d10638..b4e1b852 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -368,7 +368,6 @@ $(document).ready(function(){ console.log('sent config JSON with data:', JSON.stringify(data)); }); $("#fwUpload").on("click", function() { - var upload_path = "/flash.json"; var fileInput = document.getElementById("flashfilename").files; if (fileInput.length == 0) { diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index b7b305ea..fb899170 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -430,13 +430,13 @@ esp_err_t resource_filehandler(httpd_req_t *req){ httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); const size_t file_size = (bootstrap_js_gz_end - bootstrap_js_gz_start); httpd_resp_send(req, (const char *)bootstrap_js_gz_start, file_size); - } + } else if(strstr(filename, "bootstrap.css")) { set_content_type_from_file(req, filename); httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); const size_t file_size = (bootstrap_css_gz_end - bootstrap_css_gz_start); httpd_resp_send(req, (const char *)bootstrap_css_gz_start, file_size); - } + } else { ESP_LOGE_LOC(TAG, "Unknown resource [%s] from path [%s] ", filename,filepath); /* Respond with 404 Not Found */ diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index 1ea702c8..3f7b67e1 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -346,19 +346,16 @@

Firmware URL:

- +
-
OR
-
-
- - -
-
- Upload +

OR

+
+ +
+
- +
From 4de4e07d99e77eba88569c6db3a3bbc706944530 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Wed, 19 Feb 2020 08:02:58 -0500 Subject: [PATCH 15/46] messaging subsystem wip --- .cproject | 168 ++++++++++++------ .../com.googlecode.cppcheclipse.core.prefs | 2 + .settings/language.settings.xml | 6 +- .settings/org.eclipse.cdt.core.prefs | 9 +- Makefile | 5 +- components/cmd_i2c/CMakeLists.txt | 2 +- components/cmd_i2c/component.mk | 7 +- components/cmd_nvs/component.mk | 3 - components/cmd_system/component.mk | 2 - components/display/CMakeLists.txt | 2 +- components/driver_bt/CMakeLists.txt | 2 +- components/driver_bt/component.mk | 4 - components/raop/component.mk | 4 +- components/services/CMakeLists.txt | 4 +- components/services/messaging.c | 125 +++++++++++++ components/services/messaging.h | 25 +++ components/services/services.c | 3 +- components/squeezelite-ota/component.mk | 3 - components/squeezelite-ota/squeezelite-ota.c | 37 ++-- components/squeezelite/component.mk | 28 +-- components/telnet/CMakeLists.txt | 2 +- components/telnet/component.mk | 4 +- components/wifi-manager/code.js | 15 +- components/wifi-manager/component.mk | 8 +- .../wifi-manager/http_server_handlers.c | 28 ++- .../wifi-manager/http_server_handlers.h | 2 + .../wifi-manager/wifi_manager_http_server.c | 6 +- main/component.mk | 6 +- 28 files changed, 369 insertions(+), 143 deletions(-) create mode 100644 .settings/com.googlecode.cppcheclipse.core.prefs create mode 100644 components/services/messaging.c create mode 100644 components/services/messaging.h diff --git a/.cproject b/.cproject index e4d56c6d..be379242 100644 --- a/.cproject +++ b/.cproject @@ -143,7 +143,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -225,37 +225,57 @@ - + - @@ -299,7 +311,7 @@ - + @@ -321,37 +333,43 @@ - + - @@ -495,6 +505,24 @@ + + + + + + + + + + + + + + + + + + @@ -507,6 +535,12 @@ + + + + + + @@ -543,6 +577,12 @@ + + + + + + @@ -555,17 +595,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/.settings/com.googlecode.cppcheclipse.core.prefs b/.settings/com.googlecode.cppcheclipse.core.prefs new file mode 100644 index 00000000..b21d0f0a --- /dev/null +++ b/.settings/com.googlecode.cppcheclipse.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +suppressions=rO0ABXNyAAxqYXZhLmlvLkZpbGUELaRFDg3k/wMAAUwABHBhdGh0ABJMamF2YS9sYW5nL1N0cmluZzt4cHQAJWNvbXBvbmVudHNcd2lmaS1tYW5hZ2VyXGh0dHBfc2VydmVyLmN3AgBceA\=\=;comparePointers;395\!rO0ABXNyAAxqYXZhLmlvLkZpbGUELaRFDg3k/wMAAUwABHBhdGh0ABJMamF2YS9sYW5nL1N0cmluZzt4cHQAE21haW5cZXNwX2FwcF9tYWluLmN3AgBceA\=\=;comparePointers;176\!rO0ABXNyAAxqYXZhLmlvLkZpbGUELaRFDg3k/wMAAUwABHBhdGh0ABJMamF2YS9sYW5nL1N0cmluZzt4cHQAJ2NvbXBvbmVudHNcdGVsbmV0XGxpYnRlbG5ldFxsaWJ0ZWxuZXQuY3cCAFx4;va_list_usedBeforeStarted;2147483647\! diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index cbee2f3c..5c545a49 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -57,9 +57,9 @@ - + - + @@ -81,7 +81,7 @@ - + diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs index d5d56fd7..7a6fc1e3 100644 --- a/.settings/org.eclipse.cdt.core.prefs +++ b/.settings/org.eclipse.cdt.core.prefs @@ -32,7 +32,7 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.16039962 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=0 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/IDF_PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/IDF_PATH/operation=replace -environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/IDF_PATH/value=C\:/msys32/opt/esp-idf +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/IDF_PATH/value=c\:/msys32/opt/esp-idf environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/PATH/operation=replace environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/PATH/value=C\:\\msys32\\usr\\bin;C\:\\msys32\\mingw32\\bin;C\:\\msys32\\opt\\xtensa-esp32-elf\\bin\\ @@ -52,10 +52,10 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.16039962 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=1 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/operation=replace -environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/value=C\:/msys32/opt/esp-idf +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/value=c\:/msys32/opt/esp-idf environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/operation=replace -environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/value=C\:\\msys32\\opt\\openocd-esp32\\bin;c\:\\msys32\\opt\\xtensa-esp32-elf\\bin\\;c\:\\msys32\\mingw32\\bin;C\:\\msys32\\usr\\bin;c\:\\Python27;C\:\\msys32\\usr\\bin\\vendor_perl;C\:\\msys32\\usr\\bin\\core_perl +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/value=c\:\\msys32\\opt\\openocd-esp32\\bin;c\:\\msys32\\opt\\xtensa-esp32-elf\\bin\\;c\:\\msys32\\mingw32\\bin;C\:\\msys32\\usr\\bin;c\:\\Python27;C\:\\msys32\\usr\\bin\\vendor_perl;C\:\\msys32\\usr\\bin\\core_perl environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_NAME/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_NAME/operation=replace environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_NAME/value=recovery @@ -102,6 +102,9 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/PROJECT_ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/PROJECT_VER/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/PROJECT_VER/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/PROJECT_VER/value=custom +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/WIN_IDF_PATH/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/WIN_IDF_PATH/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/WIN_IDF_PATH/value=c\:/msys32/opt/esp-idf environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/append=true environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348/appendContributed=true environment/project/cdt.managedbuild.toolchain.gnu.cygwin.base.58932738.859326707/BATCH_BUILD/delimiter=; diff --git a/Makefile b/Makefile index f209bfed..654bfc47 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,10 @@ #recovery: CPPFLAGS+=-DRECOVERY_APPLICATION=1 PROJECT_NAME?=squeezelite +CPPFLAGS+= -Wno-error=maybe-uninitialized \ + -I$(PROJECT_PATH)/main + include $(IDF_PATH)/make/project.mk # for future gcc version, this could be needed: CPPFLAGS+= -Wno-error=format-overflow -Wno-error=stringop-truncation -CPPFLAGS+= -Wno-error=maybe-uninitialized + diff --git a/components/cmd_i2c/CMakeLists.txt b/components/cmd_i2c/CMakeLists.txt index 421e8fa7..2282da00 100644 --- a/components/cmd_i2c/CMakeLists.txt +++ b/components/cmd_i2c/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRCS "cmd_i2ctools.c" - INCLUDE_DIRS "." "../tools/" + INCLUDE_DIRS "." "$(PROJECT_PATH)/components/tools/" REQUIRES esp_common PRIV_REQUIRES freertos esp32 spi_flash newlib log console pthread ) diff --git a/components/cmd_i2c/component.mk b/components/cmd_i2c/component.mk index 0b379962..d9c79ce7 100644 --- a/components/cmd_i2c/component.mk +++ b/components/cmd_i2c/component.mk @@ -1,9 +1,6 @@ # # Main Makefile. This is basically the same as a component makefile. # -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO \ - -I$(COMPONENT_PATH)/../tools COMPONENT_ADD_INCLUDEDIRS := . -COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools -COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../squeezelite-ota -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO +COMPONENT_SRCDIRS := . \ No newline at end of file diff --git a/components/cmd_nvs/component.mk b/components/cmd_nvs/component.mk index a71c86c5..e0e9f4c1 100644 --- a/components/cmd_nvs/component.mk +++ b/components/cmd_nvs/component.mk @@ -8,6 +8,3 @@ # COMPONENT_ADD_INCLUDEDIRS := . -CFLAGS += -I$(COMPONENT_PATH)/../squeezelite-ota -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/components/tools/ -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main diff --git a/components/cmd_system/component.mk b/components/cmd_system/component.mk index 93ab014b..e0e9f4c1 100644 --- a/components/cmd_system/component.mk +++ b/components/cmd_system/component.mk @@ -8,5 +8,3 @@ # COMPONENT_ADD_INCLUDEDIRS := . -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/components/tools/ \ No newline at end of file diff --git a/components/display/CMakeLists.txt b/components/display/CMakeLists.txt index 4672e0c6..0f85bb68 100644 --- a/components/display/CMakeLists.txt +++ b/components/display/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRCS "led.c" "audio_controls.c" "buttons.c" "services.c" "monitor.c"INCLUDE_DIRS - INCLUDE_DIRS . ../tools/ + INCLUDE_DIRS . $(PROJECT_PATH)/components/tools/ ) diff --git a/components/driver_bt/CMakeLists.txt b/components/driver_bt/CMakeLists.txt index 7c31465a..06d03979 100644 --- a/components/driver_bt/CMakeLists.txt +++ b/components/driver_bt/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRCS "bt_app_core.c" "bt_app_sink.c" "bt_app_source.c" - INCLUDE_DIRS "." "../tools/" + INCLUDE_DIRS "." "$($(PROJECT_PATH)/components/)/components/tools/" REQUIRES esp_common PRIV_REQUIRES freertos bt io nvs_flash esp32 spi_flash newlib log console pthread ) diff --git a/components/driver_bt/component.mk b/components/driver_bt/component.mk index 625b10be..e0e9f4c1 100644 --- a/components/driver_bt/component.mk +++ b/components/driver_bt/component.mk @@ -7,8 +7,4 @@ # please read the SDK documents if you need to do this. # -CFLAGS += -I$(COMPONENT_PATH)/../tools \ - -I$(COMPONENT_PATH)/../config COMPONENT_ADD_INCLUDEDIRS := . -COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ diff --git a/components/raop/component.mk b/components/raop/component.mk index e06d07e7..55f53715 100644 --- a/components/raop/component.mk +++ b/components/raop/component.mk @@ -8,6 +8,6 @@ # CFLAGS += -fstack-usage\ - -I$(COMPONENT_PATH)/../tools \ - -I$(COMPONENT_PATH)/../codecs/inc/alac \ + -I$(PROJECT_PATH)/components/tools \ + -I$(PROJECT_PATH)/components/codecs/inc/alac \ -I$(PROJECT_PATH)/main/ diff --git a/components/services/CMakeLists.txt b/components/services/CMakeLists.txt index 4672e0c6..e1ffc4b9 100644 --- a/components/services/CMakeLists.txt +++ b/components/services/CMakeLists.txt @@ -1,5 +1,5 @@ -idf_component_register(SRCS "led.c" "audio_controls.c" "buttons.c" "services.c" "monitor.c"INCLUDE_DIRS - INCLUDE_DIRS . ../tools/ +idf_component_register(SRCS "led.c" "audio_controls.c" "buttons.c" "services.c" "monitor.c" "messaging.c" + INCLUDE_DIRS . $(PROJECT_PATH)/components/tools/ ) diff --git a/components/services/messaging.c b/components/services/messaging.c new file mode 100644 index 00000000..8144b1eb --- /dev/null +++ b/components/services/messaging.c @@ -0,0 +1,125 @@ + /** + * + */ +#include // Required for libtelnet.h +#include +#include "stdbool.h" +#include +#include +#include +#include +#include "esp_app_trace.h" +#include "esp_attr.h" +#include "config.h" +#include "nvs_utilities.h" +#include "platform_esp32.h" +#include "messaging.h" +/************************************ + * Globals + */ + +const static char tag[] = "messaging"; + +static messaging_list_t top; +RingbufHandle_t messaging_create_ring_buffer(uint8_t max_count){ + RingbufHandle_t buf_handle = NULL; + StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM); + if (buffer_struct != NULL) { + size_t buf_size = (size_t )(sizeof(single_message_t)+8)*(size_t )(max_count>0?max_count:5); // no-split buffer requires an additional 8 bytes + uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM); + if (buffer_storage== NULL) { + ESP_LOGE(tag,"Failed to allocate memory for messaging ring buffer !"); + } + else { + buf_handle = xRingbufferCreateStatic(buf_size, RINGBUF_TYPE_NOSPLIT, buffer_storage, buffer_struct); + if (buf_handle == NULL) { + ESP_LOGE(tag,"Failed to create messaging ring buffer !"); + } + } + } + else { + ESP_LOGE(tag,"Failed to create ring buffer for messaging!"); + } + return buf_handle; +} + +RingbufHandle_t messaging_register_subscriber(uint8_t max_count, char * name){ + messaging_list_t * cur=⊤ + while(cur->next){ + cur = cur->next; + } + cur->next=heap_caps_malloc(sizeof(messaging_list_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if(!cur->next){ + ESP_LOGE(tag,"Failed to allocate messaging subscriber entry!"); + return NULL; + } + memset(cur->next,0x00,sizeof(messaging_list_t)); + cur = cur->next; + cur->buf_handle = messaging_create_ring_buffer(max_count); + strncpy(cur->subscriber_name,name,sizeof(cur->subscriber_name)); + + return cur->buf_handle; +} +esp_err_t messaging_service_init(){ + top.buf_handle = messaging_create_ring_buffer(max_count); + if(!top.buf_handle){ + ESP_LOGE(tag, "messaging service init failed."); + } + strncpy(top.subscriber_name,"messaging"); + return (top.buf_handle!=NULL); +} + + +cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){ + single_message_t * message=NULL; + cJSON * json_messages=cJSON_CreateArray(); + cJSON * json_message=NULL; + size_t item_size; + UBaseType_t uxItemsWaiting; + vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); + if(uxItemsWaiting>0){ + message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50)); + //Check received data + if (message== NULL) { + ESP_LOGE(tag,"Failed to receive message from buffer!"); + } + else { + json_message = cJSON_CreateObject(); + cJSON_AddStringToObject(json_message, "message", message->message); + cJSON_AddStringToObject(json_message, "type", message->message); + cJSON_AddNumberToObject(json_message,"sent_time",message->sent_time); + cJSON_AddNumberToObject(json_message,"current_time",esp_timer_get_time() / 1000); + cJSON_AddItemToArray(json_messages,json_message); + vRingbufferReturnItem(buf_handle, (void *)message); + } + } + return json_messages; +} + +void messaging_release_message(RingbufHandle_t buf_handle, single_message_t * message){ + +} +esp_err_t messageing_post_to_queue(messaging_list_t * subscriber, single_message_t * message){ + UBaseType_t res = xRingbufferSend(subscriber->buf_handle, message, sizeof(message), pdMS_TO_TICKS(1000)); + if (res != pdTRUE) { + ESP_LOGE(tag,"Failed to post message to subscriber %s",subscriber->subscriber_name); + return ESP_FAIL; + } + return ESP_OK; +} +void messaging_post_message(messaging_types type, char *fmt, ...){ + single_message_t message={}; + messaging_list_t * cur=⊤ + va_list va; + va_start(va, fmt); + vsnprintf(message.message, sizeof(message.message), fmt, va); + va_end(va); + message.type = type; + message.sent_time = esp_timer_get_time() / 1000; + while(cur->next){ + messageing_post_to_queue(cur, &message); + cur = cur->next; + } + return; + +} diff --git a/components/services/messaging.h b/components/services/messaging.h new file mode 100644 index 00000000..54fb5109 --- /dev/null +++ b/components/services/messaging.h @@ -0,0 +1,25 @@ +#include "sdkconfig.h" +#include "freertos/ringbuf.h" +#include "cJSON.h" +#pragma once +typedef enum { + MESSAGING_INFO, + MESSAGING_WARNING, + MESSAGING_ERROR +} messaging_types; +typedef struct { + void * next; + char subscriber_name[21]; + RingbufHandle_t buf_handle; +} messaging_list_t; + +typedef struct { + time_t sent_time; + messaging_types type; + char message[101]; +} single_message_t; + +cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle); +RingbufHandle_t messaging_register_subscriber(uint8_t max_count, char * name); + +void messaging_post_message(messaging_types type, char * fmt, ...); diff --git a/components/services/services.c b/components/services/services.c index 36e53b60..193a2b22 100644 --- a/components/services/services.c +++ b/components/services/services.c @@ -51,6 +51,7 @@ void set_power_gpio(int gpio, char *value) { * */ void services_init(void) { + messaging_service_init(); gpio_install_isr_service(0); #ifdef CONFIG_I2C_LOCKED @@ -94,4 +95,4 @@ void services_init(void) { led_svc_init(); battery_svc_init(); monitor_svc_init(); -} \ No newline at end of file +} diff --git a/components/squeezelite-ota/component.mk b/components/squeezelite-ota/component.mk index 7f4b4f39..d0d6918e 100644 --- a/components/squeezelite-ota/component.mk +++ b/components/squeezelite-ota/component.mk @@ -5,9 +5,6 @@ # todo: add support for https COMPONENT_ADD_INCLUDEDIRS := . -COMPONENT_ADD_INCLUDEDIRS += include -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/components/tools CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO -DCONFIG_OTA_ALLOW_HTTP=1 diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 7488d355..62b91d7c 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -28,6 +28,7 @@ #include "esp_flash_encrypt.h" #include "esp_spi_flash.h" #include "sdkconfig.h" +#include "messaging.h" #include "esp_ota_ops.h" extern const char * get_certificate(); @@ -75,8 +76,6 @@ static struct { struct timeval tv; static esp_http_client_config_t ota_config; -extern void wifi_manager_refresh_ota_json(); - void _printMemStats(){ ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)", heap_caps_get_free_size(MALLOC_CAP_INTERNAL), @@ -84,22 +83,12 @@ void _printMemStats(){ heap_caps_get_free_size(MALLOC_CAP_SPIRAM), heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); } -void triggerStatusJsonRefresh(bool bDelay,const char * status, ...){ +void sendMessaging(messaging_types type,char * fmt, ...){ va_list args; - va_start(args, status); - vsnprintf(ota_status.status_text,sizeof(ota_status.status_text)-1,status, args); + va_start(args, fmt); + messaging_post_message(type, fmt, args); va_end(args); _printMemStats(); - wifi_manager_refresh_ota_json(); - if(bDelay){ - ESP_LOGD(TAG,"Holding task..."); - vTaskDelay(200 / portTICK_PERIOD_MS); // wait here for a short amount of time. This will help with refreshing the UI status - ESP_LOGD(TAG,"Done holding task..."); - } - else { - ESP_LOGI(TAG,"%s",ota_status.status_text); - taskYIELD(); - } } const char * ota_get_status(){ if(!ota_status.bInitialized) @@ -151,7 +140,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) case HTTP_EVENT_ON_CONNECTED: ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); - if(ota_status.bOTAStarted) triggerStatusJsonRefresh(true,"Installing..."); + if(ota_status.bOTAStarted) sendMessaging(MESSAGING_INFO,"Installing..."); ota_status.total_image_len=0; ota_status.actual_image_len=0; ota_status.lastpct=0; @@ -193,7 +182,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ memset(&ota_config, 0x00, sizeof(ota_config)); ota_status.bInitialized = true; - triggerStatusJsonRefresh(true,"Initializing..."); + sendMessaging(MESSAGING_INFO,"Initializing..."); ota_status.ota_type= OTA_TYPE_INVALID; if(p_ota_thread_parms->url !=NULL && strlen(p_ota_thread_parms->url)>0 ){ ota_status.ota_type= OTA_TYPE_HTTP; @@ -294,7 +283,7 @@ esp_err_t _erase_last_boot_app_partition(esp_partition_t *ota_partition) err=esp_partition_erase_range(ota_partition, i*single_pass_size, single_pass_size); if(err!=ESP_OK) return err; if(i%2) { - triggerStatusJsonRefresh(false,"Erasing flash (%u/%u)",i,num_passes); + sendMessaging(MESSAGING_INFO,"Erasing flash (%u/%u)",i,num_passes); } vTaskDelay(200/ portTICK_PERIOD_MS); // wait here for a short amount of time. This will help with reducing WDT errors } @@ -302,7 +291,7 @@ esp_err_t _erase_last_boot_app_partition(esp_partition_t *ota_partition) err=esp_partition_erase_range(ota_partition, ota_partition->size-remain_size, remain_size); if(err!=ESP_OK) return err; } - triggerStatusJsonRefresh(true,"Erasing flash complete."); + sendMessaging(MESSAGING_INFO,"Erasing flash complete."); taskYIELD(); return ESP_OK; } @@ -394,7 +383,7 @@ void ota_task_cleanup(const char * message, ...){ if(message!=NULL){ va_list args; va_start(args, message); - triggerStatusJsonRefresh(true,message, args); + sendMessaging(MESSAGING_ERROR,message, args); va_end(args); ESP_LOGE(TAG, "%s",ota_status.status_text); } @@ -438,7 +427,7 @@ void ota_task(void *pvParameter) /* Locate and erase ota application partition */ ESP_LOGW(TAG,"**************** Expecting WATCHDOG errors below during flash erase. This is OK and not to worry about **************** "); - triggerStatusJsonRefresh(true,"Erasing OTA partition"); + sendMessaging(MESSAGING_INFO,"Erasing OTA partition"); esp_partition_t *ota_partition = _get_ota_partition(ESP_PARTITION_SUBTYPE_APP_OTA_0); if(ota_partition == NULL){ ESP_LOGE(TAG,"Unable to locate OTA application partition. "); @@ -460,7 +449,7 @@ void ota_task(void *pvParameter) _printMemStats(); ota_status.bOTAStarted = true; - triggerStatusJsonRefresh(true,"Starting OTA..."); + sendMessaging(MESSAGING_INFO,"Starting OTA..."); if (ota_status.ota_type == OTA_TYPE_HTTP){ ota_http_client = esp_http_client_init(&ota_config); if (ota_http_client == NULL) { @@ -554,7 +543,7 @@ void ota_task(void *pvParameter) gettimeofday(&tv, NULL); uint32_t elapsed_ms= (tv.tv_sec-ota_status.OTA_start.tv_sec )*1000+(tv.tv_usec-ota_status.OTA_start.tv_usec)/1000; ESP_LOGI(TAG,"OTA progress : %d/%d (%d pct), %d KB/s", ota_status.actual_image_len, ota_status.total_image_len, ota_status.newpct, elapsed_ms>0?ota_status.actual_image_len*1000/elapsed_ms/1024:0); - triggerStatusJsonRefresh(true,ota_status.ota_type == OTA_TYPE_HTTP?"Downloading & writing update.":"Writing binary file."); + sendMessaging(MESSAGING_INFO,ota_status.ota_type == OTA_TYPE_HTTP?"Downloading & writing update.":"Writing binary file."); ota_status.lastpct=ota_status.newpct; } taskYIELD(); @@ -581,7 +570,7 @@ void ota_task(void *pvParameter) err = esp_ota_set_boot_partition(ota_partition); if (err == ESP_OK) { ESP_LOGI(TAG,"OTA Process completed successfully!"); - triggerStatusJsonRefresh(true,"Success!"); + sendMessaging(MESSAGING_INFO,"Success!"); vTaskDelay(1500/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh esp_restart(); } else { diff --git a/components/squeezelite/component.mk b/components/squeezelite/component.mk index c30f0ffa..8699201b 100644 --- a/components/squeezelite/component.mk +++ b/components/squeezelite/component.mk @@ -3,21 +3,21 @@ # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ONLY -DBYTES_PER_FRAME=4 \ - -I$(COMPONENT_PATH)/../codecs/inc \ - -I$(COMPONENT_PATH)/../codecs/inc/mad \ - -I$(COMPONENT_PATH)/../codecs/inc/alac \ - -I$(COMPONENT_PATH)/../codecs/inc/helix-aac \ - -I$(COMPONENT_PATH)/../codecs/inc/vorbis \ - -I$(COMPONENT_PATH)/../codecs/inc/soxr \ - -I$(COMPONENT_PATH)/../codecs/inc/resample16 \ - -I$(COMPONENT_PATH)/../tools \ - -I$(COMPONENT_PATH)/../codecs/inc/opus \ - -I$(COMPONENT_PATH)/../codecs/inc/opusfile \ - -I$(COMPONENT_PATH)/../driver_bt \ - -I$(COMPONENT_PATH)/../raop \ - -I$(COMPONENT_PATH)/../services + -I$(PROJECT_PATH)/components/codecs/inc \ + -I$(PROJECT_PATH)/components/codecs/inc/mad \ + -I$(PROJECT_PATH)/components/codecs/inc/alac \ + -I$(PROJECT_PATH)/components/codecs/inc/helix-aac \ + -I$(PROJECT_PATH)/components/codecs/inc/vorbis \ + -I$(PROJECT_PATH)/components/codecs/inc/soxr \ + -I$(PROJECT_PATH)/components/codecs/inc/resample16 \ + -I$(PROJECT_PATH)/components/tools \ + -I$(PROJECT_PATH)/components/codecs/inc/opus \ + -I$(PROJECT_PATH)/components/codecs/inc/opusfile \ + -I$(PROJECT_PATH)/components/driver_bt \ + -I$(PROJECT_PATH)/components/raop \ + -I$(PROJECT_PATH)/components/services -# -I$(COMPONENT_PATH)/../codecs/inc/faad2 +# -I$(PROJECT_PATH)/components/codecs/inc/faad2 COMPONENT_SRCDIRS := . tas57xx a1s external COMPONENT_ADD_INCLUDEDIRS := . ./tas57xx ./a1s diff --git a/components/telnet/CMakeLists.txt b/components/telnet/CMakeLists.txt index 36bcf9cb..16e0f045 100644 --- a/components/telnet/CMakeLists.txt +++ b/components/telnet/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRCS "telnet.c" INCLUDE_DIRS . - INCLUDE_DIRS . ../tools/ + INCLUDE_DIRS . $(PROJECT_PATH)/components/tools/ ) diff --git a/components/telnet/component.mk b/components/telnet/component.mk index 6c466cfb..2fd9a49d 100644 --- a/components/telnet/component.mk +++ b/components/telnet/component.mk @@ -10,6 +10,4 @@ COMPONENT_SRCDIRS := . COMPONENT_SRCDIRS += ./libtelnet COMPONENT_ADD_INCLUDEDIRS := . -COMPONENT_ADD_INCLUDEDIRS += ./libtelnet -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ - \ No newline at end of file +COMPONENT_PRIV_INCLUDEDIRS += ./libtelnet \ No newline at end of file diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index d3d10638..c2045cc8 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -646,12 +646,24 @@ function refreshAPHTML(data){ $( "#wifi-list" ).html(h) } - +function getMessages() { + $.getJSON("/messages.json", function(data) { + data.forEach(function(msg) { + }); + + }) + .fail(function(xhr, ajaxOptions, thrownError) { + console.log(xhr.status); + console.log(thrownError); + if (thrownError != '') showMessage(thrownError, 'ERROR'); + }); +} function checkStatus(){ RepeatCheckStatusInterval(); if (!enableStatusTimer) return; if (blockAjax) return; blockAjax = true; + getMessages(); $.getJSON( "/status.json", function( data ) { if (data.hasOwnProperty('ssid') && data['ssid'] != ""){ if (data["ssid"] === selectedSSID){ @@ -881,6 +893,7 @@ function getConfig() { }); } + function showMessage(message, severity) { if (severity == 'INFO') { $('#message').css('background', '#6af'); diff --git a/components/wifi-manager/component.mk b/components/wifi-manager/component.mk index 9b6972bb..a11cccff 100644 --- a/components/wifi-manager/component.mk +++ b/components/wifi-manager/component.mk @@ -7,13 +7,7 @@ # please read the SDK documents if you need to do this. # COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz - -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO \ - -I$(COMPONENT_PATH)/../tools COMPONENT_ADD_INCLUDEDIRS := . -COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools -COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../squeezelite-ota -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/ - +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index b7b305ea..5a095e7b 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -49,6 +49,7 @@ function to process requests, decode URLs, serve files, etc. etc. #include "sys/param.h" #include "esp_vfs.h" #include "lwip/ip_addr.h" +#include "messaging.h" #define HTTP_STACK_SIZE (5*1024) #define FREE_AND_NULL(p) if(p!=NULL){ free(p); p=NULL;} @@ -59,7 +60,7 @@ static const char TAG[] = "httpd_handlers"; /* @brief task handle for the http server */ SemaphoreHandle_t http_server_config_mutex = NULL; - +extern RingbufHandle_t messaging; #define AUTH_TOKEN_SIZE 50 typedef struct session_context { char * auth_token; @@ -1039,6 +1040,31 @@ esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){ esp_err_t redirect_ev_handler(httpd_req_t *req){ return redirect_processor(req,0); } + +esp_err_t messages_get_handler(httpd_req_t *req){ + ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + if(!is_user_authenticated(req)){ + // todo: redirect to login page + // return ESP_OK; + } + esp_err_t err = set_content_type_from_req(req); + if(err != ESP_OK){ + return err; + } + + cJSON * json_messages= messaging_retrieve_messages(messaging); + if(json_messages!=NULL){ + char * json_text= cJSON_Print(json_messages); + httpd_resp_send(req, (const char *)json_text, strlen(json_text)); + cJSON_free(json_messages); + free(json_text); + } + else { + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to retrieve messages"); + } + return ESP_OK; +} + esp_err_t status_get_handler(httpd_req_t *req){ ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); if(!is_user_authenticated(req)){ diff --git a/components/wifi-manager/http_server_handlers.h b/components/wifi-manager/http_server_handlers.h index d672933b..390394a1 100644 --- a/components/wifi-manager/http_server_handlers.h +++ b/components/wifi-manager/http_server_handlers.h @@ -92,6 +92,8 @@ esp_err_t recovery_post_handler(httpd_req_t *req); esp_err_t flash_post_handler(httpd_req_t *req); #endif esp_err_t status_get_handler(httpd_req_t *req); +esp_err_t messages_get_handler(httpd_req_t *req); + esp_err_t ap_scan_handler(httpd_req_t *req); esp_err_t redirect_ev_handler(httpd_req_t *req); esp_err_t redirect_200_ev_handler(httpd_req_t *req); diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 523352eb..2e98a7b9 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -29,11 +29,12 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "config.h" - +#include "messaging.h" static const char TAG[] = "http_server"; static httpd_handle_t _server = NULL; rest_server_context_t *rest_context = NULL; +RingbufHandle_t messaging=NULL; void register_common_handlers(httpd_handle_t server){ httpd_uri_t res_get = { .uri = "/res/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context }; @@ -52,6 +53,8 @@ void register_regular_handlers(httpd_handle_t server){ httpd_register_uri_handler(server, &config_get); httpd_uri_t status_get = { .uri = "/status.json", .method = HTTP_GET, .handler = status_get_handler, .user_ctx = rest_context }; httpd_register_uri_handler(server, &status_get); + httpd_uri_t messages_get = { .uri = "/messages.json", .method = HTTP_GET, .handler = messages_get_handler, .user_ctx = rest_context }; + httpd_register_uri_handler(server, &messages_get); httpd_uri_t config_post = { .uri = "/config.json", .method = HTTP_POST, .handler = config_post_handler, .user_ctx = rest_context }; httpd_register_uri_handler(server, &config_post); @@ -112,6 +115,7 @@ void register_regular_handlers(httpd_handle_t server){ esp_err_t http_server_start() { ESP_LOGI(TAG, "Initializing HTTP Server"); + messaging = messaging_register_subscriber(10, "http_server"); rest_context = calloc(1, sizeof(rest_server_context_t)); if(rest_context==NULL){ ESP_LOGE(TAG,"No memory for http context"); diff --git a/main/component.mk b/main/component.mk index dc5314b1..8edcf630 100644 --- a/main/component.mk +++ b/main/component.mk @@ -7,8 +7,6 @@ # please read the SDK documents if you need to do this. # CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO -DMODEL_NAME=SqueezeESP32 -COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools \ - $(COMPONENT_PATH)/../config -COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/components/tools/ LDFLAGS += -s -COMPONENT_EMBED_TXTFILES := ${PROJECT_PATH}/server_certs/github.pem \ No newline at end of file +COMPONENT_EMBED_TXTFILES := ${PROJECT_PATH}/server_certs/github.pem +COMPONENT_ADD_INCLUDEDIRS := . \ No newline at end of file From d4576bbdd43c20b12b6335f20a5169431c540fd7 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 21 Feb 2020 15:16:54 -0500 Subject: [PATCH 16/46] httpd implementation - wip --- .cproject | 232 +++++++++--------- .gitmodules | 3 + .project | 6 + .pydevproject | 5 + .settings/language.settings.xml | 8 +- .settings/org.eclipse.cdt.core.prefs | 22 +- Makefile | 8 +- components/codecs/component.mk | 2 +- components/config/config.c | 4 +- components/config/config.h | 2 +- esp-dsp => components/esp-dsp | 0 components/raop/component.mk | 2 + components/services/messaging.c | 149 ++++++++--- components/services/messaging.h | 23 +- components/services/services.c | 2 + components/squeezelite-ota/squeezelite-ota.c | 44 ++-- components/squeezelite-ota/squeezelite-ota.h | 2 - components/telnet/telnet.c | 25 +- components/wifi-manager/code.js | 1 + .../wifi-manager/http_server_handlers.c | 2 +- components/wifi-manager/wifi_manager.c | 23 +- components/wifi-manager/wifi_manager.h | 14 +- eclipse_make_wrapper.py | 112 +++++++++ main/esp_app_main.c | 4 +- main/platform_esp32.h | 19 ++ 25 files changed, 493 insertions(+), 221 deletions(-) create mode 100644 .pydevproject rename esp-dsp => components/esp-dsp (100%) create mode 100644 eclipse_make_wrapper.py diff --git a/.cproject b/.cproject index be379242..22fe7e14 100644 --- a/.cproject +++ b/.cproject @@ -203,7 +203,7 @@ - + @@ -225,57 +225,33 @@ - + - + @@ -297,21 +287,15 @@ - + - - - - - - - + - + @@ -329,47 +313,37 @@ - + - + - + - + @@ -493,6 +481,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -511,12 +559,6 @@ - - - - - - @@ -535,48 +577,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -607,12 +625,6 @@ - - - - - - diff --git a/.gitmodules b/.gitmodules index 9f498e78..cf487bdd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ [submodule "esp-dsp"] path = esp-dsp url = https://github.com/philippe44/esp-dsp +[submodule "components/esp-dsp"] + path = components/esp-dsp + url = https://github.com/philippe44/esp-dsp.git diff --git a/.project b/.project index 18d4dbf1..28fa00fd 100644 --- a/.project +++ b/.project @@ -6,6 +6,11 @@ esp-idf + + org.python.pydev.PyDevBuilder + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, @@ -24,5 +29,6 @@ org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + org.python.pydev.pythonNature diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 00000000..2b045655 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,5 @@ + + + Default + python interpreter + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 5c545a49..0f39020e 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -57,7 +57,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -81,9 +81,9 @@ - + - + diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs index 7a6fc1e3..bba7e926 100644 --- a/.settings/org.eclipse.cdt.core.prefs +++ b/.settings/org.eclipse.cdt.core.prefs @@ -24,6 +24,26 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1476804786/PATH/op environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1476804786/PATH/value=C\:/msys2/opt/xtensa-esp32-elf/bin;C\:/jdk-12.0.2/bin/server;C\:/jdk-12.0.2/bin;C\:\\Windows\\system32;C\:\\Windows;C\:\\Windows\\System32\\Wbem;C\:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C\:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;C\:\\jdk-12.0.2\\bin;C\:\\Program Files\\PuTTY\\;C\:\\Program Files (x86)\\HP\\IdrsOCR_15.2.10.1114\\;C\:\\eclipse environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1476804786/append=true environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1476804786/appendContributed=true +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/BATCH_BUILD/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/BATCH_BUILD/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/BATCH_BUILD/value=1 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/EXTRA_CPPFLAGS/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/EXTRA_CPPFLAGS/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=0 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/IDF_PATH/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/IDF_PATH/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/IDF_PATH/value=c\:/msys32/opt/esp-idf +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PATH/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PATH/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PATH/value=c\:\\msys32\\opt\\openocd-esp32\\bin;c\:\\msys32\\opt\\xtensa-esp32-elf\\bin\\;c\:\\msys32\\mingw32\\bin;C\:\\msys32\\usr\\bin;c\:\\Python27;C\:\\msys32\\usr\\bin\\vendor_perl;C\:\\msys32\\usr\\bin\\core_perl +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PROJECT_NAME/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PROJECT_NAME/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PROJECT_NAME/value=squeezelite +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PROJECT_VER/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PROJECT_VER/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/PROJECT_VER/value=custom +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/append=true +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.1876142873/appendContributed=true environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/BATCH_BUILD/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/BATCH_BUILD/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291.395881736/BATCH_BUILD/value=1 @@ -48,7 +68,7 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.16039962 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/BATCH_BUILD/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/BATCH_BUILD/value=1 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/delimiter=; -environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/operation=append environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/EXTRA_CPPFLAGS/value=-DRECOVERY_APPLICATION\=1 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/delimiter=\: environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/operation=replace diff --git a/Makefile b/Makefile index 9af345d6..1886763a 100644 --- a/Makefile +++ b/Makefile @@ -10,12 +10,12 @@ #recovery: PROJECT_NAME:=recovery.$(PROJECT_CONFIG_TARGET) -#recovery: CPPFLAGS+=-DRECOVERY_APPLICATION=1 +#recovery: EXTRA_CPPFLAGS+=-DRECOVERY_APPLICATION=1 PROJECT_NAME?=squeezelite -CPPFLAGS+= -Wno-error=maybe-uninitialized \ - -I$(PROJECT_PATH)/main -EXTRA_COMPONENT_DIRS := esp-dsp +EXTRA_CPPFLAGS+= -Wno-error=maybe-uninitialized \ + -I$(PROJECT_PATH)/main + include $(IDF_PATH)/make/project.mk # for future gcc version, this could be needed: CPPFLAGS+= -Wno-error=format-overflow -Wno-error=stringop-truncation diff --git a/components/codecs/component.mk b/components/codecs/component.mk index 99e87521..fb83f6be 100644 --- a/components/codecs/component.mk +++ b/components/codecs/component.mk @@ -21,6 +21,6 @@ COMPONENT_ADD_LDFLAGS=-l$(COMPONENT_NAME) \ #$(COMPONENT_PATH)/lib/libesp-tremor.a #$(COMPONENT_PATH)/lib/libesp-ogg-container.a - +COMPONENT_ADD_INCLUDEDIRS := /inc diff --git a/components/config/config.c b/components/config/config.c index def9c9d2..34d2839a 100644 --- a/components/config/config.c +++ b/components/config/config.c @@ -71,7 +71,7 @@ void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag); #if RECOVERY_APPLICATION==0 static void * malloc_fn(size_t sz){ - void * ptr = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM); + void * ptr = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM |MALLOC_CAP_8BIT); if(ptr==NULL){ ESP_LOGE(TAG,"malloc_fn: unable to allocate memory!"); } @@ -681,7 +681,7 @@ char * config_alloc_get_json(bool bFormatted){ config_unlock(); return json_buffer; } -esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){ +esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * value){ esp_err_t result = ESP_OK; if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){ ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT); diff --git a/components/config/config.h b/components/config/config.h index b6c192ce..70210499 100644 --- a/components/config/config.h +++ b/components/config/config.h @@ -39,6 +39,6 @@ void config_set_default(nvs_type_t type, const char *key, void * default_value, void * config_alloc_get(nvs_type_t nvs_type, const char *key) ; bool wait_for_commit(); char * config_alloc_get_json(bool bFormatted); -esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value); +esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, const void * value); nvs_type_t config_get_item_type(cJSON * entry); void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry); diff --git a/esp-dsp b/components/esp-dsp similarity index 100% rename from esp-dsp rename to components/esp-dsp diff --git a/components/raop/component.mk b/components/raop/component.mk index 55f53715..93f7da76 100644 --- a/components/raop/component.mk +++ b/components/raop/component.mk @@ -11,3 +11,5 @@ CFLAGS += -fstack-usage\ -I$(PROJECT_PATH)/components/tools \ -I$(PROJECT_PATH)/components/codecs/inc/alac \ -I$(PROJECT_PATH)/main/ +COMPONENT_ADD_INCLUDEDIRS := . +COMPONENT_SRCDIRS := . \ No newline at end of file diff --git a/components/services/messaging.c b/components/services/messaging.c index 8144b1eb..047a18a0 100644 --- a/components/services/messaging.c +++ b/components/services/messaging.c @@ -19,56 +19,107 @@ */ const static char tag[] = "messaging"; - +typedef struct { + struct messaging_list_t * next; + char * subscriber_name; + size_t max_count; + RingbufHandle_t buf_handle; +} messaging_list_t; static messaging_list_t top; + + +messaging_list_t * get_struct_ptr(messaging_handle_t handle){ + return (messaging_list_t *)handle; +} +messaging_handle_t get_handle_ptr(messaging_list_t * handle){ + return (messaging_handle_t )handle; +} RingbufHandle_t messaging_create_ring_buffer(uint8_t max_count){ RingbufHandle_t buf_handle = NULL; - StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM); + StaticRingbuffer_t *buffer_struct = malloc(sizeof(StaticRingbuffer_t)); if (buffer_struct != NULL) { size_t buf_size = (size_t )(sizeof(single_message_t)+8)*(size_t )(max_count>0?max_count:5); // no-split buffer requires an additional 8 bytes - uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM); + uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); if (buffer_storage== NULL) { - ESP_LOGE(tag,"Failed to allocate memory for messaging ring buffer !"); + ESP_LOGE(tag,"buff alloc failed"); } else { buf_handle = xRingbufferCreateStatic(buf_size, RINGBUF_TYPE_NOSPLIT, buffer_storage, buffer_struct); - if (buf_handle == NULL) { - ESP_LOGE(tag,"Failed to create messaging ring buffer !"); - } } } else { - ESP_LOGE(tag,"Failed to create ring buffer for messaging!"); + ESP_LOGE(tag,"ringbuf alloc failed"); } return buf_handle; } +void messaging_fill_messages(messaging_list_t * target_subscriber){ + single_message_t * message=NULL; + UBaseType_t uxItemsWaiting; -RingbufHandle_t messaging_register_subscriber(uint8_t max_count, char * name){ + vRingbufferGetInfo(top.buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); + for(size_t i=0;inext){ - cur = cur->next; + cur = get_struct_ptr(cur->next); } - cur->next=heap_caps_malloc(sizeof(messaging_list_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + cur->next=heap_caps_malloc(sizeof(messaging_list_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); if(!cur->next){ - ESP_LOGE(tag,"Failed to allocate messaging subscriber entry!"); + ESP_LOGE(tag,"subscriber alloc failed"); return NULL; } memset(cur->next,0x00,sizeof(messaging_list_t)); - cur = cur->next; + cur = get_struct_ptr(cur->next); + cur->max_count=max_count; + cur->subscriber_name=strdup(name); cur->buf_handle = messaging_create_ring_buffer(max_count); - strncpy(cur->subscriber_name,name,sizeof(cur->subscriber_name)); - + if(cur->buf_handle){ + messaging_fill_messages(cur); + } return cur->buf_handle; } -esp_err_t messaging_service_init(){ +void messaging_service_init(){ + size_t max_count=15; top.buf_handle = messaging_create_ring_buffer(max_count); if(!top.buf_handle){ ESP_LOGE(tag, "messaging service init failed."); } - strncpy(top.subscriber_name,"messaging"); - return (top.buf_handle!=NULL); + else { + top.max_count = max_count; + top.subscriber_name = strdup("messaging"); + } + return; } +const char * messaging_get_type_desc(messaging_types msg_type){ + switch (msg_type) { + CASE_TO_STR(MESSAGING_INFO); + CASE_TO_STR(MESSAGING_WARNING); + CASE_TO_STR(MESSAGING_ERROR); + default: + return "Unknown"; + break; + } +} +const char * messaging_get_class_desc(messaging_classes msg_class){ + switch (msg_class) { + CASE_TO_STR(MESSAGING_CLASS_OTA); + CASE_TO_STR(MESSAGING_CLASS_SYSTEM); + default: + return "Unknown"; + break; + } +} cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){ single_message_t * message=NULL; @@ -81,12 +132,13 @@ cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){ message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50)); //Check received data if (message== NULL) { - ESP_LOGE(tag,"Failed to receive message from buffer!"); + ESP_LOGE(tag,"received null ptr"); } else { json_message = cJSON_CreateObject(); cJSON_AddStringToObject(json_message, "message", message->message); - cJSON_AddStringToObject(json_message, "type", message->message); + cJSON_AddStringToObject(json_message, "type", messaging_get_type_desc(message->type)); + cJSON_AddStringToObject(json_message, "class", messaging_get_class_desc(message->msg_class)); cJSON_AddNumberToObject(json_message,"sent_time",message->sent_time); cJSON_AddNumberToObject(json_message,"current_time",esp_timer_get_time() / 1000); cJSON_AddItemToArray(json_messages,json_message); @@ -95,19 +147,55 @@ cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){ } return json_messages; } - -void messaging_release_message(RingbufHandle_t buf_handle, single_message_t * message){ - +single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle){ + single_message_t * message=NULL; + single_message_t * message_copy=NULL; + size_t item_size; + UBaseType_t uxItemsWaiting; + vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); + if(uxItemsWaiting>0){ + message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50)); + if(item_size!=sizeof(single_message_t)){ + ESP_LOGE(tag,"Invalid message length!"); + } + else { + message_copy = heap_caps_malloc(item_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if(message_copy){ + memcpy(message_copy,message,item_size); + } + } + vRingbufferReturnItem(buf_handle, (void *)message); + } + return message_copy; } -esp_err_t messageing_post_to_queue(messaging_list_t * subscriber, single_message_t * message){ - UBaseType_t res = xRingbufferSend(subscriber->buf_handle, message, sizeof(message), pdMS_TO_TICKS(1000)); + +esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_message_t * message, size_t message_size){ + UBaseType_t uxItemsWaiting=0; + size_t item_size=0; + messaging_list_t * subscriber=get_struct_ptr(subscriber_handle); + if(!subscriber->buf_handle){ + ESP_LOGE(tag,"post failed: null buffer for %s", str_or_unknown(subscriber->subscriber_name)); + return ESP_FAIL; + } + vRingbufferGetInfo(subscriber->buf_handle,NULL,NULL,NULL,NULL,&uxItemsWaiting); + if(uxItemsWaiting>=subscriber->max_count){ + ESP_LOGW(tag,"messaged dropped for %s",str_or_unknown(subscriber->subscriber_name)); + single_message_t * dummy = (single_message_t *)xRingbufferReceive(subscriber->buf_handle, &item_size, pdMS_TO_TICKS(50)); + if (dummy== NULL) { + ESP_LOGE(tag,"receive from buffer failed"); + } + else { + vRingbufferReturnItem(subscriber->buf_handle, (void *)dummy); + } + } + UBaseType_t res = xRingbufferSend(subscriber->buf_handle, message, message_size, pdMS_TO_TICKS(1000)); if (res != pdTRUE) { - ESP_LOGE(tag,"Failed to post message to subscriber %s",subscriber->subscriber_name); + ESP_LOGE(tag,"post to %s failed",str_or_unknown(subscriber->subscriber_name)); return ESP_FAIL; } return ESP_OK; } -void messaging_post_message(messaging_types type, char *fmt, ...){ +void messaging_post_message(messaging_types type,messaging_classes msg_class, char *fmt, ...){ single_message_t message={}; messaging_list_t * cur=⊤ va_list va; @@ -115,10 +203,11 @@ void messaging_post_message(messaging_types type, char *fmt, ...){ vsnprintf(message.message, sizeof(message.message), fmt, va); va_end(va); message.type = type; + message.msg_class = msg_class; message.sent_time = esp_timer_get_time() / 1000; - while(cur->next){ - messageing_post_to_queue(cur, &message); - cur = cur->next; + while(cur){ + messaging_post_to_queue(get_handle_ptr(cur), &message, sizeof(single_message_t)); + cur = get_struct_ptr(cur->next); } return; diff --git a/components/services/messaging.h b/components/services/messaging.h index 54fb5109..fb0ca0a0 100644 --- a/components/services/messaging.h +++ b/components/services/messaging.h @@ -7,19 +7,24 @@ typedef enum { MESSAGING_WARNING, MESSAGING_ERROR } messaging_types; -typedef struct { - void * next; - char subscriber_name[21]; - RingbufHandle_t buf_handle; -} messaging_list_t; +typedef enum { + MESSAGING_CLASS_OTA, + MESSAGING_CLASS_SYSTEM +} messaging_classes; + +typedef struct messaging_list_t *messaging_handle_t; typedef struct { time_t sent_time; messaging_types type; - char message[101]; + messaging_classes msg_class; + char message[151]; } single_message_t; cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle); -RingbufHandle_t messaging_register_subscriber(uint8_t max_count, char * name); - -void messaging_post_message(messaging_types type, char * fmt, ...); +messaging_handle_t messaging_register_subscriber(uint8_t max_count, char * name); +esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_message_t * message, size_t message_size); +void messaging_post_message(messaging_types type,messaging_classes msg_class, char * fmt, ...); +cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle); +single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle); +void messaging_service_init(); diff --git a/components/services/services.c b/components/services/services.c index 193a2b22..f138cd88 100644 --- a/components/services/services.c +++ b/components/services/services.c @@ -16,6 +16,7 @@ #include "monitor.h" #include "globdefs.h" #include "accessors.h" +#include "messaging.h" extern void battery_svc_init(void); extern void monitor_svc_init(void); @@ -52,6 +53,7 @@ void set_power_gpio(int gpio, char *value) { */ void services_init(void) { messaging_service_init(); + messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM, "Initializing services"); gpio_install_isr_service(0); #ifdef CONFIG_I2C_LOCKED diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 62b91d7c..37164f24 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -83,26 +83,36 @@ void _printMemStats(){ heap_caps_get_free_size(MALLOC_CAP_SPIRAM), heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); } -void sendMessaging(messaging_types type,char * fmt, ...){ - va_list args; - va_start(args, fmt); - messaging_post_message(type, fmt, args); - va_end(args); - _printMemStats(); -} -const char * ota_get_status(){ - if(!ota_status.bInitialized) - { - memset(ota_status.status_text, 0x00,sizeof(ota_status.status_text)); - ota_status.bInitialized = true; - } - return ota_status.status_text; -} uint8_t ota_get_pct_complete(){ return ota_status.total_image_len==0?0: (uint8_t)((float)ota_status.actual_image_len/(float)ota_status.total_image_len*100.0f); } +void sendMessaging(messaging_types type,const char * fmt, ...){ + va_list args; + cJSON * msg = cJSON_CreateObject(); + size_t str_len=0; + char * msg_str=NULL; + + va_start(args, fmt); + str_len = vsnprintf(NULL,0,fmt,args); + if(str_len>0){ + msg_str = malloc(str_len); + vsnprintf(msg_str,str_len,fmt,args); + } + va_end(args); + + cJSON_AddStringToObject(msg,"ota_dsc",msg_str); + free(msg_str); + cJSON_AddNumberToObject(msg,"ota_pct", ota_get_pct_complete() ); + char * json_msg = cJSON_PrintUnformatted(msg); + messaging_post_message(type, MESSAGING_CLASS_OTA, json_msg); + free(json_msg); + cJSON_free(msg); + _printMemStats(); +} + + static void __attribute__((noreturn)) task_fatal_error(void) { ESP_LOGE(TAG, "Exiting task due to fatal error..."); @@ -206,7 +216,7 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ ota_config.skip_cert_common_name_check = false; ota_config.url = strdup(ota_status.current_url); ota_config.max_redirection_count = 3; - ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); //ota_write_data = malloc(ota_config.buffer_size+1); if(ota_write_data== NULL){ ESP_LOGE(TAG,"Error allocating the ota buffer"); @@ -324,7 +334,7 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client } ESP_LOGD(TAG, "Redirection done, checking if we need to read the data. "); if (process_again(status_code)) { - char * local_buff = heap_caps_malloc(ota_config.buffer_size+1, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + char * local_buff = heap_caps_malloc(ota_config.buffer_size+1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); //char * local_buff = malloc(ota_config.buffer_size+1); if(local_buff==NULL){ ESP_LOGE(TAG,"Failed to allocate internal memory buffer for http processing"); diff --git a/components/squeezelite-ota/squeezelite-ota.h b/components/squeezelite-ota/squeezelite-ota.h index 2ae4dc43..8629404f 100644 --- a/components/squeezelite-ota/squeezelite-ota.h +++ b/components/squeezelite-ota/squeezelite-ota.h @@ -37,7 +37,5 @@ #define OTA_TASK_PRIOTITY 6 esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length); -const char * ota_get_status(); -uint8_t ota_get_pct_complete(); diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index 552c678e..3b4f900e 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -69,7 +69,7 @@ static ssize_t stdout_write(int fd, const void * data, size_t size); static char *eventToString(telnet_event_type_t type); static void handle_telnet_conn(); static void process_logs( UBaseType_t bytes); - +static bool bMirrorToUART=false; struct telnetUserData { int sockfd; telnet_t *tnHandle; @@ -79,11 +79,14 @@ struct telnetUserData { void init_telnet(){ char *val= get_nvs_value_alloc(NVS_TYPE_STR, "telnet_enable"); - if (!val || strlen(val) == 0 || !strcasestr("YX",val) ) { + if (!val || strlen(val) == 0 || !strcasestr("YXD",val) ) { ESP_LOGI(tag,"Telnet support disabled"); if(val) free(val); return; } + bMirrorToUART = strcasestr("D",val)!=NULL; + + FREE_AND_NULL(val); val=get_nvs_value_alloc(NVS_TYPE_STR, "telnet_block"); if(val){ send_chunk=atol(val); @@ -100,8 +103,8 @@ void init_telnet(){ vSemaphoreCreateBinary( xSemaphore ); // Redirect the output to our telnet handler as soon as possible - StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM); - uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM); + StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); buf_handle = xRingbufferCreateStatic(log_buf_size, RINGBUF_TYPE_BYTEBUF, buffer_storage, buffer_struct); if (buf_handle == NULL) { ESP_LOGE(tag,"Failed to create ring buffer for telnet!"); @@ -117,7 +120,9 @@ void init_telnet(){ .close = &stdout_close, .read = &stdout_read, }; - uart_fd=open("/dev/uart/0", O_RDWR); + if(bMirrorToUART){ + uart_fd=open("/dev/uart/0", O_RDWR); + } ESP_ERROR_CHECK(esp_vfs_register("/dev/pkspstdout", &vfs, NULL)); freopen("/dev/pkspstdout", "w", stdout); freopen("/dev/pkspstdout", "w", stderr); @@ -125,7 +130,7 @@ void init_telnet(){ } void start_telnet(void * pvParameter){ static bool isStarted=false; - StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); StackType_t *xStack = malloc(TELNET_STACK_SIZE); if(!isStarted && bIsEnabled) { @@ -228,7 +233,9 @@ void process_received_data(const char * buffer, size_t size){ command[size]='\0'; if(command[0]!='\r' && command[0]!='\n'){ // echo the command buffer out to uart and run - write(uart_fd, command, size); + if(bMirrorToUART){ + write(uart_fd, command, size); + } run_command((char *)command); } free(command); @@ -317,7 +324,7 @@ static void handle_telnet_conn() { struct telnetUserData *pTelnetUserData = (struct telnetUserData *)malloc(sizeof(struct telnetUserData)); tnHandle = telnet_init(my_telopts, handle_telnet_events, 0, pTelnetUserData); - pTelnetUserData->rxbuf = (char *) heap_caps_malloc(TELNET_RX_BUF, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + pTelnetUserData->rxbuf = (char *) heap_caps_malloc(TELNET_RX_BUF, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); pTelnetUserData->tnHandle = tnHandle; pTelnetUserData->sockfd = partnerSocket; @@ -374,7 +381,7 @@ static ssize_t stdout_write(int fd, const void * data, size_t size) { // We could not obtain the semaphore and can therefore not access // the shared resource safely. } - return write(uart_fd, data, size); + return bMirrorToUART?write(uart_fd, data, size):true; } static ssize_t stdout_read(int fd, void* data, size_t size) { diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index 8cf4f0d5..9228e1fe 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -648,6 +648,7 @@ function refreshAPHTML(data){ function getMessages() { $.getJSON("/messages.json", function(data) { data.forEach(function(msg) { + message: "{"ota_dsc":"Erasing flash complete","ota_pct":0}" }); }) diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 25e9279f..b983cf47 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -50,9 +50,9 @@ function to process requests, decode URLs, serve files, etc. etc. #include "esp_vfs.h" #include "lwip/ip_addr.h" #include "messaging.h" +#include "platform_esp32.h" #define HTTP_STACK_SIZE (5*1024) -#define FREE_AND_NULL(p) if(p!=NULL){ free(p); p=NULL;} const char str_na[]="N/A"; #define STR_OR_NA(s) s?s:str_na /* @brief tag used for ESP serial console messages */ diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c index 4fabda05..084ff142 100644 --- a/components/wifi-manager/wifi_manager.c +++ b/components/wifi-manager/wifi_manager.c @@ -75,7 +75,7 @@ Contains the freeRTOS task and all necessary support #endif #define STR_OR_BLANK(p) p==NULL?"":p -#define FREE_AND_NULL(p) if(p!=NULL){ free(p); p=NULL;} + /* objects used to manipulate the main queue of events */ QueueHandle_t wifi_manager_queue; SemaphoreHandle_t wifi_manager_json_mutex = NULL; @@ -89,7 +89,7 @@ char *ip_info_json = NULL; char * release_url=NULL; cJSON * ip_info_cjson=NULL; wifi_config_t* wifi_manager_config_sta = NULL; -static update_reason_code_t last_update_reason_code=0; + static int32_t total_connected_time=0; static int64_t last_connected=0; @@ -208,9 +208,6 @@ bool isGroupBitSet(uint8_t bit){ EventBits_t uxBits= xEventGroupGetBits(wifi_manager_event_group); return (uxBits & bit); } -void wifi_manager_refresh_ota_json(){ - wifi_manager_send_message(EVENT_REFRESH_OTA, NULL); -} void wifi_manager_scan_async(){ wifi_manager_send_message(ORDER_START_WIFI_SCAN, NULL); @@ -455,8 +452,6 @@ cJSON * wifi_manager_get_basic_info(cJSON **old){ cJSON_AddItemToObject(root, "version", cJSON_CreateString(desc->version)); if(release_url !=NULL) cJSON_AddItemToObject(root, "release_url", cJSON_CreateString(release_url)); cJSON_AddNumberToObject(root,"recovery", RECOVERY_APPLICATION ); - cJSON_AddItemToObject(root, "ota_dsc", cJSON_CreateString(ota_get_status())); - cJSON_AddNumberToObject(root,"ota_pct", ota_get_pct_complete() ); cJSON_AddItemToObject(root, "Jack", cJSON_CreateString(jack_inserted_svc() ? "1" : "0")); cJSON_AddNumberToObject(root,"Voltage", battery_value_svc()); cJSON_AddNumberToObject(root,"disconnect_count", num_disconnect ); @@ -485,12 +480,6 @@ void wifi_manager_generate_ip_info_json(update_reason_code_t update_reason_code) wifi_config_t *config = wifi_manager_get_wifi_sta_config(); ip_info_cjson = wifi_manager_get_basic_info(&ip_info_cjson); - if(update_reason_code == UPDATE_OTA) { - update_reason_code = last_update_reason_code; - } - else { - last_update_reason_code = update_reason_code; - } cJSON_AddNumberToObject(ip_info_cjson, "urc", update_reason_code); if(config){ cJSON_AddItemToObject(ip_info_cjson, "ssid", cJSON_CreateString((char *)config->sta.ssid)); @@ -1144,12 +1133,6 @@ void wifi_manager( void * pvParameters ){ ESP_LOGD(TAG, "Done Invoking SCAN DONE callback"); } break; - case EVENT_REFRESH_OTA: - if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ - wifi_manager_generate_ip_info_json( UPDATE_OTA ); - wifi_manager_unlock_json_buffer(); - } - break; case ORDER_START_WIFI_SCAN: ESP_LOGD(TAG, "MESSAGE: ORDER_START_WIFI_SCAN"); @@ -1445,7 +1428,7 @@ void wifi_manager( void * pvParameters ){ if(cb_ptr_arr[msg.code]) (*cb_ptr_arr[msg.code])(NULL); break; case UPDATE_CONNECTION_OK: - /* refresh JSON with the new ota data */ + /* refresh JSON */ if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ /* generate the connection info with success */ wifi_manager_generate_ip_info_json( UPDATE_CONNECTION_OK ); diff --git a/components/wifi-manager/wifi_manager.h b/components/wifi-manager/wifi_manager.h index 459a48c2..9aa12da6 100644 --- a/components/wifi-manager/wifi_manager.h +++ b/components/wifi-manager/wifi_manager.h @@ -198,12 +198,11 @@ typedef enum message_code_t { EVENT_STA_DISCONNECTED = 12, EVENT_SCAN_DONE = 13, EVENT_STA_GOT_IP = 14, - EVENT_REFRESH_OTA = 15, - ORDER_RESTART_OTA = 16, - ORDER_RESTART_RECOVERY = 17, - ORDER_RESTART_OTA_URL = 18, - ORDER_RESTART = 19, - MESSAGE_CODE_COUNT = 20 /* important for the callback array */ + ORDER_RESTART_OTA = 15, + ORDER_RESTART_RECOVERY = 16, + ORDER_RESTART_OTA_URL = 17, + ORDER_RESTART = 18, + MESSAGE_CODE_COUNT = 19 /* important for the callback array */ }message_code_t; @@ -226,8 +225,7 @@ typedef enum update_reason_code_t { UPDATE_CONNECTION_OK = 0, UPDATE_FAILED_ATTEMPT = 1, UPDATE_USER_DISCONNECT = 2, - UPDATE_LOST_CONNECTION = 3, - UPDATE_OTA=4 + UPDATE_LOST_CONNECTION = 3 }update_reason_code_t; typedef enum connection_request_made_by_code_t{ diff --git a/eclipse_make_wrapper.py b/eclipse_make_wrapper.py new file mode 100644 index 00000000..f18048e8 --- /dev/null +++ b/eclipse_make_wrapper.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# +# Wrapper to run make and preprocess any paths in the output from MSYS Unix-style paths +# to Windows paths, for Eclipse +from __future__ import print_function, division +import sys +import subprocess +import os.path +import os +import re +import glob +from test import test_cmd_line + +#UNIX_PATH_RE = re.compile(r'(([a-zA-Z]{1}[:]{1}){0,1}[/\\][^\s\'\"\t\[\(]+)+') +UNIX_PATH_RE = re.compile(r'(([a-zA-Z]{1}[:]{1}){0,1}[/\\][^\s\'\"\t\[\(]+(?![^\\/]*$)[/\\]?)') +INCLUDE_PATH_RE = re.compile(r'-I[\s"]{0,}(.+?)["]{0,}(?=\s-\S)') +INCLUDE_PATH_ADJ_RE = re.compile(r'^([/]opt[/]esp-idf[/]){1}(.*)') +INCLUDE_PATH_ADJ2_RE = re.compile(r'^([/]c[/]){1}(.*)') + +paths = {} +names = [] +idf_path= os.environ.get('IDF_PATH').replace("/", "\\") +cwd_path= os.environ.get('CWD') +pwd_path= os.environ.get('PWD') + +def check_path(path): + try: + return paths[path] + except KeyError: + pass + paths[path] = path + winpath =path + if not os.path.exists(winpath): + # cache as failed, replace with success if it works + if re.match(INCLUDE_PATH_ADJ2_RE, path) is not None: + winpath = INCLUDE_PATH_ADJ2_RE.sub(r'c:/\2',path) #replace /c/ + try: + winpath = subprocess.check_output(["cygpath", "-w", winpath]).strip() + except subprocess.CalledProcessError: + return path # something went wrong running cygpath, assume this is not a path! + if not os.path.exists(winpath): + if not os.path.exists(winpath): + winpath=idf_path + '\\' + re.sub(r'^[/\\]opt[/\\](esp-idf[/\\]){0,}', '', path, 1) + try: + winpath = subprocess.check_output(["cygpath", "-w", winpath]).strip() + except subprocess.CalledProcessError: + return path # something went wrong running cygpath, assume this is not a path! + if not os.path.exists(winpath): + return path # not actually a valid path + + winpath = winpath.replace("/", "\\") # make consistent with forward-slashes used elsewhere + paths[path] = winpath + + + #print("In path: {0}, out path: {1}".format(path,winpath) ) + return winpath +def fix_paths(filename): + if re.match(r'.*[\\](.*$)',filename) is not None: + filename = re.findall(r'.*[\\](.*$)',filename)[0].replace("\\", "/") + + return filename.rstrip() + +def print_paths(path_list, file_name, source_file): + + new_path_list = list(set(path_list)) + new_path_list.sort() + last_n = '' + cmd_line='xtensa-esp32-elf-gcc ' + for n in new_path_list: + if re.match(INCLUDE_PATH_ADJ_RE, n) is not None: + n = INCLUDE_PATH_ADJ_RE.sub(idf_path+r"\2",n ) + if re.match(INCLUDE_PATH_ADJ2_RE, n) is not None: + n = INCLUDE_PATH_ADJ2_RE.sub(r'c:/\2',n) + if last_n != n: + cmd_line = cmd_line + ' -I ' + n.rstrip() + last_n = n + if source_file: + cmd_line = cmd_line + ' -c ' + fix_paths(source_file) + cmd_line = cmd_line + ' -o ' + fix_paths(file_name) + print(cmd_line) +def extract_includes(): + + for filename in [y for x in os.walk('build') for y in glob.glob(os.path.join(x[0], '*.d'))]: + lines = [] + source='' + with open(filename) as file_in: + for line in file_in: + if re.match(r'\S*(?=/[^/]*\.[h][p]?)',line) is not None: + lines.extend(re.findall(r'\S*(?=/[^/]*\.[h][p]?)/',line)) + if re.match(r'\S*(?=\.[cC][pP]{0,})[^\\\s]*',line) is not None: + source = re.findall(r'\S*(?=\.[cC][pP]{0,})[^\\\s]*',line)[0] + + print_paths(lines,filename,source ) + +def main(): + cwd_path=check_path(os.getcwd()) + os.environ['CWD']= cwd_path + os.environ['PWD']= cwd_path + idf_path= os.environ.get('IDF_PATH').replace("/", "\\") + cwd_path= os.environ.get('CWD') + pwd_path= os.environ.get('PWD') + print('Running custom script make in {}, IDF_PATH={}, CWD={}, PWD={}'.format(cwd_path,idf_path,cwd_path,pwd_path)) + + make = subprocess.Popen(["make"] + sys.argv[1:] + ["BATCH_BUILD=1"], stdout=subprocess.PIPE) + for line in iter(make.stdout.readline, ''): + line = re.sub(UNIX_PATH_RE, lambda m: check_path(m.group(0)), line) + names.extend(INCLUDE_PATH_RE.findall(line)) + print(line.rstrip()) + sys.exit(make.wait()) + +if __name__ == "__main__": + main() diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 3d2f35cb..b9db45bb 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -51,7 +51,7 @@ static const char certs_namespace[] = "certificates"; static const char certs_key[] = "blob"; static const char certs_version[] = "version"; - +const char unknown_string_placeholder[] = "unknown"; EventGroupHandle_t wifi_event_group; bool bypass_wifi_manager=false; @@ -69,7 +69,7 @@ extern const uint8_t server_cert_pem_end[] asm("_binary_github_pem_end"); // as an exception _init function don't need include extern void services_init(void); extern void display_init(char *welcome); - +const char * str_or_unknown(const char * str) { return (str?str:unknown_string_placeholder); } /* brief this is an exemple of a callback that you can setup in your own app to get notified of wifi manager event */ void cb_connection_got_ip(void *pvParameter){ ESP_LOGI(TAG, "I have a connection!"); diff --git a/main/platform_esp32.h b/main/platform_esp32.h index 0291154c..545086a0 100644 --- a/main/platform_esp32.h +++ b/main/platform_esp32.h @@ -37,3 +37,22 @@ typedef enum { ERROR } message_severity_t; extern void set_status_message(message_severity_t severity, const char * message); +#ifndef STR_OR_ALT +#define STR_OR_ALT(str,alt) (str?str:alt) +#endif + +extern const char unknown_string_placeholder[]; +extern const char * str_or_unknown(const char * str); + +#ifndef FREE_AND_NULL +#define FREE_AND_NULL(x) if(x) { free(x); x=NULL; } +#endif +#ifndef QUOTE +#define QUOTE(name) #name +#endif +#ifndef STR +#define STR(macro) QUOTE(macro) +#endif +#ifndef CASE_TO_STR +#define CASE_TO_STR(x) case x: return STR(x); break; +#endif From 168c15ce02cb6d61c6bfb0cc04360d317e0daa17 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 21 Feb 2020 17:16:48 -0500 Subject: [PATCH 17/46] httpd alpha version - release --- components/esp-dsp | 2 +- components/services/messaging.c | 4 +- components/wifi-manager/code.js | 108 ++++++++++++++++------------- components/wifi-manager/index.html | 2 +- 4 files changed, 64 insertions(+), 52 deletions(-) diff --git a/components/esp-dsp b/components/esp-dsp index de39220f..8b082c10 160000 --- a/components/esp-dsp +++ b/components/esp-dsp @@ -1 +1 @@ -Subproject commit de39220fb482eeaee4db5707358bf6b97b34fe59 +Subproject commit 8b082c1071497d49346ee6ed55351470c1cb4264 diff --git a/components/services/messaging.c b/components/services/messaging.c index 047a18a0..1f4ef6af 100644 --- a/components/services/messaging.c +++ b/components/services/messaging.c @@ -128,7 +128,7 @@ cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){ size_t item_size; UBaseType_t uxItemsWaiting; vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); - if(uxItemsWaiting>0){ + for(int i = 0;ibuf_handle,NULL,NULL,NULL,NULL,&uxItemsWaiting); if(uxItemsWaiting>=subscriber->max_count){ - ESP_LOGW(tag,"messaged dropped for %s",str_or_unknown(subscriber->subscriber_name)); + ESP_LOGD(tag,"messaged dropped for %s",str_or_unknown(subscriber->subscriber_name)); single_message_t * dummy = (single_message_t *)xRingbufferReceive(subscriber->buf_handle, &item_size, pdMS_TO_TICKS(50)); if (dummy== NULL) { ESP_LOGE(tag,"receive from buffer failed"); diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index 9228e1fe..55fcb8e0 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -211,7 +211,7 @@ $(document).ready(function(){ } - showMessage('please wait for the ESP32 to reboot', 'WARNING'); + showMessage('please wait for the ESP32 to reboot', 'MESSAGING_WARNING'); $.ajax({ url: '/config.json', dataType: 'text', @@ -224,7 +224,7 @@ $(document).ready(function(){ error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); }, complete: function(response) { //var returnedResponse = JSON.parse(response.responseText); @@ -241,7 +241,7 @@ $(document).ready(function(){ error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); }, complete: function(response) { console.log('reboot call completed'); @@ -273,7 +273,7 @@ $(document).ready(function(){ error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); } }); console.log('sent config JSON with headers:', autoexec1); @@ -306,7 +306,7 @@ $(document).ready(function(){ error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); } }); console.log('sent config JSON with headers:', JSON.stringify(headers)); @@ -361,7 +361,7 @@ $(document).ready(function(){ error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); } }); console.log('sent config JSON with headers:', JSON.stringify(headers)); @@ -378,11 +378,11 @@ $(document).ready(function(){ xhttp.onreadystatechange = function() { if (xhttp.readyState == 4) { if (xhttp.status == 200) { - showMessage(xhttp.responseText, 'INFO') + showMessage(xhttp.responseText, 'MESSAGING_INFO') } else if (xhttp.status == 0) { - showMessage("Upload connection was closed abruptly!", 'ERROR'); + showMessage("Upload connection was closed abruptly!", 'MESSAGING_ERROR'); } else { - showMessage(xhttp.status + " Error!\n" + xhttp.responseText, 'ERROR'); + showMessage(xhttp.status + " Error!\n" + xhttp.responseText, 'MESSAGING_ERROR'); } } }; @@ -414,7 +414,7 @@ $(document).ready(function(){ error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); } }); enableStatusTimer = true; @@ -597,7 +597,7 @@ function performConnect(conntype){ error: function (xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); } }); @@ -645,18 +645,44 @@ function refreshAPHTML(data){ $( "#wifi-list" ).html(h) } + function getMessages() { - $.getJSON("/messages.json", function(data) { - data.forEach(function(msg) { - message: "{"ota_dsc":"Erasing flash complete","ota_pct":0}" - }); - - }) - .fail(function(xhr, ajaxOptions, thrownError) { - console.log(xhr.status); - console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); - }); + $.getJSON("/messages.json", function(data) { + data.forEach(function(msg) { + var msg_age = msg["current_time"] - msg["sent_time"]; + switch (msg["class"]) { + case "MESSAGING_CLASS_OTA": + //message: "{"ota_dsc":"Erasing flash complete","ota_pct":0}" + var ota_data = JSON.parse(msg["message"]); + if (ota_data.hasOwnProperty('ota_pct') && ota_data['ota_pct'] != 0){ + otapct = ota_data['ota_pct']; + $('.progress-bar').css('width', otapct+'%').attr('aria-valuenow', otapct); + $('.progress-bar').html(otapct+'%'); + } + if (ota_data.hasOwnProperty('ota_dsc') && ota_data['ota_dsc'] != ''){ + otadsc = ota_data['ota_dsc']; + $("span#flash-status").html(otadsc); + if (otadsc.match(/Error:/) || otapct > 95) { + blockFlashButton = false; + enableStatusTimer = true; + } + } + break; + case "MESSAGING_CLASS_SYSTEM": + showMessage(msg["message"], msg["type"],msg_age); + lastMsg = msg; + break; + default: + break; + } + }); + + }) + .fail(function(xhr, ajaxOptions, thrownError) { + console.log(xhr.status); + console.log(thrownError); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); + }); } function checkStatus(){ RepeatCheckStatusInterval(); @@ -780,29 +806,10 @@ function checkStatus(){ ver = data['version']; $("span#foot-fw").html("fw: "+ver+", mode: "+pname+""); } - if (data.hasOwnProperty('ota_pct') && data['ota_pct'] != 0){ - otapct = data['ota_pct']; - $('.progress-bar').css('width', otapct+'%').attr('aria-valuenow', otapct); - $('.progress-bar').html(otapct+'%'); - } - if (data.hasOwnProperty('ota_dsc') && data['ota_dsc'] != ''){ - otadsc = data['ota_dsc']; - $("span#flash-status").html(otadsc); - if (otadsc.match(/Error:/) || otapct > 95) { - blockFlashButton = false; - enableStatusTimer = true; - } - } else { + else { $("span#flash-status").html(''); } - if (data.hasOwnProperty('message') && data['message'] != ''){ - var msg = data['message'].text; - var severity = data['message'].severity; - if (msg != lastMsg) { - showMessage(msg, severity); - lastMsg = msg; - } - } + if (data.hasOwnProperty('Voltage')) { var voltage = data['Voltage']; var layer; @@ -832,7 +839,7 @@ function checkStatus(){ .fail(function(xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); blockAjax = false; }); } @@ -888,20 +895,25 @@ function getConfig() { .fail(function(xhr, ajaxOptions, thrownError) { console.log(xhr.status); console.log(thrownError); - if (thrownError != '') showMessage(thrownError, 'ERROR'); + if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); blockAjax = false; }); } -function showMessage(message, severity) { - if (severity == 'INFO') { +function showMessage(message, severity, age=0) { + + if (severity == 'MESSAGING_INFO') { $('#message').css('background', '#6af'); - } else if (severity == 'WARNING') { + } else if (severity == 'MESSAGING_WARNING') { $('#message').css('background', '#ff0'); + } else if (severity == 'MESSAGING_ERROR' ) { + $('#message').css('background', '#f00'); } else { $('#message').css('background', '#f00'); } + + $('#message').html(message); $("#content").fadeTo("slow", 0.3, function() { $("#message").show(500).delay(5000).hide(500, function() { diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index 3f7b67e1..154376f8 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -17,7 +17,7 @@ - + esp32-wifi-manager From 34459f54ef45f35c26cb717e8d83860ba76c50c8 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 21 Feb 2020 17:26:14 -0500 Subject: [PATCH 18/46] increase ota message buffer size by a byte - release --- components/squeezelite-ota/squeezelite-ota.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 37164f24..2cfdac7a 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -95,7 +95,7 @@ void sendMessaging(messaging_types type,const char * fmt, ...){ char * msg_str=NULL; va_start(args, fmt); - str_len = vsnprintf(NULL,0,fmt,args); + str_len = vsnprintf(NULL,0,fmt,args)+1; if(str_len>0){ msg_str = malloc(str_len); vsnprintf(msg_str,str_len,fmt,args); From d881a0ae25c128a915521edad4be94aaeedefe92 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 21 Feb 2020 17:36:13 -0500 Subject: [PATCH 19/46] trigger build - release --- components/wifi-manager/http_server_handlers.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index b983cf47..fb30eb57 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -1108,7 +1108,3 @@ esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){ return err; } - - - - From e3ea0c81405eefe7fb6d35156f97d2c6860185e6 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 21 Feb 2020 17:37:28 -0500 Subject: [PATCH 20/46] trigger build - release --- components/wifi-manager/http_server_handlers.c | 1 - 1 file changed, 1 deletion(-) diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index fb30eb57..6599f996 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -1105,6 +1105,5 @@ esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){ err = redirect_processor(req,error); } - return err; } From b70373ea31cbc187d425728b601bb2a30f51b88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien?= Date: Fri, 21 Feb 2020 17:51:28 -0500 Subject: [PATCH 21/46] Fix esp-dsp - release --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index cf487bdd..17261bba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,9 +2,6 @@ path = components/telnet/libtelnet url = https://github.com/seanmiddleditch/libtelnet branch = develop -[submodule "esp-dsp"] - path = esp-dsp - url = https://github.com/philippe44/esp-dsp [submodule "components/esp-dsp"] path = components/esp-dsp url = https://github.com/philippe44/esp-dsp.git From e19c9e12dcf0adaa57b0830300c477e7e7f97e98 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Mon, 24 Feb 2020 16:14:17 -0500 Subject: [PATCH 22/46] memory leak fixed --- Makefile | 5 +- components/cmd_system/cmd_system.c | 12 +-- components/services/messaging.c | 3 +- components/squeezelite-ota/squeezelite-ota.c | 74 ++++++++++--------- components/telnet/telnet.c | 5 +- components/tools/trace.h | 15 ++++ components/wifi-manager/component.mk | 2 +- .../wifi-manager/http_server_handlers.c | 22 +++++- components/wifi-manager/wifi_manager.c | 16 +--- .../wifi-manager/wifi_manager_http_server.c | 2 +- main/platform_esp32.h | 24 ------ 11 files changed, 92 insertions(+), 88 deletions(-) diff --git a/Makefile b/Makefile index 1886763a..9639bad0 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,8 @@ #recovery: EXTRA_CPPFLAGS+=-DRECOVERY_APPLICATION=1 PROJECT_NAME?=squeezelite -EXTRA_CPPFLAGS+= -Wno-error=maybe-uninitialized \ - -I$(PROJECT_PATH)/main - +EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main +#/-Wno-error=maybe-uninitialized include $(IDF_PATH)/make/project.mk # for future gcc version, this could be needed: CPPFLAGS+= -Wno-error=format-overflow -Wno-error=stringop-truncation diff --git a/components/cmd_system/cmd_system.c b/components/cmd_system/cmd_system.c index 02f6e0ad..dd452e41 100644 --- a/components/cmd_system/cmd_system.c +++ b/components/cmd_system/cmd_system.c @@ -28,7 +28,8 @@ #include "platform_esp32.h" #include "config.h" #include "esp_sleep.h" -#include "driver/uart.h" // for the uart driver access +#include "driver/uart.h" +#include "messaging.h" #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS #define WITH_TASKS_INFO 1 @@ -130,7 +131,7 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) if(it == NULL){ ESP_LOGE(TAG,"Unable initialize partition iterator!"); - set_status_message(ERROR, "Reboot failed. Cannot iterate through partitions"); + messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Reboot failed. Cannot iterate through partitions"); } else { @@ -144,18 +145,19 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) if(err!=ESP_OK){ ESP_LOGE(TAG,"Unable to set partition as active for next boot. %s",esp_err_to_name(err)); bFound=false; - set_status_message(ERROR, "Unable to select partition for reboot."); + messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Unable to select partition for reboot."); } else{ ESP_LOGW(TAG, "Application partition %s sub type %u is selected for boot", partition->label,partition_subtype); bFound=true; - set_status_message(WARNING, "Rebooting!"); + messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"Reboot failed. Cannot iterate through partitions"); } } else { ESP_LOGE(TAG,"partition type %u not found! Unable to reboot to recovery.",partition_subtype); - set_status_message(ERROR, "Partition not found."); + messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"partition type %u not found! Unable to reboot to recovery.",partition_subtype); + } ESP_LOGD(TAG, "Yielding to other processes"); taskYIELD(); diff --git a/components/services/messaging.c b/components/services/messaging.c index 1f4ef6af..f8841baa 100644 --- a/components/services/messaging.c +++ b/components/services/messaging.c @@ -14,6 +14,7 @@ #include "nvs_utilities.h" #include "platform_esp32.h" #include "messaging.h" +#include "trace.h" /************************************ * Globals */ @@ -137,12 +138,12 @@ cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle){ else { json_message = cJSON_CreateObject(); cJSON_AddStringToObject(json_message, "message", message->message); + vRingbufferReturnItem(buf_handle, (void *)message); cJSON_AddStringToObject(json_message, "type", messaging_get_type_desc(message->type)); cJSON_AddStringToObject(json_message, "class", messaging_get_class_desc(message->msg_class)); cJSON_AddNumberToObject(json_message,"sent_time",message->sent_time); cJSON_AddNumberToObject(json_message,"current_time",esp_timer_get_time() / 1000); cJSON_AddItemToArray(json_messages,json_message); - vRingbufferReturnItem(buf_handle, (void *)message); } } return json_messages; diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 2cfdac7a..5110baae 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -29,8 +29,9 @@ #include "esp_spi_flash.h" #include "sdkconfig.h" #include "messaging.h" - +#include "trace.h" #include "esp_ota_ops.h" + extern const char * get_certificate(); #ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 @@ -57,16 +58,12 @@ typedef enum { OTA_TYPE_INVALID } ota_type_t; static struct { - char status_text[81]; uint32_t actual_image_len; uint32_t total_image_len; uint32_t remain_image_len; - char * redirected_url; - char * current_url; ota_type_t ota_type; char * bin; bool bOTAStarted; - bool bInitialized; uint8_t lastpct; uint8_t newpct; struct timeval OTA_start; @@ -99,10 +96,22 @@ void sendMessaging(messaging_types type,const char * fmt, ...){ if(str_len>0){ msg_str = malloc(str_len); vsnprintf(msg_str,str_len,fmt,args); + if(type == MESSAGING_WARNING){ + ESP_LOGW(TAG,"%s",msg_str); + } + else if (type == MESSAGING_ERROR){ + ESP_LOGE(TAG,"%s",msg_str); + } + else + ESP_LOGI(TAG,"%s",msg_str); + } + else { + ESP_LOGW(TAG, "Sending empty string message"); } va_end(args); - cJSON_AddStringToObject(msg,"ota_dsc",msg_str); + + cJSON_AddStringToObject(msg,"ota_dsc",str_or_unknown(msg_str)); free(msg_str); cJSON_AddNumberToObject(msg,"ota_pct", ota_get_pct_complete() ); char * json_msg = cJSON_PrintUnformatted(msg); @@ -150,7 +159,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) case HTTP_EVENT_ON_CONNECTED: ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); - if(ota_status.bOTAStarted) sendMessaging(MESSAGING_INFO,"Installing..."); + if(ota_status.bOTAStarted) sendMessaging(MESSAGING_INFO,"Connecting to URL..."); ota_status.total_image_len=0; ota_status.actual_image_len=0; ota_status.lastpct=0; @@ -165,9 +174,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) case HTTP_EVENT_ON_HEADER: ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s",evt->header_key, evt->header_value); if (strcasecmp(evt->header_key, "location") == 0) { - FREE_RESET(ota_status.redirected_url); - ota_status.redirected_url=strdup(evt->header_value); - ESP_LOGW(TAG,"OTA will redirect to url: %s",ota_status.redirected_url); + ESP_LOGW(TAG,"OTA will redirect to url: %s",evt->header_value); } if (strcasecmp(evt->header_key, "content-length") == 0) { ota_status.total_image_len = atol(evt->header_value); @@ -191,7 +198,6 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ memset(&ota_config, 0x00, sizeof(ota_config)); - ota_status.bInitialized = true; sendMessaging(MESSAGING_INFO,"Initializing..."); ota_status.ota_type= OTA_TYPE_INVALID; if(p_ota_thread_parms->url !=NULL && strlen(p_ota_thread_parms->url)>0 ){ @@ -208,14 +214,14 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ switch (ota_status.ota_type) { case OTA_TYPE_HTTP: - ota_status.current_url= p_ota_thread_parms->url; ota_config.cert_pem =get_certificate(); ota_config.event_handler = _http_event_handler; ota_config.buffer_size = BUFFSIZE; - ota_config.disable_auto_redirect=false; + ota_config.disable_auto_redirect=true; ota_config.skip_cert_common_name_check = false; - ota_config.url = strdup(ota_status.current_url); + ota_config.url = strdup(p_ota_thread_parms->url); ota_config.max_redirection_count = 3; + ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); //ota_write_data = malloc(ota_config.buffer_size+1); if(ota_write_data== NULL){ @@ -295,14 +301,14 @@ esp_err_t _erase_last_boot_app_partition(esp_partition_t *ota_partition) if(i%2) { sendMessaging(MESSAGING_INFO,"Erasing flash (%u/%u)",i,num_passes); } - vTaskDelay(200/ portTICK_PERIOD_MS); // wait here for a short amount of time. This will help with reducing WDT errors + //vTaskDelay(200/ portTICK_PERIOD_MS); // wait here for a short amount of time. This will help with reducing WDT errors } if(remain_size>0){ err=esp_partition_erase_range(ota_partition, ota_partition->size-remain_size, remain_size); if(err!=ESP_OK) return err; } sendMessaging(MESSAGING_INFO,"Erasing flash complete."); - taskYIELD(); + return ESP_OK; } @@ -321,28 +327,32 @@ static bool process_again(int status_code) static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client, int status_code) { esp_err_t err=ESP_OK; - if (status_code == HttpStatus_MovedPermanently || status_code == HttpStatus_Found) { + if (status_code == HttpStatus_MovedPermanently || status_code == HttpStatus_Found ) { ESP_LOGW(TAG, "Handling HTTP redirection. "); err = esp_http_client_set_redirection(http_client); if (err != ESP_OK) { ESP_LOGE(TAG, "URL redirection Failed. %s", esp_err_to_name(err)); return err; } + ESP_LOGW(TAG, "Done Handling HTTP redirection. "); + } else if (status_code == HttpStatus_Unauthorized) { ESP_LOGW(TAG, "Handling Unauthorized. "); esp_http_client_add_auth(http_client); } ESP_LOGD(TAG, "Redirection done, checking if we need to read the data. "); if (process_again(status_code)) { - char * local_buff = heap_caps_malloc(ota_config.buffer_size+1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + ESP_LOGD(TAG, "We have to read some more data. Allocating buffer size %u",ota_config.buffer_size+1); + char local_buff_var[501]={}; + //char * local_buff = heap_caps_malloc(ota_config.buffer_size+1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); //char * local_buff = malloc(ota_config.buffer_size+1); - if(local_buff==NULL){ - ESP_LOGE(TAG,"Failed to allocate internal memory buffer for http processing"); - return ESP_ERR_NO_MEM; - } +// if(local_buff==NULL){ +// ESP_LOGE(TAG,"Failed to allocate internal memory buffer for http processing"); +// return ESP_ERR_NO_MEM; +// } while (1) { - ESP_LOGD(TAG, "Reading data chunk. "); - int data_read = esp_http_client_read(http_client, local_buff, ota_config.buffer_size); + ESP_LOGD(TAG, "Buffer successfully allocated. Reading data chunk. "); + int data_read = esp_http_client_read(http_client, local_buff_var, sizeof(local_buff_var)); if (data_read < 0) { ESP_LOGE(TAG, "Error: SSL data read error"); err= ESP_FAIL; @@ -353,7 +363,7 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client break; } } - FREE_RESET(local_buff); + //FREE_RESET(local_buff); } return err; @@ -379,8 +389,6 @@ static esp_err_t _http_connect(esp_http_client_handle_t http_client) status_code = esp_http_client_get_status_code(http_client); ESP_LOGD(TAG, "HTTP status code was %d",status_code); - - err = _http_handle_response_code(http_client, status_code); if (err != ESP_OK) { return err; @@ -395,11 +403,7 @@ void ota_task_cleanup(const char * message, ...){ va_start(args, message); sendMessaging(MESSAGING_ERROR,message, args); va_end(args); - ESP_LOGE(TAG, "%s",ota_status.status_text); } - - FREE_RESET(ota_status.redirected_url); - FREE_RESET(ota_status.current_url); FREE_RESET(ota_status.bin); FREE_RESET(ota_write_data); if(ota_http_client!=NULL) { @@ -603,7 +607,7 @@ esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t if(bin_url){ ota_thread_parms.url =strdup(bin_url); - ESP_LOGI(TAG, "Starting ota on core %u for : %s", OTA_CORE,bin_url); + ESP_LOGI(TAG, "Starting ota on core %u for : %s", OTA_CORE,ota_thread_parms.url); } else { ota_thread_parms.bin = bin_buffer; @@ -614,8 +618,7 @@ esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t char * num_buffer=config_alloc_get(NVS_TYPE_STR, "ota_stack"); if(num_buffer!=NULL) { stack_size= atol(num_buffer); - free(num_buffer); - num_buffer=NULL; + FREE_AND_NULL(num_buffer); } else { ESP_LOGW(TAG,"OTA stack size config not found"); @@ -624,8 +627,7 @@ esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t num_buffer=config_alloc_get(NVS_TYPE_STR, "ota_prio"); if(num_buffer!=NULL) { task_priority= atol(num_buffer); - free(num_buffer); - num_buffer=NULL; + FREE_AND_NULL(num_buffer); } else { ESP_LOGW(TAG,"OTA task priority not found"); diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index 3b4f900e..cd9bfadb 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -38,7 +38,7 @@ #include "config.h" #include "nvs_utilities.h" #include "platform_esp32.h" - +#include "trace.h" /************************************ * Globals @@ -148,12 +148,14 @@ static void telnet_task(void *data) { int rc = bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); if (rc < 0) { ESP_LOGE(tag, "bind: %d (%s)", errno, strerror(errno)); + close(serverSocket); return; } rc = listen(serverSocket, 5); if (rc < 0) { ESP_LOGE(tag, "listen: %d (%s)", errno, strerror(errno)); + close(serverSocket); return; } @@ -171,6 +173,7 @@ static void telnet_task(void *data) { ESP_LOGD(tag, "Telnet connection terminated"); } } + close(serverSocket); vTaskDelete(NULL); } diff --git a/components/tools/trace.h b/components/tools/trace.h index ae24c70a..82c20434 100644 --- a/components/tools/trace.h +++ b/components/tools/trace.h @@ -28,5 +28,20 @@ #define STR(macro) QUOTE(macro) #endif #define ESP_LOG_DEBUG_EVENT(tag,e) ESP_LOGD(tag,"evt: " e) +#ifndef STR_OR_ALT +#define STR_OR_ALT(str,alt) (str?str:alt) +#endif +extern const char unknown_string_placeholder[]; +extern const char * str_or_unknown(const char * str); + +#ifndef FREE_AND_NULL +#define FREE_AND_NULL(x) if(x) { free(x); x=NULL; } +#endif + +#ifndef CASE_TO_STR +#define CASE_TO_STR(x) case x: return STR(x); break; +#endif +#define START_FREE_MEM_CHECK(a) size_t a=heap_caps_get_free_size(MALLOC_CAP_INTERNAL); +#define CHECK_RESET_FREE_MEM_CHECK(a,b) ESP_LOGV(__FUNCTION__ ,b "Mem used: %i",a-heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); a=heap_caps_get_free_size(MALLOC_CAP_INTERNAL) diff --git a/components/wifi-manager/component.mk b/components/wifi-manager/component.mk index a11cccff..e3d9cd0d 100644 --- a/components/wifi-manager/component.mk +++ b/components/wifi-manager/component.mk @@ -8,6 +8,6 @@ # COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz COMPONENT_ADD_INCLUDEDIRS := . -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 6599f996..5e6f7b25 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -51,6 +51,7 @@ function to process requests, decode URLs, serve files, etc. etc. #include "lwip/ip_addr.h" #include "messaging.h" #include "platform_esp32.h" +#include "trace.h" #define HTTP_STACK_SIZE (5*1024) const char str_na[]="N/A"; @@ -148,6 +149,7 @@ char * http_alloc_get_socket_address(httpd_req_t *req, u8_t local, in_port_t * p int s = httpd_req_to_sockfd(req); if(s == -1) { + free(ipstr); return strdup("httpd_req_to_sockfd error"); } ESP_LOGV_LOC(TAG,"httpd socket descriptor: %u", s); @@ -239,24 +241,31 @@ bool is_captive_portal_host_name(httpd_req_t *req){ /* Custom function to free context */ void free_ctx_func(void *ctx) { + START_FREE_MEM_CHECK(ff); session_context_t * context = (session_context_t *)ctx; if(context){ + ESP_LOGD(TAG, "Freeing up socket context"); FREE_AND_NULL(context->auth_token); FREE_AND_NULL(context->sess_ip_address); free(context); + CHECK_RESET_FREE_MEM_CHECK(ff,"free_ctx"); } } session_context_t* get_session_context(httpd_req_t *req){ + START_FREE_MEM_CHECK(ff); 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->free_ctx = free_ctx_func; // get the remote IP address only once per session } session_context_t *ctx_data = (session_context_t*)req->sess_ctx; + FREE_AND_NULL(ctx_data->sess_ip_address); ctx_data->sess_ip_address = http_alloc_get_socket_address(req, 0, &ctx_data->port); ESP_LOGD_LOC(TAG, "serving %s to peer %s port %u", req->uri, ctx_data->sess_ip_address , ctx_data->port); + CHECK_RESET_FREE_MEM_CHECK(ff,"get sess context"); return (session_context_t *)req->sess_ctx; } @@ -1043,25 +1052,34 @@ esp_err_t redirect_ev_handler(httpd_req_t *req){ esp_err_t messages_get_handler(httpd_req_t *req){ ESP_LOGD_LOC(TAG, "serving [%s]", req->uri); + START_FREE_MEM_CHECK(before); + START_FREE_MEM_CHECK(all); if(!is_user_authenticated(req)){ // todo: redirect to login page // return ESP_OK; } + CHECK_RESET_FREE_MEM_CHECK(before, "after user auth"); esp_err_t err = set_content_type_from_req(req); if(err != ESP_OK){ return err; } - + CHECK_RESET_FREE_MEM_CHECK(before, "after set_content_type"); cJSON * json_messages= messaging_retrieve_messages(messaging); + CHECK_RESET_FREE_MEM_CHECK(before, "after receiving messages"); if(json_messages!=NULL){ char * json_text= cJSON_Print(json_messages); + CHECK_RESET_FREE_MEM_CHECK(before, "after json print"); httpd_resp_send(req, (const char *)json_text, strlen(json_text)); - cJSON_free(json_messages); + CHECK_RESET_FREE_MEM_CHECK(before, "after http send"); free(json_text); + CHECK_RESET_FREE_MEM_CHECK(before, "after free json message"); + cJSON_free(json_messages); + CHECK_RESET_FREE_MEM_CHECK(before, "after free json"); } else { httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to retrieve messages"); } + CHECK_RESET_FREE_MEM_CHECK(all, "before returning"); return ESP_OK; } diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c index 084ff142..667d01d6 100644 --- a/components/wifi-manager/wifi_manager.c +++ b/components/wifi-manager/wifi_manager.c @@ -60,6 +60,7 @@ Contains the freeRTOS task and all necessary support #include "config.h" #include "trace.h" #include "cmd_system.h" +#include "messaging.h" #include "http_server_handlers.h" #include "monitor.h" @@ -850,20 +851,6 @@ void wifi_manager_connect_async(){ wifi_manager_send_message(ORDER_CONNECT_STA, (void*)CONNECTION_REQUEST_USER); } -void set_status_message(message_severity_t severity, const char * message){ - if(ip_info_cjson==NULL){ - ip_info_cjson = wifi_manager_get_new_json(&ip_info_cjson); - } - if(ip_info_cjson==NULL){ - ESP_LOGE(TAG, "Error setting status message. Unable to allocate cJSON."); - return; - } - cJSON * item=cJSON_GetObjectItem(ip_info_cjson, "message"); - item = wifi_manager_get_new_json(&item); - cJSON_AddItemToObject(item, "severity", cJSON_CreateString(severity==INFO?"INFO":severity==WARNING?"WARNING":severity==ERROR?"ERROR":"" )); - cJSON_AddItemToObject(item, "text", cJSON_CreateString(message)); -} - char* wifi_manager_alloc_get_ip_info_json(){ return cJSON_PrintUnformatted(ip_info_cjson); @@ -1142,6 +1129,7 @@ void wifi_manager( void * pvParameters ){ if(esp_wifi_scan_start(&scan_config, false)!=ESP_OK){ ESP_LOGW(TAG, "Unable to start scan; wifi is trying to connect"); // set_status_message(WARNING, "Wifi Connecting. Cannot start scan."); + messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"Wifi connecting. Cannot start scan."); } else { xEventGroupSetBits(wifi_manager_event_group, WIFI_MANAGER_SCAN_BIT); diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 2e98a7b9..373cad3f 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -124,7 +124,7 @@ esp_err_t http_server_start() strlcpy(rest_context->base_path, "/res/", sizeof(rest_context->base_path)); httpd_config_t config = HTTPD_DEFAULT_CONFIG(); - config.max_uri_handlers = 20; + config.max_uri_handlers = 25; config.max_open_sockets = 5; config.uri_match_fn = httpd_uri_match_wildcard; //todo: use the endpoint below to configure session token? diff --git a/main/platform_esp32.h b/main/platform_esp32.h index 545086a0..3443e069 100644 --- a/main/platform_esp32.h +++ b/main/platform_esp32.h @@ -31,28 +31,4 @@ extern bool wait_for_wifi(); extern void console_start(); extern pthread_cond_t wifi_connect_suspend_cond; extern pthread_t wifi_connect_suspend_mutex; -typedef enum { - INFO, - WARNING, - ERROR -} message_severity_t; -extern void set_status_message(message_severity_t severity, const char * message); -#ifndef STR_OR_ALT -#define STR_OR_ALT(str,alt) (str?str:alt) -#endif -extern const char unknown_string_placeholder[]; -extern const char * str_or_unknown(const char * str); - -#ifndef FREE_AND_NULL -#define FREE_AND_NULL(x) if(x) { free(x); x=NULL; } -#endif -#ifndef QUOTE -#define QUOTE(name) #name -#endif -#ifndef STR -#define STR(macro) QUOTE(macro) -#endif -#ifndef CASE_TO_STR -#define CASE_TO_STR(x) case x: return STR(x); break; -#endif From 5a7a7c9e605b7e60bb12b71f3656249b34df101e Mon Sep 17 00:00:00 2001 From: Sebastien Date: Mon, 24 Feb 2020 16:41:30 -0500 Subject: [PATCH 23/46] remove unnecessary http_server.c file --- components/wifi-manager/http_server.c | 654 -------------------------- eclipse_make_wrapper.py | 5 +- 2 files changed, 3 insertions(+), 656 deletions(-) delete mode 100644 components/wifi-manager/http_server.c diff --git a/components/wifi-manager/http_server.c b/components/wifi-manager/http_server.c deleted file mode 100644 index a5f8df2a..00000000 --- a/components/wifi-manager/http_server.c +++ /dev/null @@ -1,654 +0,0 @@ -/* -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 -*/ - -#include "http_server.h" -#include "cmd_system.h" -#include -#include "squeezelite-ota.h" -#include "nvs_utilities.h" -#include -#include -#include "cJSON.h" -#include "esp_system.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "config.h" - -#define HTTP_STACK_SIZE (5*1024) - -/* @brief tag used for ESP serial console messages */ -static const char TAG[] = "http_server"; -/* @brief task handle for the http server */ -static TaskHandle_t task_http_server = NULL; -static StaticTask_t task_http_buffer; -#if RECOVERY_APPLICATION -static StackType_t task_http_stack[HTTP_STACK_SIZE]; -#else -static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE]; -#endif -SemaphoreHandle_t http_server_config_mutex = NULL; - -/** - * @brief embedded binary data. - * @see file "component.mk" - * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data - */ -extern const uint8_t style_css_start[] asm("_binary_style_css_start"); -extern const uint8_t style_css_end[] asm("_binary_style_css_end"); -extern const uint8_t jquery_gz_start[] asm("_binary_jquery_min_js_gz_start"); -extern const uint8_t jquery_gz_end[] asm("_binary_jquery_min_js_gz_end"); -extern const uint8_t popper_gz_start[] asm("_binary_popper_min_js_gz_start"); -extern const uint8_t popper_gz_end[] asm("_binary_popper_min_js_gz_end"); -extern const uint8_t bootstrap_js_gz_start[] asm("_binary_bootstrap_min_js_gz_start"); -extern const uint8_t bootstrap_js_gz_end[] asm("_binary_bootstrap_min_js_gz_end"); -extern const uint8_t bootstrap_css_gz_start[] asm("_binary_bootstrap_min_css_gz_start"); -extern const uint8_t bootstrap_css_gz_end[] asm("_binary_bootstrap_min_css_gz_end"); -extern const uint8_t code_js_start[] asm("_binary_code_js_start"); -extern const uint8_t code_js_end[] asm("_binary_code_js_end"); -extern const uint8_t index_html_start[] asm("_binary_index_html_start"); -extern const uint8_t index_html_end[] asm("_binary_index_html_end"); - - -/* const http headers stored in ROM */ -const static char http_hdr_template[] = "HTTP/1.1 200 OK\nContent-type: %s\nAccept-Ranges: bytes\nContent-Length: %d\nContent-Encoding: %s\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_html_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/html\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_css_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/css\nCache-Control: public, max-age=31536000\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_js_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\nAccess-Control-Allow-Origin: *\n\n"; -const static char http_400_hdr[] = "HTTP/1.1 400 Bad Request\nContent-Length: 0\n\n"; -const static char http_404_hdr[] = "HTTP/1.1 404 Not Found\nContent-Length: 0\n\n"; -const static char http_503_hdr[] = "HTTP/1.1 503 Service Unavailable\nContent-Length: 0\n\n"; -const static char http_ok_json_no_cache_hdr[] = "HTTP/1.1 200 OK\nContent-type: application/json\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n"; -const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://"; -const static char http_redirect_hdr_end[] = "/\n\n"; - - -void http_server_start() { - ESP_LOGD(TAG, "http_server_start "); - if(task_http_server == NULL) { - task_http_server = xTaskCreateStatic( (TaskFunction_t) &http_server, "http_server", HTTP_STACK_SIZE, NULL, - WIFI_MANAGER_TASK_PRIORITY, task_http_stack, &task_http_buffer); - } -} -void http_server(void *pvParameters) { - http_server_config_mutex = xSemaphoreCreateMutex(); - struct netconn *conn, *newconn; - err_t err; - conn = netconn_new(NETCONN_TCP); - netconn_bind(conn, IP_ADDR_ANY, 80); - netconn_listen(conn); - ESP_LOGI(TAG, "HTTP Server listening on 80/tcp"); - do { - err = netconn_accept(conn, &newconn); - if(err == ERR_OK) { - http_server_netconn_serve(newconn); - netconn_delete(newconn); - } - else - { - ESP_LOGE(TAG, "Error accepting new connection. Terminating HTTP server"); - } - taskYIELD(); /* allows the freeRTOS scheduler to take over if needed. */ - } while(err == ERR_OK); - - netconn_close(conn); - netconn_delete(conn); - vSemaphoreDelete(http_server_config_mutex); - http_server_config_mutex = NULL; - vTaskDelete( NULL ); -} - - -char* http_server_get_header(char *request, char *header_name, int *len) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - - ptr = strstr(request, header_name); - if(ptr) { - ret = ptr + strlen(header_name); - ptr = ret; - while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') { - (*len)++; - ptr++; - } - return ret; - } - return NULL; -} -char* http_server_search_header(char *request, char *header_name, int *len, char ** parm_name, char ** next_position, char * bufEnd) { - *len = 0; - char *ret = NULL; - char *ptr = NULL; - int currentLength=0; - - ESP_LOGV(TAG, "searching for header name: [%s]", header_name); - ptr = strstr(request, header_name); - - - if(ptr!=NULL && ptr0) { - ESP_LOGD(TAG, "Found Header Line %s ", last); - //Content-Type: application/json - } - else { - ESP_LOGD(TAG, "Found end of headers"); - bHeaders = false; - } - last=ptr; - } - else { - //ESP_LOGD(TAG, "Body content: %s", last); - //cJSON * json = cJSON_Parse(last); - //cJSON_Delete(json); - //todo: implement body json parsing - // right now, body is coming as compressed, so we need some type of decompression to happen. - return; - } - } - return ; - -} - -void dump_net_buffer(void * buf, u16_t buflen) { - char * curbuf = malloc(buflen+1); - ESP_LOGV(TAG, "netconn buffer, length=%u",buflen); - if(curbuf==NULL) { - ESP_LOGE(TAG, "Unable to show netconn buffer. Malloc failed"); - } - memset(curbuf,0x0, buflen+1); - memcpy(curbuf,buf,buflen); - ESP_LOGV(TAG, "netconn buffer content:\n%s",curbuf); - free(curbuf); -} - -void http_server_netconn_serve(struct netconn *conn) { - - struct netbuf *inbuf; - char *buf = NULL; - u16_t buflen = 0; - err_t err; - ip_addr_t remote_add; - u16_t port; - ESP_LOGV(TAG, "Serving page. Getting device AP address."); - const char new_line[2] = "\n"; - char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0); - if(ap_ip_address==NULL){ - ESP_LOGE(TAG, "Unable to retrieve default AP IP Address"); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - netconn_close(conn); - return; - } - ESP_LOGV(TAG, "Getting remote device IP address."); - netconn_getaddr(conn, &remote_add, &port, 0); - char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add))); - ESP_LOGD(TAG, "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address); - - u16_t bufsize = 0; - netconn_set_recvtimeout(conn, 50); - while (netconn_recv(conn, &inbuf) == ERR_OK) { - do { - u8_t *rcvbuf; - u16_t rcvlen; - netbuf_data(inbuf, (void**)&rcvbuf, &rcvlen); - dump_net_buffer(rcvbuf, rcvlen); - if (buflen + rcvlen > bufsize) { - bufsize += rcvlen - bufsize < 2048 ? 2048 : rcvlen - bufsize; - buf = realloc(buf, bufsize); - } - memcpy(buf + buflen, rcvbuf, rcvlen); - buflen += rcvlen; - ESP_LOGI(TAG, "received netbuf of %hu", rcvlen); - } while (netbuf_next(inbuf) != -1); - netbuf_delete(inbuf); - } - - if(buflen) { - ESP_LOGV(TAG, "Getting data buffer."); - int lenH = 0; - /* extract the first line of the request */ - char *save_ptr = buf; - char *line = strtok_r(save_ptr, new_line, &save_ptr); - char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH); - char * host = malloc(lenH+1); - memset(host,0x00,lenH+1); - if(lenH>0){ - strlcpy(host,temphost,lenH+1); - } - ESP_LOGD(TAG, "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line); - - if(line) { - - /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */ - const char * host_name=NULL; - if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) { - ESP_LOGE(TAG, "Unable to get host name. Error: %s",esp_err_to_name(err)); - } - else { - ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host); - } - - /* determine if Host is from the STA IP address */ - wifi_manager_lock_sta_ip_string(portMAX_DELAY); - bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false; - wifi_manager_unlock_sta_ip_string(); - bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name); - - if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) { - ESP_LOGI(TAG, "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address); - netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY); - netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY); - netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY); - } - else { - //static stuff - /* default page */ - if(strstr(line, "GET / ")) { - netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, index_html_start, index_html_end- index_html_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /code.js ")) { - netconn_write(conn, http_js_hdr, sizeof(http_js_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, code_js_start, code_js_end - code_js_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /style.css ")) { - netconn_write(conn, http_css_hdr, sizeof(http_css_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, style_css_start, style_css_end - style_css_start, NETCONN_NOCOPY); - } - else if(strstr(line, "GET /jquery.js ")) { - http_server_send_resource_file(conn,jquery_gz_start, jquery_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /popper.js ")) { - http_server_send_resource_file(conn,popper_gz_start, popper_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.js ")) { - http_server_send_resource_file(conn,bootstrap_js_gz_start, bootstrap_js_gz_end, "text/javascript", "gzip" ); - } - else if(strstr(line, "GET /bootstrap.css ")) { - http_server_send_resource_file(conn,bootstrap_css_gz_start, bootstrap_css_gz_end, "text/css", "gzip" ); - } - - //dynamic stuff - else if(strstr(line, "GET /scan.json ")) { - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - } - else if(strstr(line, "GET /ap.json ")) { - /* if we can get the mutex, write the last version of the AP list */ - ESP_LOGI(TAG, "Processing ap.json request"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - char *buff = wifi_manager_alloc_get_ap_list_json(); - wifi_manager_unlock_json_buffer(); - if(buff!=NULL){ - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - ESP_LOGD(TAG, "Error retrieving ap list json string. "); - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex"); - } - /* request a wifi scan */ - ESP_LOGI(TAG, "Starting wifi scan"); - wifi_manager_scan_async(); - ESP_LOGI(TAG, "Done serving ap.json"); - } - else if(strstr(line, "GET /config.json ")) { - ESP_LOGI(TAG, "Serving config.json"); - ESP_LOGI(TAG, "About to get config from flash"); - http_server_send_config_json(conn); - ESP_LOGD(TAG, "Done serving config.json"); - } - else if(strstr(line, "POST /config.json ")) { - ESP_LOGI(TAG, "Serving POST config.json"); - int lenA=0; - char * last_parm=save_ptr; - char * next_parm=save_ptr; - char * last_parm_name=NULL; - bool bErrorFound=false; - bool bOTA=false; - char * otaURL=NULL; - // todo: implement json body parsing - //http_server_process_config(conn,save_ptr); - - while(last_parm!=NULL) { - // Search will return - ESP_LOGD(TAG, "Getting parameters from X-Custom headers"); - last_parm = http_server_search_header(next_parm, "X-Custom-", &lenA, &last_parm_name,&next_parm,buf+buflen); - if(last_parm!=NULL && last_parm_name!=NULL) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST config.json, config %s=%s", last_parm_name, last_parm); - if(strcmp(last_parm_name, "fwurl")==0) { - // we're getting a request to do an OTA from that URL - ESP_LOGW(TAG, "Found OTA request!"); - otaURL=strdup(last_parm); - bOTA=true; - } - else { - ESP_LOGV(TAG, "http_server_netconn_serve: POST config.json Storing parameter"); - if(config_set_value(NVS_TYPE_STR, last_parm_name , last_parm) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save nvs value."); - } - } - } - if(last_parm_name!=NULL) { - free(last_parm_name); - last_parm_name=NULL; - } - } - if(bErrorFound) { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); //400 invalid request - } - else { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - if(bOTA) { - -#if RECOVERY_APPLICATION - ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); -#else - ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); -#endif - wifi_manager_reboot_ota(otaURL); - free(otaURL); - } - } - ESP_LOGI(TAG, "Done Serving POST config.json"); - } - else if(strstr(line, "POST /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST /connect.json"); - bool found = false; - int lenS = 0, lenP = 0, lenN = 0; - char *ssid = NULL, *password = NULL; - ssid = http_server_get_header(save_ptr, "X-Custom-ssid: ", &lenS); - password = http_server_get_header(save_ptr, "X-Custom-pwd: ", &lenP); - char * new_host_name_b = http_server_get_header(save_ptr, "X-Custom-host_name: ", &lenN); - if(lenN > 0){ - lenN++; - char * new_host_name = malloc(lenN); - strlcpy(new_host_name, new_host_name_b, lenN); - if(config_set_value(NVS_TYPE_STR, "host_name", new_host_name) != ESP_OK){ - ESP_LOGE(TAG, "Unable to save host name configuration"); - } - free(new_host_name); - } - - if(ssid && lenS <= MAX_SSID_SIZE && password && lenP <= MAX_PASSWORD_SIZE) { - wifi_config_t* config = wifi_manager_get_wifi_sta_config(); - memset(config, 0x00, sizeof(wifi_config_t)); - memcpy(config->sta.ssid, ssid, lenS); - memcpy(config->sta.password, password, lenP); - ESP_LOGD(TAG, "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password); - wifi_manager_connect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok - found = true; - } - else{ - ESP_LOGE(TAG, "SSID or Password invalid"); - } - - - if(!found) { - /* bad request the authentification header is not complete/not the correct format */ - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request the authentification header is not complete/not the correct format"); - } - - ESP_LOGI(TAG, "http_server_netconn_serve: done serving connect.json"); - } - else if(strstr(line, "DELETE /connect.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: DELETE /connect.json"); - /* request a disconnection from wifi and forget about it */ - wifi_manager_disconnect_async(); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - ESP_LOGI(TAG, "http_server_netconn_serve: done serving DELETE /connect.json"); - } - else if(strstr(line, "POST /reboot_ota.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot_ota.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(OTA); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot_ota.json"); - } - else if(strstr(line, "POST /reboot.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST reboot.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RESTART); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST reboot.json"); - } - else if(strstr(line, "POST /recovery.json ")) { - ESP_LOGI(TAG, "http_server_netconn_serve: POST recovery.json"); - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */ - wifi_manager_reboot(RECOVERY); - ESP_LOGI(TAG, "http_server_netconn_serve: done serving POST recovery.json"); - } - else if(strstr(line, "GET /status.json ")) { - ESP_LOGI(TAG, "Serving status.json"); - if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) { - char *buff = wifi_manager_alloc_get_ip_info_json(); - wifi_manager_unlock_json_buffer(); - if(buff) { - netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); - netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY); - free(buff); - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - } - - } - else { - netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "http_server_netconn_serve: GET /status failed to obtain mutex"); - } - ESP_LOGI(TAG, "Done Serving status.json"); - } - else { - netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); - ESP_LOGE(TAG, "bad request from host: %s, request %s",remote_address, line); - } - } - } - else { - ESP_LOGE(TAG, "URL not found processing for remote host : %s",remote_address); - netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY); - } - free(host); - free(buf); - } - - free(ap_ip_address); - free(remote_address); - netconn_close(conn); - /* free the buffer */ - -} - -bool http_server_lock_json_object(TickType_t xTicksToWait) { - ESP_LOGD(TAG, "Locking config json object"); - if(http_server_config_mutex) { - if( xSemaphoreTake( http_server_config_mutex, xTicksToWait ) == pdTRUE ) { - ESP_LOGV(TAG, "config Json object locked!"); - return true; - } - else { - ESP_LOGW(TAG, "Semaphore take failed. Unable to lock config Json object mutex"); - return false; - } - } - else { - ESP_LOGW(TAG, "Unable to lock config Json object mutex"); - return false; - } - -} - -void http_server_unlock_json_object() { - ESP_LOGD(TAG, "Unlocking json buffer!"); - xSemaphoreGive( http_server_config_mutex ); -} - -void strreplace(char *src, char *str, char *rep) -{ - char *p = strstr(src, str); - if(p) - { - int len = strlen(src)+strlen(rep)-strlen(str); - char r[len]; - memset(r, 0, len); - if( p >= src ) { - strncpy(r, src, p-src); - r[p-src]='\0'; - strncat(r, rep, strlen(rep)); - strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); - strcpy(src, r); - strreplace(p+strlen(rep), str, rep); - } - } -} - diff --git a/eclipse_make_wrapper.py b/eclipse_make_wrapper.py index f18048e8..d45d9aa6 100644 --- a/eclipse_make_wrapper.py +++ b/eclipse_make_wrapper.py @@ -12,7 +12,7 @@ import glob from test import test_cmd_line #UNIX_PATH_RE = re.compile(r'(([a-zA-Z]{1}[:]{1}){0,1}[/\\][^\s\'\"\t\[\(]+)+') -UNIX_PATH_RE = re.compile(r'(([a-zA-Z]{1}[:]{1}){0,1}[/\\][^\s\'\"\t\[\(]+(?![^\\/]*$)[/\\]?)') +UNIX_PATH_RE = re.compile(r'(([a-zA-Z]{1}[:]{1}){0,1}[/\\][^\s\'\"\t\[\(]+(?![^\\/\n]*$)[/\\]?)') INCLUDE_PATH_RE = re.compile(r'-I[\s"]{0,}(.+?)["]{0,}(?=\s-\S)') INCLUDE_PATH_ADJ_RE = re.compile(r'^([/]opt[/]esp-idf[/]){1}(.*)') INCLUDE_PATH_ADJ2_RE = re.compile(r'^([/]c[/]){1}(.*)') @@ -29,7 +29,8 @@ def check_path(path): except KeyError: pass paths[path] = path - winpath =path + winpath =re.sub(r'\\n$',winpath,' ',1) + if not os.path.exists(winpath): # cache as failed, replace with success if it works if re.match(INCLUDE_PATH_ADJ2_RE, path) is not None: From d0a086e84b196887809c6e2f53b931a136bb617a Mon Sep 17 00:00:00 2001 From: Sebastien Date: Mon, 24 Feb 2020 18:00:48 -0500 Subject: [PATCH 24/46] increase http client buffer size --- components/squeezelite-ota/squeezelite-ota.c | 30 ++++++++++---------- eclipse_make_wrapper.py | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 5110baae..84d2d383 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -41,10 +41,9 @@ extern const char * get_certificate(); #endif static const char *TAG = "squeezelite-ota"; -char * ota_write_data = NULL; esp_http_client_handle_t ota_http_client = NULL; #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1 -#define BUFFSIZE 4096 +#define BUFFSIZE 8192 #define HASH_LEN 32 /* SHA-256 digest length */ typedef struct { char * url; @@ -62,7 +61,7 @@ static struct { uint32_t total_image_len; uint32_t remain_image_len; ota_type_t ota_type; - char * bin; + char * ota_write_data; bool bOTAStarted; uint8_t lastpct; uint8_t newpct; @@ -222,16 +221,16 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ ota_config.url = strdup(p_ota_thread_parms->url); ota_config.max_redirection_count = 3; - ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - //ota_write_data = malloc(ota_config.buffer_size+1); - if(ota_write_data== NULL){ + ota_status.ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + + if(ota_status.ota_write_data== NULL){ ESP_LOGE(TAG,"Error allocating the ota buffer"); return ESP_ERR_NO_MEM; } break; case OTA_TYPE_BUFFER: - ota_status.bin = p_ota_thread_parms->bin; + ota_status.ota_write_data = p_ota_thread_parms->bin; ota_status.total_image_len = p_ota_thread_parms->length; break; @@ -342,7 +341,7 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client } ESP_LOGD(TAG, "Redirection done, checking if we need to read the data. "); if (process_again(status_code)) { - ESP_LOGD(TAG, "We have to read some more data. Allocating buffer size %u",ota_config.buffer_size+1); + //ESP_LOGD(TAG, "We have to read some more data. Allocating buffer size %u",ota_config.buffer_size+1); char local_buff_var[501]={}; //char * local_buff = heap_caps_malloc(ota_config.buffer_size+1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); //char * local_buff = malloc(ota_config.buffer_size+1); @@ -404,8 +403,9 @@ void ota_task_cleanup(const char * message, ...){ sendMessaging(MESSAGING_ERROR,message, args); va_end(args); } - FREE_RESET(ota_status.bin); - FREE_RESET(ota_write_data); + if(ota_status.ota_type == OTA_TYPE_HTTP){ + FREE_RESET(ota_status.ota_write_data); + } if(ota_http_client!=NULL) { esp_http_client_cleanup(ota_http_client); ota_http_client=NULL; @@ -479,7 +479,6 @@ void ota_task(void *pvParameter) } } else { - ota_write_data = ota_status.bin; gettimeofday(&ota_status.OTA_start, NULL); } _printMemStats(); @@ -493,7 +492,8 @@ void ota_task(void *pvParameter) ota_status.remain_image_len =ota_status.total_image_len -ota_status.actual_image_len; if (ota_status.ota_type == OTA_TYPE_HTTP){ - data_read = esp_http_client_read(ota_http_client, ota_write_data, buffer_size); + ESP_LOGW(TAG,"Reading data from http client"); + data_read = esp_http_client_read(ota_http_client, ota_status.ota_write_data, buffer_size); } else { if(ota_status.remain_image_len >buffer_size){ @@ -510,7 +510,7 @@ void ota_task(void *pvParameter) esp_app_desc_t new_app_info; if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) { // check current version with downloading - memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); + memcpy(&new_app_info, &ota_status.ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); esp_app_desc_t running_app_info; @@ -541,7 +541,7 @@ void ota_task(void *pvParameter) return; } } - err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read); + err = esp_ota_write( update_handle, (const void *)ota_status.ota_write_data, data_read); if (err != ESP_OK) { ota_task_cleanup("Error: OTA Partition write failure. (%s)",esp_err_to_name(err)); return; @@ -549,7 +549,7 @@ void ota_task(void *pvParameter) ota_status.actual_image_len += data_read; if(ota_status.ota_type == OTA_TYPE_BUFFER){ // position the ota buffer in the next buffer chunk - ota_write_data+= data_read; + ota_status.ota_write_data+= data_read; } ESP_LOGD(TAG, "Written image length %d", ota_status.actual_image_len); if(ota_get_pct_complete()%5 == 0) ota_status.newpct = ota_get_pct_complete(); diff --git a/eclipse_make_wrapper.py b/eclipse_make_wrapper.py index d45d9aa6..76abdb2c 100644 --- a/eclipse_make_wrapper.py +++ b/eclipse_make_wrapper.py @@ -29,7 +29,7 @@ def check_path(path): except KeyError: pass paths[path] = path - winpath =re.sub(r'\\n$',winpath,' ',1) + winpath =path if not os.path.exists(winpath): # cache as failed, replace with success if it works From c6eb24020b4c8f1cfd00129c86c4829f81029f4d Mon Sep 17 00:00:00 2001 From: Sebastien Date: Mon, 24 Feb 2020 19:06:51 -0500 Subject: [PATCH 25/46] httpd testing - release --- components/squeezelite-ota/squeezelite-ota.c | 1 - components/wifi-manager/component.mk | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 84d2d383..518e8f06 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -492,7 +492,6 @@ void ota_task(void *pvParameter) ota_status.remain_image_len =ota_status.total_image_len -ota_status.actual_image_len; if (ota_status.ota_type == OTA_TYPE_HTTP){ - ESP_LOGW(TAG,"Reading data from http client"); data_read = esp_http_client_read(ota_http_client, ota_status.ota_write_data, buffer_size); } else { diff --git a/components/wifi-manager/component.mk b/components/wifi-manager/component.mk index e3d9cd0d..1800f23c 100644 --- a/components/wifi-manager/component.mk +++ b/components/wifi-manager/component.mk @@ -8,6 +8,6 @@ # COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz COMPONENT_ADD_INCLUDEDIRS := . -CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO From fe4f7ffb586208c3bcb479739714b1b4309e6790 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Mon, 24 Feb 2020 21:28:41 -0500 Subject: [PATCH 26/46] tune OTA update buffer - release --- components/services/services.c | 1 - components/squeezelite-ota/squeezelite-ota.c | 47 ++++++++++++-------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/components/services/services.c b/components/services/services.c index f138cd88..5880af11 100644 --- a/components/services/services.c +++ b/components/services/services.c @@ -53,7 +53,6 @@ void set_power_gpio(int gpio, char *value) { */ void services_init(void) { messaging_service_init(); - messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM, "Initializing services"); gpio_install_isr_service(0); #ifdef CONFIG_I2C_LOCKED diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 518e8f06..aa44fb24 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -40,10 +40,11 @@ extern const char * get_certificate(); #define OTA_CORE 1 #endif + static const char *TAG = "squeezelite-ota"; esp_http_client_handle_t ota_http_client = NULL; #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1 -#define BUFFSIZE 8192 +#define BUFFSIZE 2048 #define HASH_LEN 32 /* SHA-256 digest length */ typedef struct { char * url; @@ -63,6 +64,7 @@ static struct { ota_type_t ota_type; char * ota_write_data; bool bOTAStarted; + size_t buffer_size; uint8_t lastpct; uint8_t newpct; struct timeval OTA_start; @@ -210,18 +212,19 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ ESP_LOGE(TAG,"HTTP OTA called without a url or a binary buffer"); return ESP_ERR_INVALID_ARG; } - + ota_status.buffer_size = BUFFSIZE; switch (ota_status.ota_type) { case OTA_TYPE_HTTP: ota_config.cert_pem =get_certificate(); ota_config.event_handler = _http_event_handler; - ota_config.buffer_size = BUFFSIZE; + ota_config.buffer_size = ota_status.buffer_size; ota_config.disable_auto_redirect=true; ota_config.skip_cert_common_name_check = false; ota_config.url = strdup(p_ota_thread_parms->url); ota_config.max_redirection_count = 3; - ota_status.ota_write_data = heap_caps_malloc(ota_config.buffer_size+1 , MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + + ota_status.ota_write_data = heap_caps_malloc(ota_status.buffer_size+1 , (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); if(ota_status.ota_write_data== NULL){ ESP_LOGE(TAG,"Error allocating the ota buffer"); @@ -300,7 +303,7 @@ esp_err_t _erase_last_boot_app_partition(esp_partition_t *ota_partition) if(i%2) { sendMessaging(MESSAGING_INFO,"Erasing flash (%u/%u)",i,num_passes); } - //vTaskDelay(200/ portTICK_PERIOD_MS); // wait here for a short amount of time. This will help with reducing WDT errors + vTaskDelay(100/ portTICK_PERIOD_MS); // wait here for a short amount of time. This will help with reducing WDT errors } if(remain_size>0){ err=esp_partition_erase_range(ota_partition, ota_partition->size-remain_size, remain_size); @@ -342,16 +345,15 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client ESP_LOGD(TAG, "Redirection done, checking if we need to read the data. "); if (process_again(status_code)) { //ESP_LOGD(TAG, "We have to read some more data. Allocating buffer size %u",ota_config.buffer_size+1); - char local_buff_var[501]={}; - //char * local_buff = heap_caps_malloc(ota_config.buffer_size+1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - //char * local_buff = malloc(ota_config.buffer_size+1); -// if(local_buff==NULL){ -// ESP_LOGE(TAG,"Failed to allocate internal memory buffer for http processing"); -// return ESP_ERR_NO_MEM; -// } + char * local_buff = heap_caps_malloc(ota_status.buffer_size+1, (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + + if(local_buff==NULL){ + ESP_LOGE(TAG,"Failed to allocate internal memory buffer for http processing"); + return ESP_ERR_NO_MEM; + } while (1) { ESP_LOGD(TAG, "Buffer successfully allocated. Reading data chunk. "); - int data_read = esp_http_client_read(http_client, local_buff_var, sizeof(local_buff_var)); + int data_read = esp_http_client_read(http_client, local_buff, ota_status.buffer_size); if (data_read < 0) { ESP_LOGE(TAG, "Error: SSL data read error"); err= ESP_FAIL; @@ -362,7 +364,7 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client break; } } - //FREE_RESET(local_buff); + FREE_RESET(local_buff); } return err; @@ -487,12 +489,17 @@ void ota_task(void *pvParameter) /*deal with all receive packet*/ bool image_header_was_checked = false; int data_read = 0; + if (ota_status.ota_type == OTA_TYPE_HTTP && ota_status.total_image_len > ota_partition->size){ + ota_task_cleanup("Error: Image size too large to fit in partition."); + return; + } while (1) { ota_status.remain_image_len =ota_status.total_image_len -ota_status.actual_image_len; if (ota_status.ota_type == OTA_TYPE_HTTP){ - data_read = esp_http_client_read(ota_http_client, ota_status.ota_write_data, buffer_size); + + data_read = esp_http_client_read(ota_http_client, ota_status.ota_write_data, ota_status.buffer_size); } else { if(ota_status.remain_image_len >buffer_size){ @@ -507,7 +514,7 @@ void ota_task(void *pvParameter) } else if (data_read > 0) { if (image_header_was_checked == false) { esp_app_desc_t new_app_info; - if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) { + if (data_read >= IMAGE_HEADER_SIZE) { // check current version with downloading memcpy(&new_app_info, &ota_status.ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); @@ -535,11 +542,13 @@ void ota_task(void *pvParameter) return; } ESP_LOGD(TAG, "esp_ota_begin succeeded"); - } else { - ota_task_cleanup("Error: Binary file too large for the current partition"); - return; } + else { + ota_task_cleanup("Error: Increase ota http buffer."); + return; + } } + err = esp_ota_write( update_handle, (const void *)ota_status.ota_write_data, data_read); if (err != ESP_OK) { ota_task_cleanup("Error: OTA Partition write failure. (%s)",esp_err_to_name(err)); From 47d7baaf5fcaf56ddad2a9e12830288802ee7507 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Tue, 25 Feb 2020 12:26:31 -0500 Subject: [PATCH 27/46] adjust grace period before reboot after success flash --- components/squeezelite-ota/squeezelite-ota.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index aa44fb24..8b48e840 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -593,7 +593,7 @@ void ota_task(void *pvParameter) if (err == ESP_OK) { ESP_LOGI(TAG,"OTA Process completed successfully!"); sendMessaging(MESSAGING_INFO,"Success!"); - vTaskDelay(1500/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh + vTaskDelay(1000/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh esp_restart(); } else { ota_task_cleanup("Error: Unable to update boot partition [%s]",esp_err_to_name(err)); From 0acb0dc3e781b86488ab7640dbf9225e333d1aa1 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Tue, 25 Feb 2020 21:40:57 -0500 Subject: [PATCH 28/46] fix system freezing on telnet activation --- .gitignore | 3 + build-scripts/ESP32-A1S-sdkconfig.defaults | 1 + build-scripts/I2S-4MFlash-sdkconfig.defaults | 2 +- .../NonOTA-I2S-4MFlash-sdkconfig.defaults | 1 + .../NonOTA-SqueezeAmp-sdkconfig.defaults | 1 + .../SqueezeAmp4MBFlash-sdkconfig.defaults | 1 + .../SqueezeAmp8MBFlash-sdkconfig.defaults | 1 + build_flash_cmd.sh | 113 +++++++++++++++++ components/telnet/telnet.c | 92 ++++++-------- components/telnet/telnet.h | 1 + main/console.c | 120 +++++++++++------- 11 files changed, 236 insertions(+), 100 deletions(-) create mode 100644 build_flash_cmd.sh diff --git a/.gitignore b/.gitignore index 6fae3f75..8f3b64f6 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ libs/ /_* sdkconfig squeezelite-esp32-jsonblob.zip +/flash_cmd.txt +/writeSequeezeEsp.bat +/writeSequeezeEsp.sh diff --git a/build-scripts/ESP32-A1S-sdkconfig.defaults b/build-scripts/ESP32-A1S-sdkconfig.defaults index b143fa21..0592a074 100644 --- a/build-scripts/ESP32-A1S-sdkconfig.defaults +++ b/build-scripts/ESP32-A1S-sdkconfig.defaults @@ -596,6 +596,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 5fee8c1d..0dc46d30 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -594,7 +594,7 @@ CONFIG_FMB_TIMER_INDEX=0 CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y - +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_HZ=100 CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults b/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults index f0819243..96583af2 100644 --- a/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults @@ -597,6 +597,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults index 8665f49c..72c3a1ed 100644 --- a/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults +++ b/build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults @@ -596,6 +596,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults index da977fe5..ea2b0531 100644 --- a/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults @@ -596,6 +596,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults index de796d67..94484e00 100644 --- a/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults @@ -590,6 +590,7 @@ CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_HZ=100 +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y diff --git a/build_flash_cmd.sh b/build_flash_cmd.sh new file mode 100644 index 00000000..7124e1f3 --- /dev/null +++ b/build_flash_cmd.sh @@ -0,0 +1,113 @@ +#!/bin/bash +echo +echo ================================================================= +echo Build flash command +echo ================================================================= +# Location of partitions.csv relative to this script +partitionsCsv="../partitions.csv" + +# File to output readme instructions to +outputReadme="./flash_cmd.txt" + +# File to output bash script to +outputBashScript="./writeSequeezeEsp.sh" + +# File to output bat script to +outputBatScript="./writeSequeezeEsp.bat" + +# The name of partitions to ignore from partitions.csv +paritionsToIgnore=( + "nvs" + "phy_init" + "storage" + "coredump" + "settings" +) + +# Function that maps partition name to actual bin file +# defaults to "[PARTION_NAME_FROM_CSV].bin" +function partitionNameToBinFile { + if [[ "$1" == "otadata" ]]; then + echo "ota_data_initial.bin" + elif [[ "$1" == "ota_0" || "$1" == "factory" ]]; then + echo "squeezelite.bin" + else + echo $1.bin + fi +} + +# write parameters for esptool.py +writeParameters="$writeParameters write_flash" +writeParameters="$writeParameters --flash_mode dio --flash_freq 80m --flash_size detect" + +# bootloader.bin and partitions.bin not in partitions.csv so manually add here +partitionsParameters=" 0x1000 bootloader/bootloader.bin" +partitionsParameters="$partitionsParameters 0x8000 partitions.bin" + +# ============================================================================== + +# Loop over partitions.csv and add partition bins and offsets to partitionsParameters + +for line in $($IDF_PATH/components/partition_table/gen_esp32part.py --quiet build/partitions.bin | grep '^[^#]') +do + partitionName=$(echo $line | awk -F',' '{printf "%s", $1}' ) + partitionOffset=$(echo $line |awk -F',' '{printf "%s", $4}' ) + partitionFile=$(partitionNameToBinFile $partitionName) + + if [[ " ${paritionsToIgnore[@]} " =~ " ${partitionName} " ]]; then + continue + fi + + partitionsParameters="$partitionsParameters $partitionOffset $partitionFile" + echo "$partitionsParameters" + +done + +# Write README Instructions +if [ ! -f "$outputReadme" ]; then + touch $outputReadme +fi + +echo "" >> $outputReadme +echo "====LINUX====" >> $outputReadme +echo "To flash sequeezelite run the following script:" >> $outputReadme +echo "$outputBashScript [PORT_HERE] [BAUD_RATE]" >> $outputReadme +echo "e.g. $outputBashScript /dev/ttyUSB0 115200" >> $outputReadme +echo "" >> $outputReadme +echo "====WINDOWS====" >> $outputReadme +echo "To flash sequeezelite run the following script:" >> $outputReadme +echo "$outputBatScript [PORT_HERE] [BAUD_RATE]" >> $outputReadme +echo "e.g. $outputBatScript COM11 115200" >> $outputReadme +echo "" >> $outputReadme +echo "If you don't know how to run the BAT file with arguments then you can" >> $outputReadme +echo "edit the bat file in Notepad. Open the file up and edit the following:" >> $outputReadme +echo "Change 'set port=%1' to 'set port=[PORT_HERE]'. E.g. 'set port=COM11'" >> $outputReadme +echo "Change 'set baud=%2' to 'set baud=[BAUD_RATE]'. E.g. 'set baud=115200'" >> $outputReadme +echo "" >> $outputReadme +echo "====MANUAL====" >> $outputReadme +echo "Python esptool.py --port [PORT_HERE] --baud [BAUD_RATE] $writeParameters $partitionsParameters" >> $outputReadme + +# Write Linux BASH File +if [ ! -f "$outputBashScript" ]; then + touch $outputBashScript +fi + +echo "#!/bin/bash" >> $outputBashScript +echo >> $outputBashScript +echo "port=\$1" >> $outputBashScript +echo "baud=\$2" >> $outputBashScript +linuxFlashCommand="Python esptool.py --port \$port --baud \$baud" +echo "$linuxFlashCommand $writeParameters $partitionsParameters" >> $outputBashScript + +# Write Windows BAT File +if [ ! -f "$outputBatScript" ]; then + touch $outputBatScript +fi + +echo "echo off" >> $outputBatScript +echo "" >> $outputBatScript +echo "set port=%1" >> $outputBatScript +echo "set baud=%2" >> $outputBatScript +windowsFlashCommand="Python esptool.py --port %port% --baud %baud%" +echo "$windowsFlashCommand $writeParameters $partitionsParameters" >> $outputBatScript + diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index cd9bfadb..b9b94f06 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -50,7 +50,7 @@ const static char tag[] = "telnet"; static int uart_fd=0; RingbufHandle_t buf_handle; -SemaphoreHandle_t xSemaphore = NULL; +//static SemaphoreHandle_t xSemaphore = NULL; static size_t send_chunk=300; static size_t log_buf_size=2000; //32-bit aligned size static bool bIsEnabled=false; @@ -68,7 +68,7 @@ static int stdout_fstat(int fd, struct stat * st); static ssize_t stdout_write(int fd, const void * data, size_t size); static char *eventToString(telnet_event_type_t type); static void handle_telnet_conn(); -static void process_logs( UBaseType_t bytes); +static void process_logs( UBaseType_t bytes, bool is_write_op); static bool bMirrorToUART=false; struct telnetUserData { int sockfd; @@ -76,7 +76,9 @@ struct telnetUserData { char * rxbuf; }; - +bool is_serial_suppressed(){ + return !bIsEnabled || !bMirrorToUART ; +} void init_telnet(){ char *val= get_nvs_value_alloc(NVS_TYPE_STR, "telnet_enable"); if (!val || strlen(val) == 0 || !strcasestr("YXD",val) ) { @@ -100,11 +102,12 @@ void init_telnet(){ log_buf_size=log_buf_size>0?log_buf_size:4000; } // Create the semaphore to guard a shared resource. - vSemaphoreCreateBinary( xSemaphore ); + //vSemaphoreCreateBinary( xSemaphore ); // Redirect the output to our telnet handler as soon as possible - StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)malloc(sizeof(StaticRingbuffer_t) ); + // All non-split ring buffer must have their memory alignment set to 32 bits. + uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT ); buf_handle = xRingbufferCreateStatic(log_buf_size, RINGBUF_TYPE_BYTEBUF, buffer_storage, buffer_struct); if (buf_handle == NULL) { ESP_LOGE(tag,"Failed to create ring buffer for telnet!"); @@ -119,7 +122,9 @@ void init_telnet(){ .fstat = &stdout_fstat, .close = &stdout_close, .read = &stdout_read, + }; + if(bMirrorToUART){ uart_fd=open("/dev/uart/0", O_RDWR); } @@ -130,11 +135,11 @@ void init_telnet(){ } void start_telnet(void * pvParameter){ static bool isStarted=false; - StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - StackType_t *xStack = malloc(TELNET_STACK_SIZE); + StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + StackType_t *xStack = heap_caps_malloc(TELNET_STACK_SIZE,(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); if(!isStarted && bIsEnabled) { - xTaskCreateStatic( (TaskFunction_t) &telnet_task, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, xTaskBuffer); + xTaskCreateStatic( (TaskFunction_t) &telnet_task, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_MAIN_PRIO , xStack, xTaskBuffer); isStarted=true; } } @@ -275,23 +280,23 @@ static void handle_telnet_events( } // myhandle_telnet_events -static void process_logs(UBaseType_t count){ +static void process_logs( UBaseType_t bytes, bool is_write_op){ //Receive an item from no-split ring buffer size_t item_size; - UBaseType_t uxItemsWaiting; - UBaseType_t uxBytesToSend=count; + UBaseType_t uxItemsWaiting; + UBaseType_t uxBytesToSend=bytes; - vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); - if(count == 0){ - // this sends the entire buffer to the remote client - uxBytesToSend = uxItemsWaiting; - } - if( partnerSocket ==0 && (uxItemsWaiting*100 / log_buf_size) <75){ - // We still have some room in the ringbuffer and there's no telnet - // connection yet, so bail out for now. - //printf("%s() Log buffer used %u of %u bytes used\n", __FUNCTION__, uxItemsWaiting, log_buf_size); + vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); + bool is_space_available = ((log_buf_size-uxItemsWaiting)>=bytes && log_buf_size>uxItemsWaiting); + if( is_space_available && (is_write_op || partnerSocket == 0) ){ + // there's still some room left in the buffer, and we're either + // processing a write operation or telnet isn't connected yet. return; } + if(is_write_op && !is_space_available && uxBytesToSend==0){ + // flush at least the size of a full chunk + uxBytesToSend = send_chunk; + } while(uxBytesToSend>0){ char *item = (char *)xRingbufferReceiveUpTo(buf_handle, &item_size, pdMS_TO_TICKS(50), uxBytesToSend); @@ -327,12 +332,12 @@ static void handle_telnet_conn() { struct telnetUserData *pTelnetUserData = (struct telnetUserData *)malloc(sizeof(struct telnetUserData)); tnHandle = telnet_init(my_telopts, handle_telnet_events, 0, pTelnetUserData); - pTelnetUserData->rxbuf = (char *) heap_caps_malloc(TELNET_RX_BUF, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + pTelnetUserData->rxbuf = (char *) heap_caps_malloc(TELNET_RX_BUF, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); pTelnetUserData->tnHandle = tnHandle; pTelnetUserData->sockfd = partnerSocket; // flush all the log buffer on connect - process_logs(0); + process_logs(log_buf_size, false); while(1) { //ESP_LOGD(tag, "waiting for data"); @@ -349,7 +354,7 @@ static void handle_telnet_conn() { partnerSocket = 0; return; } - process_logs(send_chunk); + process_logs(send_chunk, false); taskYIELD(); } @@ -358,37 +363,24 @@ static void handle_telnet_conn() { // ******************* stdout/stderr Redirection to ringbuffer static ssize_t stdout_write(int fd, const void * data, size_t size) { - if (xSemaphoreTake(xSemaphore, (TickType_t) 10) == pdTRUE) { - // #1 Write to ringbuffer - if (buf_handle == NULL) { - printf("%s() ABORT. file handle _log_remote_fp is NULL\n", - __FUNCTION__); - } else { - //Send an item - UBaseType_t res = xRingbufferSend(buf_handle, data, size, - pdMS_TO_TICKS(100)); - if (res != pdTRUE) { - // flush some entries - process_logs(size); - res = xRingbufferSend(buf_handle, data, size, - pdMS_TO_TICKS(100)); - if (res != pdTRUE) { - - printf("%s() ABORT. Unable to store log entry in buffer\n", - __FUNCTION__); - } - } - } - xSemaphoreGive(xSemaphore); + // #1 Write to ringbuffer + if (buf_handle == NULL) { + printf("%s() ABORT. file handle _log_remote_fp is NULL\n", + __FUNCTION__); } else { - // We could not obtain the semaphore and can therefore not access - // the shared resource safely. + // flush the buffer if needed + process_logs(size, true); + //Send an item + UBaseType_t res = xRingbufferSend(buf_handle, data, size, pdMS_TO_TICKS(10)); + assert(res == pdTRUE); + } - return bMirrorToUART?write(uart_fd, data, size):true; + return bMirrorToUART?write(uart_fd, data, size):size; } static ssize_t stdout_read(int fd, void* data, size_t size) { - return read(fd, data, size); + //return read(fd, data, size); + return 0; } static int stdout_open(const char * path, int flags, int mode) { diff --git a/components/telnet/telnet.h b/components/telnet/telnet.h index 255fa3d6..eb563ece 100644 --- a/components/telnet/telnet.h +++ b/components/telnet/telnet.h @@ -1,3 +1,4 @@ void init_telnet(); void start_telnet(void * pvParameter); +extern bool is_serial_suppressed(); diff --git a/main/console.c b/main/console.c index 2b83d68d..62bc5199 100644 --- a/main/console.c +++ b/main/console.c @@ -25,6 +25,7 @@ #include "cmd_decl.h" #include "console.h" #include "wifi_manager.h" +#include "telnet.h" #include "cmd_squeezelite.h" #include "config.h" @@ -156,8 +157,19 @@ void initialize_console() { void console_start() { - initialize_console(); - + if(!is_serial_suppressed()){ + initialize_console(); + } + else { + /* Initialize the console */ + esp_console_config_t console_config = { .max_cmdline_args = 22, + .max_cmdline_length = 600, + #if CONFIG_LOG_COLORS + .hint_color = atoi(LOG_COLOR_CYAN) + #endif + }; + ESP_ERROR_CHECK(esp_console_init(&console_config)); + } /* Register commands */ esp_console_register_help_command(); register_system(); @@ -171,54 +183,64 @@ void console_start() { #error "Unknown build configuration" #endif register_i2ctools(); - printf("\n" -#if RECOVERY_APPLICATION - "****************************************************************\n" - "RECOVERY APPLICATION\n" - "This mode is used to flash Squeezelite into the OTA partition\n" - "****\n\n" -#endif - "Type 'help' to get the list of commands.\n" - "Use UP/DOWN arrows to navigate through command history.\n" - "Press TAB when typing command name to auto-complete.\n" - "\n" -#if !RECOVERY_APPLICATION - "To automatically execute lines at startup:\n" - "\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n" - "\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n" -#endif - "\n" - "\n"); + if(!is_serial_suppressed()){ + printf("\n" + #if RECOVERY_APPLICATION + "****************************************************************\n" + "RECOVERY APPLICATION\n" + "This mode is used to flash Squeezelite into the OTA partition\n" + "****\n\n" + #endif + "Type 'help' to get the list of commands.\n" + "Use UP/DOWN arrows to navigate through command history.\n" + "Press TAB when typing command name to auto-complete.\n" + "\n" + #if !RECOVERY_APPLICATION + "To automatically execute lines at startup:\n" + "\tSet NVS variable autoexec (U8) = 1 to enable, 0 to disable automatic execution.\n" + "\tSet NVS variable autoexec[1~9] (string)to a command that should be executed automatically\n" + #endif + "\n" + "\n"); - /* Figure out if the terminal supports escape sequences */ - int probe_status = linenoiseProbe(); - if (probe_status) { /* zero indicates success */ - printf("\n****************************\n" - "Your terminal application does not support escape sequences.\n" - "Line editing and history features are disabled.\n" - "On Windows, try using Putty instead.\n" - "****************************\n"); - linenoiseSetDumbMode(1); -#if CONFIG_LOG_COLORS - /* Since the terminal doesn't support escape sequences, - * don't use color codes in the prompt. - */ - prompt = "squeezelite-esp32> "; -#endif //CONFIG_LOG_COLORS + /* Figure out if the terminal supports escape sequences */ + int probe_status = linenoiseProbe(); + if (probe_status) { /* zero indicates success */ + printf("\n****************************\n" + "Your terminal application does not support escape sequences.\n" + "Line editing and history features are disabled.\n" + "On Windows, try using Putty instead.\n" + "****************************\n"); + linenoiseSetDumbMode(1); + #if CONFIG_LOG_COLORS + /* Since the terminal doesn't support escape sequences, + * don't use color codes in the prompt. + */ + prompt = "squeezelite-esp32> "; + #endif //CONFIG_LOG_COLORS + } + + + esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); + cfg.thread_name= "console"; + cfg.inherit_cfg = true; + #if RECOVERY_APPLICATION + cfg.stack_size = 4096 ; + #endif + esp_pthread_set_cfg(&cfg); + pthread_attr_t attr; + pthread_attr_init(&attr); + + pthread_create(&thread_console, &attr, console_thread, NULL); + pthread_attr_destroy(&attr); } - esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); - cfg.thread_name= "console"; - cfg.inherit_cfg = true; -#if RECOVERY_APPLICATION - cfg.stack_size = 4096 ; + else { +#if !RECOVERY_APPLICATION + // process autoexec locally, as we're not going to start the console thread + process_autoexec(); #endif - esp_pthread_set_cfg(&cfg); - pthread_attr_t attr; - pthread_attr_init(&attr); - - pthread_create(&thread_console, &attr, console_thread, NULL); - pthread_attr_destroy(&attr); + } } void run_command(char * line){ /* Try to run the command */ @@ -226,14 +248,14 @@ void run_command(char * line){ esp_err_t err = esp_console_run(line, &ret); if (err == ESP_ERR_NOT_FOUND) { - ESP_LOGE(TAG,"Unrecognized command: %s\n", line); + ESP_LOGE(TAG,"Unrecognized command: %s", line); } else if (err == ESP_ERR_INVALID_ARG) { // command was empty } else if (err == ESP_OK && ret != ESP_OK) { - ESP_LOGW(TAG,"Command returned non-zero error code: 0x%x (%s)\n", ret, + ESP_LOGW(TAG,"Command returned non-zero error code: 0x%x (%s)", ret, esp_err_to_name(err)); } else if (err != ESP_OK) { - ESP_LOGE(TAG,"Internal error: %s\n", esp_err_to_name(err)); + ESP_LOGE(TAG,"Internal error: %s", esp_err_to_name(err)); } } static void * console_thread() { From 055d87ce9dc567e3c5713937bd3850647f6b4184 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Wed, 26 Feb 2020 09:08:14 -0500 Subject: [PATCH 29/46] prevent startup delay from display if i2c is unresponsive - release --- main/esp_app_main.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/main/esp_app_main.c b/main/esp_app_main.c index b9db45bb..1cdaa920 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -341,7 +341,10 @@ void register_default_nvs(){ ESP_LOGD(TAG,"Done setting default values in nvs."); } - +void displayInitCallback(TimerHandle_t pxTimer){ + ESP_LOGD(TAG,"Initializing display"); + display_init("SqueezeESP32"); +} void app_main() { char * fwurl = NULL; @@ -364,10 +367,10 @@ void app_main() ESP_LOGD(TAG,"Configuring services"); services_init(); - - ESP_LOGD(TAG,"Initializing display"); - display_init("SqueezeESP32"); - + // initialize display in a timer thread to prevent locking up + // the main init sequence + TimerHandle_t display_init = xTimerCreate( "DisplInit", 100,pdFALSE,NULL,displayInitCallback); + xTimerStart(display_init, portMAX_DELAY); #if !RECOVERY_APPLICATION ESP_LOGI(TAG,"Checking if certificates need to be updated"); update_certificates(); From 6c256469e99a673996a650d3cd47fa61c729b3a3 Mon Sep 17 00:00:00 2001 From: Christian Herzog Date: Wed, 26 Feb 2020 19:16:46 +0100 Subject: [PATCH 30/46] fix Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 9639bad0..929f00d9 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ PROJECT_NAME?=squeezelite EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main +EXTRA_COMPONENT_DIRS := esp-dsp #/-Wno-error=maybe-uninitialized include $(IDF_PATH)/make/project.mk From 5fcf08e4c51e8b8fc98bffc9212cb5e75562d293 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Wed, 26 Feb 2020 15:56:15 -0500 Subject: [PATCH 31/46] httpd ready for some testing - release --- components/telnet/telnet.c | 30 +++++++++++++++++++----------- main/esp_app_main.c | 23 ++++++++++------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index b9b94f06..0f603ae4 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -47,7 +47,7 @@ #define TELNET_STACK_SIZE 8048 #define TELNET_RX_BUF 1024 -const static char tag[] = "telnet"; +const static char TAG[] = "telnet"; static int uart_fd=0; RingbufHandle_t buf_handle; //static SemaphoreHandle_t xSemaphore = NULL; @@ -56,6 +56,7 @@ static size_t log_buf_size=2000; //32-bit aligned size static bool bIsEnabled=false; static int partnerSocket=0; static telnet_t *tnHandle; +extern bool bypass_wifi_manager; /************************************ * Forward declarations @@ -77,16 +78,23 @@ struct telnetUserData { }; bool is_serial_suppressed(){ - return !bIsEnabled || !bMirrorToUART ; + return bIsEnabled?!bMirrorToUART:false ; } void init_telnet(){ char *val= get_nvs_value_alloc(NVS_TYPE_STR, "telnet_enable"); if (!val || strlen(val) == 0 || !strcasestr("YXD",val) ) { - ESP_LOGI(tag,"Telnet support disabled"); + ESP_LOGI(TAG,"Telnet support disabled"); if(val) free(val); return; } - bMirrorToUART = strcasestr("D",val)!=NULL; + // if wifi manager is bypassed, there will possibly be no wifi available + // + bMirrorToUART = (strcasestr("D",val)!=NULL); + if(!bMirrorToUART && bypass_wifi_manager){ + // This isn't supposed to happen, as telnet won't start if wifi manager isn't + // started. So this is a safeguard only. + ESP_LOGW(TAG,"Wifi manager is not active. Forcing console on Serial output."); + } FREE_AND_NULL(val); val=get_nvs_value_alloc(NVS_TYPE_STR, "telnet_block"); @@ -110,11 +118,11 @@ void init_telnet(){ uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*log_buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT ); buf_handle = xRingbufferCreateStatic(log_buf_size, RINGBUF_TYPE_BYTEBUF, buffer_storage, buffer_struct); if (buf_handle == NULL) { - ESP_LOGE(tag,"Failed to create ring buffer for telnet!"); + ESP_LOGE(TAG,"Failed to create ring buffer for telnet!"); return; } - ESP_LOGI(tag, "***Redirecting log output to telnet"); + ESP_LOGI(TAG, "***Redirecting log output to telnet"); const esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, .write = &stdout_write, @@ -152,14 +160,14 @@ static void telnet_task(void *data) { int rc = bind(serverSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); if (rc < 0) { - ESP_LOGE(tag, "bind: %d (%s)", errno, strerror(errno)); + ESP_LOGE(TAG, "bind: %d (%s)", errno, strerror(errno)); close(serverSocket); return; } rc = listen(serverSocket, 5); if (rc < 0) { - ESP_LOGE(tag, "listen: %d (%s)", errno, strerror(errno)); + ESP_LOGE(TAG, "listen: %d (%s)", errno, strerror(errno)); close(serverSocket); return; } @@ -168,14 +176,14 @@ static void telnet_task(void *data) { socklen_t len = sizeof(serverAddr); rc = accept(serverSocket, (struct sockaddr *)&serverAddr, &len); if (rc < 0 ){ - ESP_LOGE(tag, "accept: %d (%s)", errno, strerror(errno)); + ESP_LOGE(TAG, "accept: %d (%s)", errno, strerror(errno)); return; } else { partnerSocket = rc; - ESP_LOGD(tag, "We have a new client connection!"); + ESP_LOGD(TAG, "We have a new client connection!"); handle_telnet_conn(); - ESP_LOGD(tag, "Telnet connection terminated"); + ESP_LOGD(TAG, "Telnet connection terminated"); } } close(serverSocket); diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 1cdaa920..10234c45 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -154,7 +154,7 @@ esp_err_t update_certificates(){ if ( (esp_err= nvs_get_str(handle, certs_version, NULL, &len)) == ESP_OK) { str=(char *)malloc(len); if ( (esp_err = nvs_get_str(handle, certs_version, str, &len)) == ESP_OK) { - printf("String associated with key '%s' is %s \n", certs_version, str); + ESP_LOGI(TAG,"String associated with key '%s' is %s", certs_version, str); } } if(str!=NULL){ @@ -341,10 +341,7 @@ void register_default_nvs(){ ESP_LOGD(TAG,"Done setting default values in nvs."); } -void displayInitCallback(TimerHandle_t pxTimer){ - ESP_LOGD(TAG,"Initializing display"); - display_init("SqueezeESP32"); -} + void app_main() { char * fwurl = NULL; @@ -360,17 +357,15 @@ void app_main() wifi_event_group = xEventGroupCreate(); ESP_LOGD(TAG,"Clearing CONNECTED_BIT from wifi group"); xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); - ESP_LOGI(TAG,"Registering default values"); register_default_nvs(); - ESP_LOGD(TAG,"Configuring services"); + ESP_LOGI(TAG,"Configuring services"); services_init(); - // initialize display in a timer thread to prevent locking up - // the main init sequence - TimerHandle_t display_init = xTimerCreate( "DisplInit", 100,pdFALSE,NULL,displayInitCallback); - xTimerStart(display_init, portMAX_DELAY); + + ESP_LOGI(TAG,"Initializing display"); + display_init("SqueezeESP32"); #if !RECOVERY_APPLICATION ESP_LOGI(TAG,"Checking if certificates need to be updated"); update_certificates(); @@ -404,10 +399,12 @@ void app_main() led_blink(LED_GREEN, 250, 250); if(bypass_wifi_manager){ - ESP_LOGW(TAG,"\n\nwifi manager is disabled. Please use wifi commands to connect to your wifi access point.\n\n"); + ESP_LOGW(TAG,"*******************************************************************************************"); + ESP_LOGW(TAG,"* wifi manager is disabled. Please use wifi commands to connect to your wifi access point."); + ESP_LOGW(TAG,"*******************************************************************************************"); } else { - ESP_LOGW(TAG,"\n\nwifi manager is ENABLED. Starting...\n\n"); + ESP_LOGI(TAG,"Starting Wifi Manager"); wifi_manager_start(); wifi_manager_set_callback(EVENT_STA_GOT_IP, &cb_connection_got_ip); wifi_manager_set_callback(EVENT_STA_DISCONNECTED, &cb_connection_sta_disconnected); From 59a617a40d7f0289b53f9afcdffade1d2178b6bb Mon Sep 17 00:00:00 2001 From: Sebastien Date: Wed, 26 Feb 2020 23:18:58 -0500 Subject: [PATCH 32/46] merge display updates from master - release --- components/squeezelite-ota/squeezelite-ota.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 8b48e840..734f827c 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -40,7 +40,7 @@ extern const char * get_certificate(); #define OTA_CORE 1 #endif - +static const size_t bin_ota_chunk = 40000; static const char *TAG = "squeezelite-ota"; esp_http_client_handle_t ota_http_client = NULL; #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1 @@ -235,7 +235,7 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ case OTA_TYPE_BUFFER: ota_status.ota_write_data = p_ota_thread_parms->bin; ota_status.total_image_len = p_ota_thread_parms->length; - + ota_status.buffer_size = bin_ota_chunk; break; default: return ESP_FAIL; @@ -418,7 +418,6 @@ void ota_task_cleanup(const char * message, ...){ void ota_task(void *pvParameter) { esp_err_t err = ESP_OK; - size_t buffer_size = BUFFSIZE; ESP_LOGD(TAG, "HTTP ota Thread started"); const esp_partition_t *configured = esp_ota_get_boot_partition(); const esp_partition_t *running = esp_ota_get_running_partition(); @@ -502,8 +501,8 @@ void ota_task(void *pvParameter) data_read = esp_http_client_read(ota_http_client, ota_status.ota_write_data, ota_status.buffer_size); } else { - if(ota_status.remain_image_len >buffer_size){ - data_read = buffer_size; + if(ota_status.remain_image_len >ota_status.buffer_size){ + data_read = ota_status.buffer_size; } else { data_read = ota_status.remain_image_len; } From e550c08273af906b9cdd26626edc50024481c64c Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 27 Feb 2020 17:45:24 -0500 Subject: [PATCH 33/46] leverage displayer to show flash update on display --- components/squeezelite-ota/squeezelite-ota.c | 37 +++++++++++++++++--- components/squeezelite-ota/squeezelite-ota.h | 2 +- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 734f827c..e0fe10c5 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -31,6 +31,7 @@ #include "messaging.h" #include "trace.h" #include "esp_ota_ops.h" +#include "display.h" extern const char * get_certificate(); @@ -40,7 +41,7 @@ extern const char * get_certificate(); #define OTA_CORE 1 #endif -static const size_t bin_ota_chunk = 40000; +static const size_t bin_ota_chunk = 4096*2; static const char *TAG = "squeezelite-ota"; esp_http_client_handle_t ota_http_client = NULL; #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1 @@ -85,7 +86,12 @@ uint8_t ota_get_pct_complete(){ return ota_status.total_image_len==0?0: (uint8_t)((float)ota_status.actual_image_len/(float)ota_status.total_image_len*100.0f); } - +static bool (*display_bus_chain)(void *from, enum display_bus_cmd_e cmd); +static bool display_dummy_handler(void *from, enum display_bus_cmd_e cmd) { + // chain to rest of "bus" + if (display_bus_chain) return (*display_bus_chain)(from, cmd); + else return true; +} void sendMessaging(messaging_types type,const char * fmt, ...){ va_list args; cJSON * msg = cJSON_CreateObject(); @@ -111,7 +117,7 @@ void sendMessaging(messaging_types type,const char * fmt, ...){ } va_end(args); - + displayer_scroll(msg_str, 33); cJSON_AddStringToObject(msg,"ota_dsc",str_or_unknown(msg_str)); free(msg_str); cJSON_AddNumberToObject(msg,"ota_pct", ota_get_pct_complete() ); @@ -121,7 +127,19 @@ void sendMessaging(messaging_types type,const char * fmt, ...){ cJSON_free(msg); _printMemStats(); } - +//esp_err_t decode_alloc_ota_message(single_message_t * message, char * ota_dsc, uint8_t * ota_pct ){ +// if(!message || !message->message) return ESP_ERR_INVALID_ARG; +// cJSON * json = cJSON_Parse(message->message); +// if(!json) return ESP_FAIL; +// if(ota_dsc) { +// ota_dsc = strdup(cJSON_GetObjectItem(json, "ota_dsc")?cJSON_GetStringValue(cJSON_GetObjectItem(json, "ota_dsc")):""); +// } +// if(ota_pct){ +// *ota_pct = cJSON_GetObjectItem(json, "ota_pct")?cJSON_GetObjectItem(json, "ota_pct")->valueint:0; +// } +// cJSON_free(json); +// return ESP_OK; +//} static void __attribute__((noreturn)) task_fatal_error(void) { @@ -413,11 +431,16 @@ void ota_task_cleanup(const char * message, ...){ ota_http_client=NULL; } ota_status.bOTAStarted = false; + displayer_control(DISPLAYER_SHUTDOWN); task_fatal_error(); } + + void ota_task(void *pvParameter) { esp_err_t err = ESP_OK; + displayer_control(DISPLAYER_ACTIVATE, "Firmware update"); + displayer_scroll("Initializing...", 33); ESP_LOGD(TAG, "HTTP ota Thread started"); const esp_partition_t *configured = esp_ota_get_boot_partition(); const esp_partition_t *running = esp_ota_get_running_partition(); @@ -559,11 +582,14 @@ void ota_task(void *pvParameter) ota_status.ota_write_data+= data_read; } ESP_LOGD(TAG, "Written image length %d", ota_status.actual_image_len); + if(ota_get_pct_complete()%5 == 0) ota_status.newpct = ota_get_pct_complete(); if(ota_status.lastpct!=ota_status.newpct ) { + gettimeofday(&tv, NULL); uint32_t elapsed_ms= (tv.tv_sec-ota_status.OTA_start.tv_sec )*1000+(tv.tv_usec-ota_status.OTA_start.tv_usec)/1000; ESP_LOGI(TAG,"OTA progress : %d/%d (%d pct), %d KB/s", ota_status.actual_image_len, ota_status.total_image_len, ota_status.newpct, elapsed_ms>0?ota_status.actual_image_len*1000/elapsed_ms/1024:0); + sendMessaging(MESSAGING_INFO,ota_status.ota_type == OTA_TYPE_HTTP?"Downloading & writing update.":"Writing binary file."); ota_status.lastpct=ota_status.newpct; } @@ -592,6 +618,7 @@ void ota_task(void *pvParameter) if (err == ESP_OK) { ESP_LOGI(TAG,"OTA Process completed successfully!"); sendMessaging(MESSAGING_INFO,"Success!"); + vTaskDelay(1000/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh esp_restart(); } else { @@ -604,6 +631,8 @@ void ota_task(void *pvParameter) esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length){ int ret = 0; + display_bus_chain = display_bus; + display_bus = display_dummy_handler; uint16_t stack_size, task_priority; if(ota_status.bOTAThreadStarted){ ESP_LOGE(TAG,"OTA Already started. "); diff --git a/components/squeezelite-ota/squeezelite-ota.h b/components/squeezelite-ota/squeezelite-ota.h index 8629404f..0d8718e9 100644 --- a/components/squeezelite-ota/squeezelite-ota.h +++ b/components/squeezelite-ota/squeezelite-ota.h @@ -11,6 +11,7 @@ #include "esp_ota_ops.h" #include "sys/param.h" + #if RECOVERY_APPLICATION #define CODE_RAM_LOCATION #define RECOVERY_IRAM_FUNCTION IRAM_ATTR @@ -38,4 +39,3 @@ esp_err_t start_ota(const char * bin_url, char * bin_buffer, uint32_t length); - From 2fadea10b0e984b71bf940b744ee1c0e4516c729 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 27 Feb 2020 21:24:12 -0500 Subject: [PATCH 34/46] add display for OTA progress --- components/squeezelite-ota/squeezelite-ota.c | 7 ++++--- main/console.c | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index e0fe10c5..12b62a68 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -88,7 +88,8 @@ uint8_t ota_get_pct_complete(){ } static bool (*display_bus_chain)(void *from, enum display_bus_cmd_e cmd); static bool display_dummy_handler(void *from, enum display_bus_cmd_e cmd) { - // chain to rest of "bus" + + // Nothing implemented at this point if (display_bus_chain) return (*display_bus_chain)(from, cmd); else return true; } @@ -117,7 +118,7 @@ void sendMessaging(messaging_types type,const char * fmt, ...){ } va_end(args); - displayer_scroll(msg_str, 33); + displayer_scroll(msg_str, 33, 250); cJSON_AddStringToObject(msg,"ota_dsc",str_or_unknown(msg_str)); free(msg_str); cJSON_AddNumberToObject(msg,"ota_pct", ota_get_pct_complete() ); @@ -440,7 +441,7 @@ void ota_task(void *pvParameter) { esp_err_t err = ESP_OK; displayer_control(DISPLAYER_ACTIVATE, "Firmware update"); - displayer_scroll("Initializing...", 33); + displayer_scroll("Initializing...", 33, 250); ESP_LOGD(TAG, "HTTP ota Thread started"); const esp_partition_t *configured = esp_ota_get_boot_partition(); const esp_partition_t *running = esp_ota_get_running_partition(); diff --git a/main/console.c b/main/console.c index 62bc5199..5daa7164 100644 --- a/main/console.c +++ b/main/console.c @@ -26,6 +26,11 @@ #include "console.h" #include "wifi_manager.h" #include "telnet.h" +#include "gds.h" +#include "gds_default_if.h" +#include "gds_draw.h" +#include "gds_text.h" +#include "gds_font.h" #include "cmd_squeezelite.h" #include "config.h" @@ -239,6 +244,9 @@ void console_start() { #if !RECOVERY_APPLICATION // process autoexec locally, as we're not going to start the console thread process_autoexec(); +#else + GDS_ClearExt(display, true); + GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_UPDATE, "Recovery mode"); #endif } } From 439f5b88510efd97638b2900c93974e92d88b3f4 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 27 Feb 2020 21:33:02 -0500 Subject: [PATCH 35/46] tweaking recovery display --- main/console.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/main/console.c b/main/console.c index 5daa7164..6accf459 100644 --- a/main/console.c +++ b/main/console.c @@ -31,7 +31,7 @@ #include "gds_draw.h" #include "gds_text.h" #include "gds_font.h" - +#include "display.h" #include "cmd_squeezelite.h" #include "config.h" pthread_t thread_console; @@ -191,6 +191,7 @@ void console_start() { if(!is_serial_suppressed()){ printf("\n" #if RECOVERY_APPLICATION + "****************************************************************\n" "RECOVERY APPLICATION\n" "This mode is used to flash Squeezelite into the OTA partition\n" @@ -207,7 +208,11 @@ void console_start() { #endif "\n" "\n"); +#if RECOVERY_APPLICATION + GDS_SetFont(display, &Font_droid_sans_fallback_15x17 ); + GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "RECOVERY"); +#endif /* Figure out if the terminal supports escape sequences */ int probe_status = linenoiseProbe(); if (probe_status) { /* zero indicates success */ @@ -244,9 +249,7 @@ void console_start() { #if !RECOVERY_APPLICATION // process autoexec locally, as we're not going to start the console thread process_autoexec(); -#else - GDS_ClearExt(display, true); - GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_UPDATE, "Recovery mode"); + #endif } } From c9998281970fb5cc399eb7aa7ccbcc9a79536171 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 28 Feb 2020 12:29:34 -0500 Subject: [PATCH 36/46] OTA feedback on local display - release --- components/squeezelite-ota/squeezelite-ota.c | 380 ++++++++++++------- main/console.c | 1 + 2 files changed, 235 insertions(+), 146 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 12b62a68..1ca23773 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -32,6 +32,9 @@ #include "trace.h" #include "esp_ota_ops.h" #include "display.h" +#include "gds.h" +#include "gds_text.h" +#include "gds_draw.h" extern const char * get_certificate(); @@ -41,7 +44,6 @@ extern const char * get_certificate(); #define OTA_CORE 1 #endif -static const size_t bin_ota_chunk = 4096*2; static const char *TAG = "squeezelite-ota"; esp_http_client_handle_t ota_http_client = NULL; #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1 @@ -58,20 +60,27 @@ typedef enum { OTA_TYPE_BUFFER, OTA_TYPE_INVALID } ota_type_t; + static struct { uint32_t actual_image_len; uint32_t total_image_len; uint32_t remain_image_len; ota_type_t ota_type; char * ota_write_data; + char * bin_data; bool bOTAStarted; size_t buffer_size; uint8_t lastpct; uint8_t newpct; struct timeval OTA_start; bool bOTAThreadStarted; - + const esp_partition_t *configured; + const esp_partition_t *running; + const esp_partition_t * update_partition; + const esp_partition_t* last_invalid_app ; + const esp_partition_t * ota_partition; } ota_status; + struct timeval tv; static esp_http_client_config_t ota_config; @@ -86,12 +95,66 @@ uint8_t ota_get_pct_complete(){ return ota_status.total_image_len==0?0: (uint8_t)((float)ota_status.actual_image_len/(float)ota_status.total_image_len*100.0f); } -static bool (*display_bus_chain)(void *from, enum display_bus_cmd_e cmd); -static bool display_dummy_handler(void *from, enum display_bus_cmd_e cmd) { +typedef struct { + int x1,y1,x2,y2,width,height; +} rect_t; +typedef struct _progress { + int border_thickness; + int sides_margin; + int vertical_margin; + int bar_tot_height; + int bar_fill_height; + rect_t border; + rect_t filler; +} progress_t; - // Nothing implemented at this point - if (display_bus_chain) return (*display_bus_chain)(from, cmd); - else return true; +static progress_t * loc_displayer_get_progress_dft(){ + int start_coord_offset=0; + static progress_t def={ + .border_thickness = 2, + .sides_margin = 2, + .bar_tot_height = 7, + }; + def.bar_fill_height= def.bar_tot_height-(def.border_thickness*2); + def.border.x1=start_coord_offset+def.sides_margin; + def.border.x2=GDS_GetWidth(display)-def.sides_margin; + // progress bar will be drawn at the bottom of the display + def.border.y2= GDS_GetHeight(display)-def.border_thickness; + def.border.y1= def.border.y2-def.bar_tot_height; + def.border.width=def.border.x2-def.border.x1; + def.border.height=def.border.y2-def.border.y1; + def.filler.x1= def.border.x1+def.border_thickness; + def.filler.x2= def.border.x2-def.border_thickness; + def.filler.y1= def.border.y1+def.border_thickness; + def.filler.y2= def.border.y2-def.border_thickness; + def.filler.width=def.filler.x2-def.filler.x1; + def.filler.height=def.filler.y2-def.filler.y1; + assert(def.filler.width>0); + assert(def.filler.height>0); + assert(def.border.width>0); + assert(def.border.height>0); + assert(def.border.width>def.filler.width); + assert(def.border.height>def.filler.height); + return &def; + +} +static void loc_displayer_progressbar(uint8_t pct){ + static progress_t * progress_coordinates; + if(!progress_coordinates) progress_coordinates = loc_displayer_get_progress_dft(); + int filler_x=progress_coordinates->filler.x1+(int)((float)progress_coordinates->filler.width*(float)pct/(float)100); + + ESP_LOGI(TAG,"Drawing %d,%d,%d,%d",progress_coordinates->border.x1,progress_coordinates->border.y1,progress_coordinates->border.x2,progress_coordinates->border.y2); + GDS_DrawBox(display,progress_coordinates->border.x1,progress_coordinates->border.y1,progress_coordinates->border.x2,progress_coordinates->border.y2,GDS_COLOR_WHITE,false); + ESP_LOGI(TAG,"Drawing %d,%d,%d,%d",progress_coordinates->filler.x1,progress_coordinates->filler.y1,filler_x,progress_coordinates->filler.y2); + if(filler_x > progress_coordinates->filler.x1){ + GDS_DrawBox(display,progress_coordinates->filler.x1,progress_coordinates->filler.y1,filler_x,progress_coordinates->filler.y2,GDS_COLOR_WHITE,true); + } + else { + // Clear the inner box + GDS_DrawBox(display,progress_coordinates->filler.x1,progress_coordinates->filler.y1,progress_coordinates->filler.x2,progress_coordinates->filler.y2,GDS_COLOR_BLACK,true); + } + ESP_LOGI(TAG,"Updating Display"); + GDS_Update(display); } void sendMessaging(messaging_types type,const char * fmt, ...){ va_list args; @@ -117,8 +180,10 @@ void sendMessaging(messaging_types type,const char * fmt, ...){ ESP_LOGW(TAG, "Sending empty string message"); } va_end(args); + if(type!=MESSAGING_INFO){ + GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, msg_str); + } - displayer_scroll(msg_str, 33, 250); cJSON_AddStringToObject(msg,"ota_dsc",str_or_unknown(msg_str)); free(msg_str); cJSON_AddNumberToObject(msg,"ota_pct", ota_get_pct_complete() ); @@ -219,6 +284,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ memset(&ota_config, 0x00, sizeof(ota_config)); sendMessaging(MESSAGING_INFO,"Initializing..."); + loc_displayer_progressbar(0); ota_status.ota_type= OTA_TYPE_INVALID; if(p_ota_thread_parms->url !=NULL && strlen(p_ota_thread_parms->url)>0 ){ ota_status.ota_type= OTA_TYPE_HTTP; @@ -231,30 +297,25 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ ESP_LOGE(TAG,"HTTP OTA called without a url or a binary buffer"); return ESP_ERR_INVALID_ARG; } + ota_status.buffer_size = BUFFSIZE; + ota_status.ota_write_data = heap_caps_malloc(ota_status.buffer_size+1 , (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + if(ota_status.ota_write_data== NULL){ + ESP_LOGE(TAG,"Error allocating the ota buffer"); + return ESP_ERR_NO_MEM; + } switch (ota_status.ota_type) { case OTA_TYPE_HTTP: ota_config.cert_pem =get_certificate(); ota_config.event_handler = _http_event_handler; - ota_config.buffer_size = ota_status.buffer_size; ota_config.disable_auto_redirect=true; ota_config.skip_cert_common_name_check = false; ota_config.url = strdup(p_ota_thread_parms->url); ota_config.max_redirection_count = 3; - - - ota_status.ota_write_data = heap_caps_malloc(ota_status.buffer_size+1 , (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); - - if(ota_status.ota_write_data== NULL){ - ESP_LOGE(TAG,"Error allocating the ota buffer"); - return ESP_ERR_NO_MEM; - } - break; case OTA_TYPE_BUFFER: - ota_status.ota_write_data = p_ota_thread_parms->bin; + ota_status.bin_data = p_ota_thread_parms->bin; ota_status.total_image_len = p_ota_thread_parms->length; - ota_status.buffer_size = bin_ota_chunk; break; default: return ESP_FAIL; @@ -287,7 +348,7 @@ esp_partition_t * _get_ota_partition(esp_partition_subtype_t subtype){ -esp_err_t _erase_last_boot_app_partition(esp_partition_t *ota_partition) +esp_err_t _erase_last_boot_app_partition(const esp_partition_t *ota_partition) { uint16_t num_passes=0; uint16_t remain_size=0; @@ -320,16 +381,19 @@ esp_err_t _erase_last_boot_app_partition(esp_partition_t *ota_partition) err=esp_partition_erase_range(ota_partition, i*single_pass_size, single_pass_size); if(err!=ESP_OK) return err; if(i%2) { + loc_displayer_progressbar((int)(((float)i/(float)num_passes)*100.0f)); sendMessaging(MESSAGING_INFO,"Erasing flash (%u/%u)",i,num_passes); } vTaskDelay(100/ portTICK_PERIOD_MS); // wait here for a short amount of time. This will help with reducing WDT errors } if(remain_size>0){ err=esp_partition_erase_range(ota_partition, ota_partition->size-remain_size, remain_size); + if(err!=ESP_OK) return err; } sendMessaging(MESSAGING_INFO,"Erasing flash complete."); - + loc_displayer_progressbar(100); + vTaskDelay(200/ portTICK_PERIOD_MS); return ESP_OK; } @@ -418,42 +482,135 @@ static esp_err_t _http_connect(esp_http_client_handle_t http_client) } void ota_task_cleanup(const char * message, ...){ ota_status.bOTAThreadStarted=false; + loc_displayer_progressbar(0); if(message!=NULL){ va_list args; va_start(args, message); sendMessaging(MESSAGING_ERROR,message, args); va_end(args); } - if(ota_status.ota_type == OTA_TYPE_HTTP){ - FREE_RESET(ota_status.ota_write_data); - } + FREE_RESET(ota_status.ota_write_data); + FREE_RESET(ota_status.bin_data); if(ota_http_client!=NULL) { esp_http_client_cleanup(ota_http_client); ota_http_client=NULL; } ota_status.bOTAStarted = false; - displayer_control(DISPLAYER_SHUTDOWN); task_fatal_error(); } +esp_err_t ota_buffer_all(){ + int data_read=0; + esp_err_t err=ESP_OK; + if (ota_status.ota_type == OTA_TYPE_HTTP){ + GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Downloading file"); + ota_http_client = esp_http_client_init(&ota_config); + if (ota_http_client == NULL) { + sendMessaging(MESSAGING_ERROR,"Error: Failed to initialize HTTP connection."); + return ESP_FAIL; + } + _printMemStats(); + // Open the http connection and follow any redirection + err = _http_connect(ota_http_client); + if (err != ESP_OK) { + sendMessaging(MESSAGING_ERROR,"Error: HTTP Start read failed. (%s)",esp_err_to_name(err)); + return err; + } + if(ota_status.total_image_len<=0){ + sendMessaging(MESSAGING_ERROR,"Error: Invalid image length"); + return ESP_FAIL; + } + ota_status.bin_data= malloc(ota_status.total_image_len); + if(ota_status.bin_data==NULL){ + sendMessaging(MESSAGING_ERROR,"Error: buffer alloc error"); + return ESP_FAIL; + } + data_read = esp_http_client_read(ota_http_client, ota_status.bin_data, ota_status.total_image_len); + if(data_read != ota_status.total_image_len){ + sendMessaging(MESSAGING_ERROR,"Error: Binary incomplete"); + return ESP_FAIL; + } + } + else { + gettimeofday(&ota_status.OTA_start, NULL); + } + ota_status.remain_image_len=ota_status.total_image_len; + return err; +} +int ota_buffer_read(){ + int data_read=0; + if(ota_status.remain_image_len >ota_status.buffer_size){ + data_read = ota_status.buffer_size; + } else { + data_read = ota_status.remain_image_len; + } + memcpy(ota_status.ota_write_data, &ota_status.bin_data[ota_status.actual_image_len], data_read); + + ota_status.actual_image_len += data_read; + ota_status.remain_image_len -= data_read; + return data_read; +} +esp_err_t ota_header_check(){ + esp_app_desc_t new_app_info; + esp_app_desc_t running_app_info; + + ota_status.configured = esp_ota_get_boot_partition(); + ota_status.running = esp_ota_get_running_partition(); + ota_status.update_partition = esp_ota_get_next_update_partition(NULL); + ota_status.last_invalid_app= esp_ota_get_last_invalid_partition(); + ota_status.ota_partition = _get_ota_partition(ESP_PARTITION_SUBTYPE_APP_OTA_0); + + ESP_LOGI(TAG, "Running partition [%s] type %d subtype %d (offset 0x%08x)", ota_status.running->label, ota_status.running->type, ota_status.running->subtype, ota_status.running->address); + if (ota_status.total_image_len > ota_status.ota_partition->size){ + ota_task_cleanup("Error: Image size too large to fit in partition."); + return ESP_FAIL; + } + if(ota_status.ota_partition == NULL){ + ESP_LOGE(TAG,"Unable to locate OTA application partition. "); + ota_task_cleanup("Error: OTA partition not found"); + return ESP_FAIL; + } + if (ota_status.configured != ota_status.running) { + ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x", ota_status.configured->address, ota_status.running->address); + ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)"); + } + ESP_LOGI(TAG, "Next ota update partition is: [%s] subtype %d at offset 0x%x", + ota_status.update_partition->label, ota_status.update_partition->subtype, ota_status.update_partition->address); + + if (ota_status.total_image_len >= IMAGE_HEADER_SIZE) { + // check current version with downloading + memcpy(&new_app_info, &ota_status.bin_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); + ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); + if (esp_ota_get_partition_description(ota_status.running, &running_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Running recovery version: %s", running_app_info.version); + } + + esp_app_desc_t invalid_app_info; + if (esp_ota_get_partition_description(ota_status.last_invalid_app, &invalid_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version); + } + + if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) { + ESP_LOGW(TAG, "Current running version is the same as a new."); + } + return ESP_OK; + } + else{ + ota_task_cleanup("Error: Binary file too small"); + } + return ESP_FAIL; +} void ota_task(void *pvParameter) { esp_err_t err = ESP_OK; - displayer_control(DISPLAYER_ACTIVATE, "Firmware update"); - displayer_scroll("Initializing...", 33, 250); + int data_read = 0; + GDS_TextSetFont(display,2,&Font_droid_sans_fallback_15x17,-2); + GDS_ClearExt(display, true); + GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Firmware update"); + GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Initializing"); + loc_displayer_progressbar(0); ESP_LOGD(TAG, "HTTP ota Thread started"); - const esp_partition_t *configured = esp_ota_get_boot_partition(); - const esp_partition_t *running = esp_ota_get_running_partition(); - const esp_partition_t * update_partition = esp_ota_get_next_update_partition(NULL); - ESP_LOGI(TAG, "esp_ota_get_next_update_partition returned : partition [%s] subtype %d at offset 0x%x", - update_partition->label, update_partition->subtype, update_partition->address); - - if (configured != running) { - ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x", configured->address, running->address); - ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)"); - } - ESP_LOGI(TAG, "Running partition [%s] type %d subtype %d (offset 0x%08x)", running->label, running->type, running->subtype, running->address); _printMemStats(); @@ -464,134 +621,66 @@ void ota_task(void *pvParameter) return; } + _printMemStats(); + ota_status.bOTAStarted = true; + sendMessaging(MESSAGING_INFO,"Starting OTA..."); + err=ota_buffer_all(); + if(err!=ESP_OK){ + ota_task_cleanup(NULL); + return; + } + + + if(ota_header_check()!=ESP_OK){ + ota_task_cleanup(NULL); + return; + } + /* Locate and erase ota application partition */ ESP_LOGW(TAG,"**************** Expecting WATCHDOG errors below during flash erase. This is OK and not to worry about **************** "); - sendMessaging(MESSAGING_INFO,"Erasing OTA partition"); - esp_partition_t *ota_partition = _get_ota_partition(ESP_PARTITION_SUBTYPE_APP_OTA_0); - if(ota_partition == NULL){ - ESP_LOGE(TAG,"Unable to locate OTA application partition. "); - ota_task_cleanup("Error: OTA application partition not found. (%s)",esp_err_to_name(err)); - return; - } - if(ota_status.ota_type == OTA_TYPE_BUFFER){ - if(ota_status.total_image_len > ota_partition->size){ - ota_task_cleanup("Error: Image size too large to fit in partition."); - return; - } - } + GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Formatting partition"); + sendMessaging(MESSAGING_INFO,"Formatting OTA partition"); _printMemStats(); - err=_erase_last_boot_app_partition(ota_partition); + err=_erase_last_boot_app_partition(ota_status.ota_partition); if(err!=ESP_OK){ ota_task_cleanup("Error: Unable to erase last APP partition. (%s)",esp_err_to_name(err)); return; } - - _printMemStats(); - ota_status.bOTAStarted = true; - sendMessaging(MESSAGING_INFO,"Starting OTA..."); - if (ota_status.ota_type == OTA_TYPE_HTTP){ - ota_http_client = esp_http_client_init(&ota_config); - if (ota_http_client == NULL) { - ota_task_cleanup("Error: Failed to initialize HTTP connection."); - return; - } - _printMemStats(); - // Open the http connection and follow any redirection - err = _http_connect(ota_http_client); - if (err != ESP_OK) { - ota_task_cleanup("Error: HTTP Start read failed. (%s)",esp_err_to_name(err)); - return; - } - } - else { - gettimeofday(&ota_status.OTA_start, NULL); - } + loc_displayer_progressbar(0); _printMemStats(); + + // Call OTA Begin with a small partition size - this minimizes the time spent in erasing partition, + // which was already done above esp_ota_handle_t update_handle = 0 ; - /*deal with all receive packet*/ - bool image_header_was_checked = false; - int data_read = 0; - if (ota_status.ota_type == OTA_TYPE_HTTP && ota_status.total_image_len > ota_partition->size){ - ota_task_cleanup("Error: Image size too large to fit in partition."); - return; + err = esp_ota_begin(ota_status.ota_partition, 512, &update_handle); + if (err != ESP_OK) { + ota_task_cleanup("esp_ota_begin failed (%s)", esp_err_to_name(err)); + return; } + ESP_LOGD(TAG, "esp_ota_begin succeeded"); + GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Writing image..."); + while (ota_status.remain_image_len>0) { - while (1) { - ota_status.remain_image_len =ota_status.total_image_len -ota_status.actual_image_len; - - if (ota_status.ota_type == OTA_TYPE_HTTP){ - - data_read = esp_http_client_read(ota_http_client, ota_status.ota_write_data, ota_status.buffer_size); - } - else { - if(ota_status.remain_image_len >ota_status.buffer_size){ - data_read = ota_status.buffer_size; - } else { - data_read = ota_status.remain_image_len; - } - } - if (data_read < 0) { + data_read = ota_buffer_read(); + if (data_read <= 0) { ota_task_cleanup("Error: Data read error"); return; } else if (data_read > 0) { - if (image_header_was_checked == false) { - esp_app_desc_t new_app_info; - if (data_read >= IMAGE_HEADER_SIZE) { - // check current version with downloading - memcpy(&new_app_info, &ota_status.ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t)); - ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version); - - esp_app_desc_t running_app_info; - if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) { - ESP_LOGI(TAG, "Running recovery version: %s", running_app_info.version); - } - - const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition(); - esp_app_desc_t invalid_app_info; - if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) { - ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version); - } - - if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) { - ESP_LOGW(TAG, "Current running version is the same as a new."); - } - - image_header_was_checked = true; - // Call OTA Begin with a small partition size - this drives the erase operation which was already done; - err = esp_ota_begin(ota_partition, 512, &update_handle); - if (err != ESP_OK) { - ota_task_cleanup("esp_ota_begin failed (%s)", esp_err_to_name(err)); - return; - } - ESP_LOGD(TAG, "esp_ota_begin succeeded"); - } - else { - ota_task_cleanup("Error: Increase ota http buffer."); - return; - } - } - err = esp_ota_write( update_handle, (const void *)ota_status.ota_write_data, data_read); if (err != ESP_OK) { ota_task_cleanup("Error: OTA Partition write failure. (%s)",esp_err_to_name(err)); return; } - ota_status.actual_image_len += data_read; - if(ota_status.ota_type == OTA_TYPE_BUFFER){ - // position the ota buffer in the next buffer chunk - ota_status.ota_write_data+= data_read; - } ESP_LOGD(TAG, "Written image length %d", ota_status.actual_image_len); if(ota_get_pct_complete()%5 == 0) ota_status.newpct = ota_get_pct_complete(); if(ota_status.lastpct!=ota_status.newpct ) { - + loc_displayer_progressbar(ota_status.newpct); gettimeofday(&tv, NULL); uint32_t elapsed_ms= (tv.tv_sec-ota_status.OTA_start.tv_sec )*1000+(tv.tv_usec-ota_status.OTA_start.tv_usec)/1000; ESP_LOGI(TAG,"OTA progress : %d/%d (%d pct), %d KB/s", ota_status.actual_image_len, ota_status.total_image_len, ota_status.newpct, elapsed_ms>0?ota_status.actual_image_len*1000/elapsed_ms/1024:0); - - sendMessaging(MESSAGING_INFO,ota_status.ota_type == OTA_TYPE_HTTP?"Downloading & writing update.":"Writing binary file."); + sendMessaging(MESSAGING_INFO,"Writing binary file."); ota_status.lastpct=ota_status.newpct; } taskYIELD(); @@ -608,19 +697,20 @@ void ota_task(void *pvParameter) return; } _printMemStats(); - + loc_displayer_progressbar(100); err = esp_ota_end(update_handle); if (err != ESP_OK) { ota_task_cleanup("Error: %s",esp_err_to_name(err)); return; } _printMemStats(); - err = esp_ota_set_boot_partition(ota_partition); + err = esp_ota_set_boot_partition(ota_status.ota_partition); if (err == ESP_OK) { ESP_LOGI(TAG,"OTA Process completed successfully!"); sendMessaging(MESSAGING_INFO,"Success!"); - - vTaskDelay(1000/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh + GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Success!"); + vTaskDelay(1500/ portTICK_PERIOD_MS); // wait here to give the UI a chance to refresh + GDS_Clear(display,GDS_COLOR_BLACK); esp_restart(); } else { ota_task_cleanup("Error: Unable to update boot partition [%s]",esp_err_to_name(err)); @@ -632,8 +722,6 @@ void ota_task(void *pvParameter) esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length){ int ret = 0; - display_bus_chain = display_bus; - display_bus = display_dummy_handler; uint16_t stack_size, task_priority; if(ota_status.bOTAThreadStarted){ ESP_LOGE(TAG,"OTA Already started. "); diff --git a/main/console.c b/main/console.c index 6accf459..8f037fe1 100644 --- a/main/console.c +++ b/main/console.c @@ -209,6 +209,7 @@ void console_start() { "\n" "\n"); #if RECOVERY_APPLICATION + GDS_ClearExt(display, true); GDS_SetFont(display, &Font_droid_sans_fallback_15x17 ); GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "RECOVERY"); From a690b177ca702d750263114eed8759756537a915 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Sat, 29 Feb 2020 08:41:28 -0500 Subject: [PATCH 37/46] http ota buffer length fix - release --- components/squeezelite-ota/squeezelite-ota.c | 25 ++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 1ca23773..0f35e13d 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -47,7 +47,7 @@ extern const char * get_certificate(); static const char *TAG = "squeezelite-ota"; esp_http_client_handle_t ota_http_client = NULL; #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1 -#define BUFFSIZE 2048 +#define BUFFSIZE 4096 #define HASH_LEN 32 /* SHA-256 digest length */ typedef struct { char * url; @@ -68,6 +68,7 @@ static struct { ota_type_t ota_type; char * ota_write_data; char * bin_data; + char * http_client_write_buf; bool bOTAStarted; size_t buffer_size; uint8_t lastpct; @@ -312,6 +313,7 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ ota_config.skip_cert_common_name_check = false; ota_config.url = strdup(p_ota_thread_parms->url); ota_config.max_redirection_count = 3; + ota_config.buffer_size = ota_status.buffer_size; break; case OTA_TYPE_BUFFER: ota_status.bin_data = p_ota_thread_parms->bin; @@ -435,14 +437,14 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client return ESP_ERR_NO_MEM; } while (1) { - ESP_LOGD(TAG, "Buffer successfully allocated. Reading data chunk. "); + ESP_LOGI(TAG, "Buffer successfully allocated. Reading data chunk. "); int data_read = esp_http_client_read(http_client, local_buff, ota_status.buffer_size); if (data_read < 0) { ESP_LOGE(TAG, "Error: SSL data read error"); err= ESP_FAIL; break; } else if (data_read == 0) { - ESP_LOGD(TAG, "No more data. "); + ESP_LOGI(TAG, "No more data. "); err= ESP_OK; break; } @@ -457,27 +459,37 @@ static esp_err_t _http_connect(esp_http_client_handle_t http_client) esp_err_t err = ESP_FAIL; int status_code, header_ret; do { - ESP_LOGD(TAG, "connecting the http client. "); + ESP_LOGI(TAG, "connecting the http client. "); err = esp_http_client_open(http_client, 0); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); + sendMessaging(MESSAGING_ERROR,"Failed to open HTTP connection: %s", esp_err_to_name(err)); return err; } - ESP_LOGD(TAG, "Fetching headers"); + ESP_LOGI(TAG, "Fetching headers"); header_ret = esp_http_client_fetch_headers(http_client); if (header_ret < 0) { // Error found + sendMessaging(MESSAGING_ERROR,"Header fetch failed"); return header_ret; } - ESP_LOGD(TAG, "HTTP Header fetch completed, found content length of %d",header_ret); + ESP_LOGI(TAG, "HTTP Header fetch completed, found content length of %d",header_ret); status_code = esp_http_client_get_status_code(http_client); ESP_LOGD(TAG, "HTTP status code was %d",status_code); err = _http_handle_response_code(http_client, status_code); if (err != ESP_OK) { + sendMessaging(MESSAGING_ERROR,"HTTP connect error: %s", esp_err_to_name(err)); return err; } + } while (process_again(status_code)); + + if(status_code >=400 && status_code <=900){ + sendMessaging(MESSAGING_ERROR,"Error: HTTP Status %d",status_code); + err=ESP_FAIL; + } + return err; } void ota_task_cleanup(const char * message, ...){ @@ -512,7 +524,6 @@ esp_err_t ota_buffer_all(){ // Open the http connection and follow any redirection err = _http_connect(ota_http_client); if (err != ESP_OK) { - sendMessaging(MESSAGING_ERROR,"Error: HTTP Start read failed. (%s)",esp_err_to_name(err)); return err; } if(ota_status.total_image_len<=0){ From e2d77684e3e8c1bdccfdd9175c8236a67497037d Mon Sep 17 00:00:00 2001 From: Sebastien Date: Sat, 29 Feb 2020 08:45:19 -0500 Subject: [PATCH 38/46] HTTP and Binary upload ota work - release decrease logging verbosity on low level messages merging with master branch correcting buffer size for better OTA redirection/http header parsing --- components/squeezelite-ota/squeezelite-ota.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 0f35e13d..e99f2e71 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -144,9 +144,9 @@ static void loc_displayer_progressbar(uint8_t pct){ if(!progress_coordinates) progress_coordinates = loc_displayer_get_progress_dft(); int filler_x=progress_coordinates->filler.x1+(int)((float)progress_coordinates->filler.width*(float)pct/(float)100); - ESP_LOGI(TAG,"Drawing %d,%d,%d,%d",progress_coordinates->border.x1,progress_coordinates->border.y1,progress_coordinates->border.x2,progress_coordinates->border.y2); + ESP_LOGD(TAG,"Drawing %d,%d,%d,%d",progress_coordinates->border.x1,progress_coordinates->border.y1,progress_coordinates->border.x2,progress_coordinates->border.y2); GDS_DrawBox(display,progress_coordinates->border.x1,progress_coordinates->border.y1,progress_coordinates->border.x2,progress_coordinates->border.y2,GDS_COLOR_WHITE,false); - ESP_LOGI(TAG,"Drawing %d,%d,%d,%d",progress_coordinates->filler.x1,progress_coordinates->filler.y1,filler_x,progress_coordinates->filler.y2); + ESP_LOGD(TAG,"Drawing %d,%d,%d,%d",progress_coordinates->filler.x1,progress_coordinates->filler.y1,filler_x,progress_coordinates->filler.y2); if(filler_x > progress_coordinates->filler.x1){ GDS_DrawBox(display,progress_coordinates->filler.x1,progress_coordinates->filler.y1,filler_x,progress_coordinates->filler.y2,GDS_COLOR_WHITE,true); } @@ -154,7 +154,7 @@ static void loc_displayer_progressbar(uint8_t pct){ // Clear the inner box GDS_DrawBox(display,progress_coordinates->filler.x1,progress_coordinates->filler.y1,progress_coordinates->filler.x2,progress_coordinates->filler.y2,GDS_COLOR_BLACK,true); } - ESP_LOGI(TAG,"Updating Display"); + ESP_LOGD(TAG,"Updating Display"); GDS_Update(display); } void sendMessaging(messaging_types type,const char * fmt, ...){ @@ -437,14 +437,14 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client return ESP_ERR_NO_MEM; } while (1) { - ESP_LOGI(TAG, "Buffer successfully allocated. Reading data chunk. "); + ESP_LOGD(TAG, "Buffer successfully allocated. Reading data chunk. "); int data_read = esp_http_client_read(http_client, local_buff, ota_status.buffer_size); if (data_read < 0) { ESP_LOGE(TAG, "Error: SSL data read error"); err= ESP_FAIL; break; } else if (data_read == 0) { - ESP_LOGI(TAG, "No more data. "); + ESP_LOGD(TAG, "No more data. "); err= ESP_OK; break; } @@ -459,21 +459,21 @@ static esp_err_t _http_connect(esp_http_client_handle_t http_client) esp_err_t err = ESP_FAIL; int status_code, header_ret; do { - ESP_LOGI(TAG, "connecting the http client. "); + ESP_LOGD(TAG, "connecting the http client. "); err = esp_http_client_open(http_client, 0); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); sendMessaging(MESSAGING_ERROR,"Failed to open HTTP connection: %s", esp_err_to_name(err)); return err; } - ESP_LOGI(TAG, "Fetching headers"); + ESP_LOGD(TAG, "Fetching headers"); header_ret = esp_http_client_fetch_headers(http_client); if (header_ret < 0) { // Error found sendMessaging(MESSAGING_ERROR,"Header fetch failed"); return header_ret; } - ESP_LOGI(TAG, "HTTP Header fetch completed, found content length of %d",header_ret); + ESP_LOGD(TAG, "HTTP Header fetch completed, found content length of %d",header_ret); status_code = esp_http_client_get_status_code(http_client); ESP_LOGD(TAG, "HTTP status code was %d",status_code); From 4944210ef1f610776b38792fd51950dc6c8a2bf8 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Sat, 29 Feb 2020 09:41:13 -0500 Subject: [PATCH 39/46] buffering fix on http OTA - release --- components/squeezelite-ota/squeezelite-ota.c | 47 ++++++++++---------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index e99f2e71..6202c051 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -68,7 +68,6 @@ static struct { ota_type_t ota_type; char * ota_write_data; char * bin_data; - char * http_client_write_buf; bool bOTAStarted; size_t buffer_size; uint8_t lastpct; @@ -83,7 +82,7 @@ static struct { } ota_status; struct timeval tv; -static esp_http_client_config_t ota_config; +static esp_http_client_config_t http_client_config; void _printMemStats(){ ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)", @@ -283,7 +282,7 @@ esp_err_t _http_event_handler(esp_http_client_event_t *evt) } esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ - memset(&ota_config, 0x00, sizeof(ota_config)); + memset(&http_client_config, 0x00, sizeof(http_client_config)); sendMessaging(MESSAGING_INFO,"Initializing..."); loc_displayer_progressbar(0); ota_status.ota_type= OTA_TYPE_INVALID; @@ -307,13 +306,14 @@ esp_err_t init_config(ota_thread_parms_t * p_ota_thread_parms){ } switch (ota_status.ota_type) { case OTA_TYPE_HTTP: - ota_config.cert_pem =get_certificate(); - ota_config.event_handler = _http_event_handler; - ota_config.disable_auto_redirect=true; - ota_config.skip_cert_common_name_check = false; - ota_config.url = strdup(p_ota_thread_parms->url); - ota_config.max_redirection_count = 3; - ota_config.buffer_size = ota_status.buffer_size; + http_client_config.cert_pem =get_certificate(); + http_client_config.event_handler = _http_event_handler; + http_client_config.disable_auto_redirect=true; + http_client_config.skip_cert_common_name_check = false; + http_client_config.url = strdup(p_ota_thread_parms->url); + http_client_config.max_redirection_count = 3; + // buffer size below is for http read chunks + http_client_config.buffer_size = 1024 ; break; case OTA_TYPE_BUFFER: ota_status.bin_data = p_ota_thread_parms->bin; @@ -430,15 +430,16 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client ESP_LOGD(TAG, "Redirection done, checking if we need to read the data. "); if (process_again(status_code)) { //ESP_LOGD(TAG, "We have to read some more data. Allocating buffer size %u",ota_config.buffer_size+1); - char * local_buff = heap_caps_malloc(ota_status.buffer_size+1, (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + //char * local_buff = heap_caps_malloc(ota_status.buffer_size+1, (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + +// if(local_buff==NULL){ +// ESP_LOGE(TAG,"Failed to allocate internal memory buffer for http processing"); +// return ESP_ERR_NO_MEM; +// } - if(local_buff==NULL){ - ESP_LOGE(TAG,"Failed to allocate internal memory buffer for http processing"); - return ESP_ERR_NO_MEM; - } while (1) { - ESP_LOGD(TAG, "Buffer successfully allocated. Reading data chunk. "); - int data_read = esp_http_client_read(http_client, local_buff, ota_status.buffer_size); + ESP_LOGD(TAG, "Reading data chunk. "); + int data_read = esp_http_client_read(http_client, ota_status.ota_write_data, ota_status.buffer_size); if (data_read < 0) { ESP_LOGE(TAG, "Error: SSL data read error"); err= ESP_FAIL; @@ -449,7 +450,7 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client break; } } - FREE_RESET(local_buff); + //FREE_RESET(local_buff); } return err; @@ -459,21 +460,21 @@ static esp_err_t _http_connect(esp_http_client_handle_t http_client) esp_err_t err = ESP_FAIL; int status_code, header_ret; do { - ESP_LOGD(TAG, "connecting the http client. "); + ESP_LOGI(TAG, "connecting the http client. "); err = esp_http_client_open(http_client, 0); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); sendMessaging(MESSAGING_ERROR,"Failed to open HTTP connection: %s", esp_err_to_name(err)); return err; } - ESP_LOGD(TAG, "Fetching headers"); + ESP_LOGI(TAG, "Fetching headers"); header_ret = esp_http_client_fetch_headers(http_client); if (header_ret < 0) { // Error found sendMessaging(MESSAGING_ERROR,"Header fetch failed"); return header_ret; } - ESP_LOGD(TAG, "HTTP Header fetch completed, found content length of %d",header_ret); + ESP_LOGI(TAG, "HTTP Header fetch completed, found content length of %d",header_ret); status_code = esp_http_client_get_status_code(http_client); ESP_LOGD(TAG, "HTTP status code was %d",status_code); @@ -515,7 +516,7 @@ esp_err_t ota_buffer_all(){ esp_err_t err=ESP_OK; if (ota_status.ota_type == OTA_TYPE_HTTP){ GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Downloading file"); - ota_http_client = esp_http_client_init(&ota_config); + ota_http_client = esp_http_client_init(&http_client_config); if (ota_http_client == NULL) { sendMessaging(MESSAGING_ERROR,"Error: Failed to initialize HTTP connection."); return ESP_FAIL; @@ -567,7 +568,6 @@ esp_err_t ota_header_check(){ ota_status.configured = esp_ota_get_boot_partition(); ota_status.running = esp_ota_get_running_partition(); - ota_status.update_partition = esp_ota_get_next_update_partition(NULL); ota_status.last_invalid_app= esp_ota_get_last_invalid_partition(); ota_status.ota_partition = _get_ota_partition(ESP_PARTITION_SUBTYPE_APP_OTA_0); @@ -624,6 +624,7 @@ void ota_task(void *pvParameter) ESP_LOGD(TAG, "HTTP ota Thread started"); _printMemStats(); + ota_status.update_partition = esp_ota_get_next_update_partition(NULL); ESP_LOGI(TAG,"Initializing OTA configuration"); err = init_config(pvParameter); From 5ab1f04ea534e541dfbbc601f2f98fc6ff82d8b2 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Mon, 2 Mar 2020 18:03:47 -0500 Subject: [PATCH 40/46] taming the memory monster --- Makefile | 2 +- components/cmd_system/cmd_system.c | 16 +- components/services/messaging.c | 58 +-- components/services/messaging.h | 6 +- components/services/monitor.c | 42 +- components/squeezelite-ota/squeezelite-ota.c | 2 +- components/telnet/telnet.c | 2 +- components/wifi-manager/_esp_http_server.h | 93 +++++ components/wifi-manager/_esp_httpd_main.c | 373 ++++++++++++++++++ components/wifi-manager/code.js | 21 +- components/wifi-manager/component.mk | 2 +- .../wifi-manager/wifi_manager_http_server.c | 4 +- main/CMakeLists.txt | 2 +- main/component.mk | 2 +- main/esp_app_main.c | 4 + 15 files changed, 583 insertions(+), 46 deletions(-) create mode 100644 components/wifi-manager/_esp_http_server.h create mode 100644 components/wifi-manager/_esp_httpd_main.c diff --git a/Makefile b/Makefile index 9639bad0..bfbb0778 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ #recovery: EXTRA_CPPFLAGS+=-DRECOVERY_APPLICATION=1 PROJECT_NAME?=squeezelite -EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main +EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main -I$(IDF_PATH)/components/esp_http_server/src -I$(IDF_PATH)/components/esp_http_server/src/port/esp32 -I$(IDF_PATH)/components/esp_http_server/src/util #/-Wno-error=maybe-uninitialized include $(IDF_PATH)/make/project.mk diff --git a/components/cmd_system/cmd_system.c b/components/cmd_system/cmd_system.c index dd452e41..7e9dc015 100644 --- a/components/cmd_system/cmd_system.c +++ b/components/cmd_system/cmd_system.c @@ -106,8 +106,7 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) if(!wait_for_commit()){ ESP_LOGW(TAG,"Unable to commit configuration. "); } - ESP_LOGW(TAG, "Restarting after tx complete"); - uart_wait_tx_done(UART_NUM_1, 500 / portTICK_RATE_MS); + vTaskDelay(750/ portTICK_PERIOD_MS); esp_restart(); return ESP_OK; } @@ -117,8 +116,7 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) if(!wait_for_commit()){ ESP_LOGW(TAG,"Unable to commit configuration. "); } - ESP_LOGW(TAG, "Restarting after tx complete"); - uart_wait_tx_done(UART_NUM_1, 500 / portTICK_RATE_MS); + vTaskDelay(750/ portTICK_PERIOD_MS); esp_restart(); return ESP_OK; } @@ -166,8 +164,7 @@ esp_err_t guided_boot(esp_partition_subtype_t partition_subtype) if(!wait_for_commit()){ ESP_LOGW(TAG,"Unable to commit configuration. "); } - ESP_LOGW(TAG, "Restarting after tx complete"); - uart_wait_tx_done(UART_NUM_1, 500 / portTICK_RATE_MS); + vTaskDelay(750/ portTICK_PERIOD_MS); esp_restart(); } } @@ -181,8 +178,7 @@ static int restart(int argc, char **argv) if(!wait_for_commit()){ ESP_LOGW(TAG,"Unable to commit configuration. "); } - ESP_LOGW(TAG, "Restarting after tx complete"); - uart_wait_tx_done(UART_NUM_1, 500 / portTICK_RATE_MS); + vTaskDelay(750/ portTICK_PERIOD_MS); esp_restart(); return 0; } @@ -193,9 +189,7 @@ void simple_restart() if(!wait_for_commit()){ ESP_LOGW(TAG,"Unable to commit configuration. "); } - - ESP_LOGW(TAG, "Restarting after tx complete"); - uart_wait_tx_done(UART_NUM_1, 500 / portTICK_RATE_MS); + vTaskDelay(750/ portTICK_PERIOD_MS); esp_restart(); } diff --git a/components/services/messaging.c b/components/services/messaging.c index f8841baa..3d1d9ff6 100644 --- a/components/services/messaging.c +++ b/components/services/messaging.c @@ -27,7 +27,7 @@ typedef struct { RingbufHandle_t buf_handle; } messaging_list_t; static messaging_list_t top; - +#define MSG_LENGTH_AVG 201 messaging_list_t * get_struct_ptr(messaging_handle_t handle){ return (messaging_list_t *)handle; @@ -35,12 +35,14 @@ messaging_list_t * get_struct_ptr(messaging_handle_t handle){ messaging_handle_t get_handle_ptr(messaging_list_t * handle){ return (messaging_handle_t )handle; } + RingbufHandle_t messaging_create_ring_buffer(uint8_t max_count){ RingbufHandle_t buf_handle = NULL; StaticRingbuffer_t *buffer_struct = malloc(sizeof(StaticRingbuffer_t)); if (buffer_struct != NULL) { - size_t buf_size = (size_t )(sizeof(single_message_t)+8)*(size_t )(max_count>0?max_count:5); // no-split buffer requires an additional 8 bytes - uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + size_t buf_size = (size_t )(sizeof(single_message_t)+8+MSG_LENGTH_AVG)*(size_t )(max_count>0?max_count:5); // no-split buffer requires an additional 8 bytes + buf_size = buf_size - (buf_size % 4); + uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_32BIT); if (buffer_storage== NULL) { ESP_LOGE(tag,"buff alloc failed"); } @@ -62,9 +64,9 @@ void messaging_fill_messages(messaging_list_t * target_subscriber){ message= messaging_retrieve_message(top.buf_handle); if(message){ //re-post to original queue so it is available to future subscribers - messaging_post_to_queue(get_handle_ptr(&top), message, sizeof(single_message_t)); + messaging_post_to_queue(get_handle_ptr(&top), message, message->msg_size); // post to new subscriber - messaging_post_to_queue(get_handle_ptr(target_subscriber) , message, sizeof(single_message_t)); + messaging_post_to_queue(get_handle_ptr(target_subscriber) , message, message->msg_size); FREE_AND_NULL(message); } } @@ -116,6 +118,7 @@ const char * messaging_get_class_desc(messaging_classes msg_class){ switch (msg_class) { CASE_TO_STR(MESSAGING_CLASS_OTA); CASE_TO_STR(MESSAGING_CLASS_SYSTEM); + CASE_TO_STR(MESSAGING_CLASS_STATS); default: return "Unknown"; break; @@ -156,14 +159,9 @@ single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle){ vRingbufferGetInfo(buf_handle, NULL, NULL, NULL, NULL, &uxItemsWaiting); if(uxItemsWaiting>0){ message = (single_message_t *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(50)); - if(item_size!=sizeof(single_message_t)){ - ESP_LOGE(tag,"Invalid message length!"); - } - else { - message_copy = heap_caps_malloc(item_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - if(message_copy){ - memcpy(message_copy,message,item_size); - } + message_copy = heap_caps_malloc(item_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if(message_copy){ + memcpy(message_copy,message,item_size); } vRingbufferReturnItem(buf_handle, (void *)message); } @@ -171,15 +169,22 @@ single_message_t * messaging_retrieve_message(RingbufHandle_t buf_handle){ } esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_message_t * message, size_t message_size){ - UBaseType_t uxItemsWaiting=0; size_t item_size=0; messaging_list_t * subscriber=get_struct_ptr(subscriber_handle); if(!subscriber->buf_handle){ ESP_LOGE(tag,"post failed: null buffer for %s", str_or_unknown(subscriber->subscriber_name)); return ESP_FAIL; } - vRingbufferGetInfo(subscriber->buf_handle,NULL,NULL,NULL,NULL,&uxItemsWaiting); - if(uxItemsWaiting>=subscriber->max_count){ + void * pItem=NULL; + int passes=0; + UBaseType_t res=pdFALSE; + while(passes++<3){ + res = xRingbufferSendAcquire(subscriber->buf_handle, &pItem, message_size, pdMS_TO_TICKS(100)); + if(res == pdTRUE && pItem){ + memcpy(pItem,message,message_size); + xRingbufferSendComplete(subscriber->buf_handle, pItem); + break; + } ESP_LOGD(tag,"messaged dropped for %s",str_or_unknown(subscriber->subscriber_name)); single_message_t * dummy = (single_message_t *)xRingbufferReceive(subscriber->buf_handle, &item_size, pdMS_TO_TICKS(50)); if (dummy== NULL) { @@ -189,7 +194,6 @@ esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_m vRingbufferReturnItem(subscriber->buf_handle, (void *)dummy); } } - UBaseType_t res = xRingbufferSend(subscriber->buf_handle, message, message_size, pdMS_TO_TICKS(1000)); if (res != pdTRUE) { ESP_LOGE(tag,"post to %s failed",str_or_unknown(subscriber->subscriber_name)); return ESP_FAIL; @@ -197,19 +201,27 @@ esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_m return ESP_OK; } void messaging_post_message(messaging_types type,messaging_classes msg_class, char *fmt, ...){ - single_message_t message={}; + single_message_t * message=NULL; + size_t msg_size=0; + size_t ln =0; messaging_list_t * cur=⊤ va_list va; va_start(va, fmt); - vsnprintf(message.message, sizeof(message.message), fmt, va); + ln = vsnprintf(NULL, 0, fmt, va)+1; + msg_size = sizeof(single_message_t)+ln; + message = (single_message_t *)heap_caps_malloc(msg_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + vsprintf(message->message, fmt, va); va_end(va); - message.type = type; - message.msg_class = msg_class; - message.sent_time = esp_timer_get_time() / 1000; + message->msg_size = msg_size; + message->type = type; + message->msg_class = msg_class; + message->sent_time = esp_timer_get_time() / 1000; + ESP_LOGI(tag,"Post: %s",message->message); while(cur){ - messaging_post_to_queue(get_handle_ptr(cur), &message, sizeof(single_message_t)); + messaging_post_to_queue(get_handle_ptr(cur), message, msg_size); cur = get_struct_ptr(cur->next); } + FREE_AND_NULL(message); return; } diff --git a/components/services/messaging.h b/components/services/messaging.h index fb0ca0a0..f9ecbca6 100644 --- a/components/services/messaging.h +++ b/components/services/messaging.h @@ -9,7 +9,8 @@ typedef enum { } messaging_types; typedef enum { MESSAGING_CLASS_OTA, - MESSAGING_CLASS_SYSTEM + MESSAGING_CLASS_SYSTEM, + MESSAGING_CLASS_STATS } messaging_classes; typedef struct messaging_list_t *messaging_handle_t; @@ -18,7 +19,8 @@ typedef struct { time_t sent_time; messaging_types type; messaging_classes msg_class; - char message[151]; + size_t msg_size; + char message[]; } single_message_t; cJSON * messaging_retrieve_messages(RingbufHandle_t buf_handle); diff --git a/components/services/monitor.c b/components/services/monitor.c index 4b56dbe5..04199895 100644 --- a/components/services/monitor.c +++ b/components/services/monitor.c @@ -21,6 +21,9 @@ #include "globdefs.h" #include "config.h" #include "accessors.h" +#include "messaging.h" +#include "cJSON.h" +#include "trace.h" #define MONITOR_TIMER (10*1000) @@ -49,10 +52,12 @@ static void task_stats( void ) { TaskStatus_t *tasks; uint32_t total, n; } current, previous; - + cJSON * top=cJSON_CreateObject(); + cJSON * tlist=cJSON_CreateArray(); current.n = uxTaskGetNumberOfTasks(); current.tasks = malloc( current.n * sizeof( TaskStatus_t ) ); current.n = uxTaskGetSystemState( current.tasks, current.n, ¤t.total ); + cJSON_AddNumberToObject(top,"ntasks",current.n); static EXT_RAM_ATTR char scratch[128+1]; *scratch = '\0'; @@ -66,6 +71,20 @@ static void task_stats( void ) { n += sprintf(scratch + n, "%16s %2u%% s:%5u", current.tasks[i].pcTaskName, 100 * (current.tasks[i].ulRunTimeCounter - previous.tasks[j].ulRunTimeCounter) / elapsed, current.tasks[i].usStackHighWaterMark); + cJSON * t=cJSON_CreateObject(); + cJSON_AddNumberToObject(t,"cpu",100 * (current.tasks[i].ulRunTimeCounter - previous.tasks[j].ulRunTimeCounter) / elapsed); + cJSON_AddNumberToObject(t,"minstk",current.tasks[i].usStackHighWaterMark); + cJSON_AddNumberToObject(t,"bprio",current.tasks[i].uxBasePriority); + cJSON_AddNumberToObject(t,"cprio",current.tasks[i].uxCurrentPriority); + cJSON_AddStringToObject(t,"nme",current.tasks[i].pcTaskName); + cJSON_AddNumberToObject(t,"st",current.tasks[i].eCurrentState); + cJSON_AddNumberToObject(t,"num",current.tasks[i].xTaskNumber); + cJSON_AddItemToArray(tlist,t); + char * topsts = cJSON_PrintUnformatted(t); + if(topsts){ + ESP_LOGI(TAG,"task detail: %s",topsts); + FREE_AND_NULL(topsts); + } if (i % 3 == 2 || i == current.n - 1) { ESP_LOGI(TAG, "%s", scratch); n = 0; @@ -77,13 +96,32 @@ static void task_stats( void ) { #else for (int i = 0, n = 0; i < current.n; i ++) { n += sprintf(scratch + n, "%16s s:%5u\t", current.tasks[i].pcTaskName, current.tasks[i].usStackHighWaterMark); + cJSON * t=cJSON_CreateObject(); + cJSON_AddNumberToObject(t,"minstk",current.tasks[i].usStackHighWaterMark); + cJSON_AddNumberToObject(t,"bprio",current.tasks[i].uxBasePriority); + cJSON_AddNumberToObject(t,"cprio",current.tasks[i].uxCurrentPriority); + cJSON_AddStringToObject(t,"nme",current.tasks[i].pcTaskName); + cJSON_AddStringToObject(t,"st",current.tasks[i].eCurrentState); + cJSON_AddNumberToObject(t,"num",current.tasks[i].xTaskNumber); + cJSON_AddItemToArray(tlist,t); + char * topsts = cJSON_PrintUnformatted(t); + if(topsts){ + ESP_LOGI(TAG,"task detail: %s",topsts); + FREE_AND_NULL(topsts); + } if (i % 3 == 2 || i == current.n - 1) { ESP_LOGI(TAG, "%s", scratch); n = 0; } } #endif - + cJSON_AddItemToObject(top,"tasks",tlist); + char * top_a= cJSON_PrintUnformatted(top); + if(top_a){ + messaging_post_message(MESSAGING_INFO, MESSAGING_CLASS_STATS,top_a); + FREE_AND_NULL(top_a); + } + cJSON_free(top); if (previous.tasks) free(previous.tasks); previous = current; #endif diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 6202c051..ea7bd719 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -616,7 +616,7 @@ void ota_task(void *pvParameter) { esp_err_t err = ESP_OK; int data_read = 0; - GDS_TextSetFont(display,2,&Font_droid_sans_fallback_15x17,-2); + GDS_TextSetFont(display,2,GDS_GetHeight(display)>32?&Font_droid_sans_fallback_15x17:&Font_droid_sans_fallback_11x13,-2); GDS_ClearExt(display, true); GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Firmware update"); GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, "Initializing"); diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index 0f603ae4..526ed468 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -144,7 +144,7 @@ void init_telnet(){ void start_telnet(void * pvParameter){ static bool isStarted=false; StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); - StackType_t *xStack = heap_caps_malloc(TELNET_STACK_SIZE,(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + StackType_t *xStack = heap_caps_malloc(TELNET_STACK_SIZE,(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT)); if(!isStarted && bIsEnabled) { xTaskCreateStatic( (TaskFunction_t) &telnet_task, "telnet", TELNET_STACK_SIZE, NULL, ESP_TASK_MAIN_PRIO , xStack, xTaskBuffer); diff --git a/components/wifi-manager/_esp_http_server.h b/components/wifi-manager/_esp_http_server.h new file mode 100644 index 00000000..bde57c65 --- /dev/null +++ b/components/wifi-manager/_esp_http_server.h @@ -0,0 +1,93 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_HTTP_SERVER_H_ +#define __ESP_HTTP_SERVER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * @brief Starts the web server + * + * Create an instance of HTTP server and allocate memory/resources for it + * depending upon the specified configuration. + * + * Example usage: + * @code{c} + * + * //Function for starting the webserver + * httpd_handle_t start_webserver(void) + * { + * // Generate default configuration + * httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + * + * // Empty handle to http_server + * httpd_handle_t server = NULL; + * + * // Start the httpd server + * if (httpd_start(&server, &config) == ESP_OK) { + * // Register URI handlers + * httpd_register_uri_handler(server, &uri_get); + * httpd_register_uri_handler(server, &uri_post); + * } + * // If server failed to start, handle will be NULL + * return server; + * } + * + * @endcode + * + * @param[in] config Configuration for new instance of the server + * @param[out] handle Handle to newly created instance of the server. NULL on error + * @return + * - ESP_OK : Instance created successfully + * - ESP_ERR_INVALID_ARG : Null argument(s) + * - ESP_ERR_HTTPD_ALLOC_MEM : Failed to allocate memory for instance + * - ESP_ERR_HTTPD_TASK : Failed to launch server task + */ +esp_err_t __httpd_start(httpd_handle_t *handle, const httpd_config_t *config); +static inline int __httpd_os_thread_create_static(TaskHandle_t *thread, + const char *name, uint16_t stacksize, int prio, + void (*thread_routine)(void *arg), void *arg, + BaseType_t core_id) +{ + + + StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + StackType_t *xStack = heap_caps_malloc(stacksize,(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT)); + + + // + *thread = xTaskCreateStaticPinnedToCore(thread_routine, name, stacksize, arg, prio, xStack,xTaskBuffer,core_id); + if (*thread) { + return ESP_OK; + } + return ESP_FAIL; +} +#ifdef __cplusplus +} +#endif + +#endif /* ! _ESP_HTTP_SERVER_H_ */ diff --git a/components/wifi-manager/_esp_httpd_main.c b/components/wifi-manager/_esp_httpd_main.c new file mode 100644 index 00000000..af6faefa --- /dev/null +++ b/components/wifi-manager/_esp_httpd_main.c @@ -0,0 +1,373 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include <_esp_http_server.h> +#include "../src/esp_httpd_priv.h" +#include "../src/util/ctrl_sock.h" + +static const char *TAG = "_httpd"; + + +struct httpd_ctrl_data { + enum httpd_ctrl_msg { + HTTPD_CTRL_SHUTDOWN, + HTTPD_CTRL_WORK, + } hc_msg; + httpd_work_fn_t hc_work; + void *hc_work_arg; +}; + + +static esp_err_t _httpd_server_init(struct httpd_data *hd) +{ + int fd = socket(PF_INET6, SOCK_STREAM, 0); + if (fd < 0) { + ESP_LOGE(TAG, LOG_FMT("error in socket (%d)"), errno); + return ESP_FAIL; + } + + struct in6_addr inaddr_any = IN6ADDR_ANY_INIT; + struct sockaddr_in6 serv_addr = { + .sin6_family = PF_INET6, + .sin6_addr = inaddr_any, + .sin6_port = htons(hd->config.server_port) + }; + + /* Enable SO_REUSEADDR to allow binding to the same + * address and port when restarting the server */ + int enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) { + /* This will fail if CONFIG_LWIP_SO_REUSE is not enabled. But + * it does not affect the normal working of the HTTP Server */ + ESP_LOGW(TAG, LOG_FMT("error enabling SO_REUSEADDR (%d)"), errno); + } + + int ret = bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + if (ret < 0) { + ESP_LOGE(TAG, LOG_FMT("error in bind (%d)"), errno); + close(fd); + return ESP_FAIL; + } + + ret = listen(fd, hd->config.backlog_conn); + if (ret < 0) { + ESP_LOGE(TAG, LOG_FMT("error in listen (%d)"), errno); + close(fd); + return ESP_FAIL; + } + + int ctrl_fd = cs_create_ctrl_sock(hd->config.ctrl_port); + if (ctrl_fd < 0) { + ESP_LOGE(TAG, LOG_FMT("error in creating ctrl socket (%d)"), errno); + close(fd); + return ESP_FAIL; + } + + int msg_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (msg_fd < 0) { + ESP_LOGE(TAG, LOG_FMT("error in creating msg socket (%d)"), errno); + close(fd); + close(ctrl_fd); + return ESP_FAIL; + } + + hd->listen_fd = fd; + hd->ctrl_fd = ctrl_fd; + hd->msg_fd = msg_fd; + return ESP_OK; +} + +static void _httpd_process_ctrl_msg(struct httpd_data *hd) +{ + struct httpd_ctrl_data msg; + int ret = recv(hd->ctrl_fd, &msg, sizeof(msg), 0); + if (ret <= 0) { + ESP_LOGW(TAG, LOG_FMT("error in recv (%d)"), errno); + return; + } + if (ret != sizeof(msg)) { + ESP_LOGW(TAG, LOG_FMT("incomplete msg")); + return; + } + + switch (msg.hc_msg) { + case HTTPD_CTRL_WORK: + if (msg.hc_work) { + ESP_LOGD(TAG, LOG_FMT("work")); + (*msg.hc_work)(msg.hc_work_arg); + } + break; + case HTTPD_CTRL_SHUTDOWN: + ESP_LOGD(TAG, LOG_FMT("shutdown")); + hd->hd_td.status = THREAD_STOPPING; + break; + default: + break; + } +} + +static esp_err_t _httpd_accept_conn(struct httpd_data *hd, int listen_fd) +{ + /* If no space is available for new session, close the least recently used one */ + if (hd->config.lru_purge_enable == true) { + if (!httpd_is_sess_available(hd)) { + /* Queue asynchronous closure of the least recently used session */ + return httpd_sess_close_lru(hd); + /* Returning from this allowes the main server thread to process + * the queued asynchronous control message for closing LRU session. + * Since connection request hasn't been addressed yet using accept() + * therefore _httpd_accept_conn() will be called again, but this time + * with space available for one session + */ + } + } + + struct sockaddr_in addr_from; + socklen_t addr_from_len = sizeof(addr_from); + int new_fd = accept(listen_fd, (struct sockaddr *)&addr_from, &addr_from_len); + if (new_fd < 0) { + ESP_LOGW(TAG, LOG_FMT("error in accept (%d)"), errno); + return ESP_FAIL; + } + ESP_LOGD(TAG, LOG_FMT("newfd = %d"), new_fd); + + struct timeval tv; + /* Set recv timeout of this fd as per config */ + tv.tv_sec = hd->config.recv_wait_timeout; + tv.tv_usec = 0; + setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)); + + /* Set send timeout of this fd as per config */ + tv.tv_sec = hd->config.send_wait_timeout; + tv.tv_usec = 0; + setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv)); + + if (ESP_OK != httpd_sess_new(hd, new_fd)) { + ESP_LOGW(TAG, LOG_FMT("session creation failed")); + close(new_fd); + return ESP_FAIL; + } + ESP_LOGD(TAG, LOG_FMT("complete")); + return ESP_OK; +} +/* Manage in-coming connection or data requests */ +static esp_err_t _httpd_server(struct httpd_data *hd) +{ + fd_set read_set; + FD_ZERO(&read_set); + if (hd->config.lru_purge_enable || httpd_is_sess_available(hd)) { + /* Only listen for new connections if server has capacity to + * handle more (or when LRU purge is enabled, in which case + * older connections will be closed) */ + FD_SET(hd->listen_fd, &read_set); + } + FD_SET(hd->ctrl_fd, &read_set); + + int tmp_max_fd; + httpd_sess_set_descriptors(hd, &read_set, &tmp_max_fd); + int maxfd = MAX(hd->listen_fd, tmp_max_fd); + tmp_max_fd = maxfd; + maxfd = MAX(hd->ctrl_fd, tmp_max_fd); + + ESP_LOGD(TAG, LOG_FMT("doing select maxfd+1 = %d"), maxfd + 1); + int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL); + if (active_cnt < 0) { + ESP_LOGE(TAG, LOG_FMT("error in select (%d)"), errno); + httpd_sess_delete_invalid(hd); + return ESP_OK; + } + + /* Case0: Do we have a control message? */ + if (FD_ISSET(hd->ctrl_fd, &read_set)) { + ESP_LOGD(TAG, LOG_FMT("processing ctrl message")); + _httpd_process_ctrl_msg(hd); + if (hd->hd_td.status == THREAD_STOPPING) { + ESP_LOGD(TAG, LOG_FMT("stopping thread")); + return ESP_FAIL; + } + } + + /* Case1: Do we have any activity on the current data + * sessions? */ + int fd = -1; + while ((fd = httpd_sess_iterate(hd, fd)) != -1) { + if (FD_ISSET(fd, &read_set) || (httpd_sess_pending(hd, fd))) { + ESP_LOGD(TAG, LOG_FMT("processing socket %d"), fd); + if (httpd_sess_process(hd, fd) != ESP_OK) { + ESP_LOGD(TAG, LOG_FMT("closing socket %d"), fd); + close(fd); + /* Delete session and update fd to that + * preceding the one being deleted */ + fd = httpd_sess_delete(hd, fd); + } + } + } + + /* Case2: Do we have any incoming connection requests to + * process? */ + if (FD_ISSET(hd->listen_fd, &read_set)) { + ESP_LOGD(TAG, LOG_FMT("processing listen socket %d"), hd->listen_fd); + if (_httpd_accept_conn(hd, hd->listen_fd) != ESP_OK) { + ESP_LOGW(TAG, LOG_FMT("error accepting new connection")); + } + } + return ESP_OK; +} + +static void _httpd_close_all_sessions(struct httpd_data *hd) +{ + int fd = -1; + while ((fd = httpd_sess_iterate(hd, fd)) != -1) { + ESP_LOGD(TAG, LOG_FMT("cleaning up socket %d"), fd); + httpd_sess_delete(hd, fd); + close(fd); + } +} +/* The main HTTPD thread */ +static void _httpd_thread(void *arg) +{ + int ret; + struct httpd_data *hd = (struct httpd_data *) arg; + hd->hd_td.status = THREAD_RUNNING; + + ESP_LOGD(TAG, LOG_FMT("web server started")); + while (1) { + ret = _httpd_server(hd); + if (ret != ESP_OK) { + break; + } + } + + ESP_LOGD(TAG, LOG_FMT("web server exiting")); + close(hd->msg_fd); + cs_free_ctrl_sock(hd->ctrl_fd); + _httpd_close_all_sessions(hd); + close(hd->listen_fd); + hd->hd_td.status = THREAD_STOPPED; + httpd_os_thread_delete(); +} +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)); + 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 *)); + 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)); + if (!hd->hd_sd) { + ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data")); + free(hd->hd_calls); + free(hd); + return NULL; + } + struct httpd_req_aux *ra = &hd->hd_req_aux; + ra->resp_hdrs = calloc(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); + free(hd->hd_calls); + free(hd); + return NULL; + } + hd->err_handler_fns = calloc(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); + free(hd->hd_sd); + free(hd->hd_calls); + free(hd); + return NULL; + } + /* Save the configuration for this instance */ + hd->config = *config; + return hd; +} +static void _httpd_delete(struct httpd_data *hd) +{ + struct httpd_req_aux *ra = &hd->hd_req_aux; + /* Free memory of httpd instance data */ + free(hd->err_handler_fns); + free(ra->resp_hdrs); + free(hd->hd_sd); + + /* Free registered URI handlers */ + httpd_unregister_all_uri_handlers(hd); + free(hd->hd_calls); + free(hd); +} +esp_err_t __httpd_start(httpd_handle_t *handle, const httpd_config_t *config) +{ + if (handle == NULL || config == NULL) { + return ESP_ERR_INVALID_ARG; + } + + /* Sanity check about whether LWIP is configured for providing the + * maximum number of open sockets sufficient for the server. Though, + * this check doesn't guarantee that many sockets will actually be + * available at runtime as other processes may use up some sockets. + * Note that server also uses 3 sockets for its internal use : + * 1) listening for new TCP connections + * 2) for sending control messages over UDP + * 3) for receiving control messages over UDP + * So the total number of required sockets is max_open_sockets + 3 + */ + if (CONFIG_LWIP_MAX_SOCKETS < config->max_open_sockets + 3) { + ESP_LOGE(TAG, "Configuration option max_open_sockets is too large (max allowed %d)\n\t" + "Either decrease this or configure LWIP_MAX_SOCKETS to a larger value", + CONFIG_LWIP_MAX_SOCKETS - 3); + return ESP_ERR_INVALID_ARG; + } + + struct httpd_data *hd = __httpd_create(config); + if (hd == NULL) { + /* Failed to allocate memory */ + return ESP_ERR_HTTPD_ALLOC_MEM; + } + + if (_httpd_server_init(hd) != ESP_OK) { + _httpd_delete(hd); + return ESP_FAIL; + } + + httpd_sess_init(hd); + if (__httpd_os_thread_create_static(&hd->hd_td.handle, "httpd", + hd->config.stack_size, + hd->config.task_priority, + _httpd_thread, hd, + hd->config.core_id) != ESP_OK) { + /* Failed to launch task */ + _httpd_delete(hd); + return ESP_ERR_HTTPD_TASK; + } + + *handle = (httpd_handle_t *)hd; + return ESP_OK; +} + diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index 55fcb8e0..58ca2f01 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -24,6 +24,14 @@ var nvs_type_t = { NVS_TYPE_ANY : 0xff /*!< Must be last */ } ; +var task_state_t = { + 0 : "eRunning", /*!< A task is querying the state of itself, so must be running. */ + 1 : "eReady", /*!< The task being queried is in a read or pending ready list. */ + 2 : "eBlocked", /*!< The task being queried is in the Blocked state. */ + 3 : "eSuspended", /*!< The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */ + 4 : "eDeleted" + +} var releaseURL = 'https://api.github.com/repos/sle118/squeezelite-esp32/releases'; var recovery = false; var enableAPTimer = true; @@ -649,7 +657,9 @@ function refreshAPHTML(data){ function getMessages() { $.getJSON("/messages.json", function(data) { data.forEach(function(msg) { - var msg_age = msg["current_time"] - msg["sent_time"]; + var msg_age = msg["current_time"] - msg["sent_time"]; + var msg_time = new Date( ); + msg_time.setTime( msg_time .getTime() - msg_age ); switch (msg["class"]) { case "MESSAGING_CLASS_OTA": //message: "{"ota_dsc":"Erasing flash complete","ota_pct":0}" @@ -668,6 +678,15 @@ function getMessages() { } } break; + case "MESSAGING_CLASS_STATS": + // for task states, check structure : task_state_t + var stats_data = JSON.parse(msg["message"]); + console.log(msg_time + " - Number of tasks on the ESP32: " + stats_data["ntasks"]); + var stats_tasks = stats_data["tasks"]; + stats_tasks.forEach(function(task) { + console.log(msg_time + " - " + task["nme"] + ' - '+ task["cpu"]); + }); + break; case "MESSAGING_CLASS_SYSTEM": showMessage(msg["message"], msg["type"],msg_age); lastMsg = msg; diff --git a/components/wifi-manager/component.mk b/components/wifi-manager/component.mk index 1800f23c..4a5d5006 100644 --- a/components/wifi-manager/component.mk +++ b/components/wifi-manager/component.mk @@ -7,7 +7,7 @@ # please read the SDK documents if you need to do this. # COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz -COMPONENT_ADD_INCLUDEDIRS := . +COMPONENT_ADD_INCLUDEDIRS := . $(IDF_PATH)/components/esp_http_server/src $(IDF_PATH)/components/esp_http_server/src/port/esp32 $(IDF_PATH)/components/esp_http_server/src/util CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 373cad3f..deb91352 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -22,6 +22,7 @@ #include "http_server_handlers.h" #include "esp_log.h" #include "esp_http_server.h" +#include "_esp_http_server.h" #include #include #include @@ -112,6 +113,7 @@ void register_regular_handlers(httpd_handle_t server){ } + esp_err_t http_server_start() { ESP_LOGI(TAG, "Initializing HTTP Server"); @@ -131,7 +133,7 @@ esp_err_t http_server_start() // config.open_fn ESP_LOGI(TAG, "Starting HTTP Server"); - esp_err_t err= httpd_start(&_server, &config); + esp_err_t err= __httpd_start(&_server, &config); if(err != ESP_OK){ ESP_LOGE_LOC(TAG,"Start server failed"); } diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 71b1bcdd..6cf0111e 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_ADD_INCLUDEDIRS . ) +set(COMPONENT_ADD_INCLUDEDIRS . ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32 ${IDF_PATH}/components/esp_http_server/src/util) set(COMPONENT_SRCS "esp_app_main.c" "platform_esp32.c" "cmd_wifi.c" "console.c" "nvs_utilities.c" "cmd_squeezelite.c" "config.c") set(REQUIRES esp_common) diff --git a/main/component.mk b/main/component.mk index 8edcf630..175f015e 100644 --- a/main/component.mk +++ b/main/component.mk @@ -9,4 +9,4 @@ CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO -DMODEL_NAME=SqueezeESP32 LDFLAGS += -s COMPONENT_EMBED_TXTFILES := ${PROJECT_PATH}/server_certs/github.pem -COMPONENT_ADD_INCLUDEDIRS := . \ No newline at end of file +COMPONENT_ADD_INCLUDEDIRS := . \ No newline at end of file diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 10234c45..8ccb6018 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -47,6 +47,7 @@ #include "config.h" #include "audio_controls.h" #include "telnet.h" +#include "messaging.h" static const char certs_namespace[] = "certificates"; static const char certs_key[] = "blob"; @@ -73,12 +74,14 @@ const char * str_or_unknown(const char * str) { return (str?str:unknown_string_p /* brief this is an exemple of a callback that you can setup in your own app to get notified of wifi manager event */ void cb_connection_got_ip(void *pvParameter){ ESP_LOGI(TAG, "I have a connection!"); + messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"Wifi connected"); xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); bWifiConnected=true; led_unpush(LED_GREEN); } void cb_connection_sta_disconnected(void *pvParameter){ led_blink_pushed(LED_GREEN, 250, 250); + messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"Wifi disconnected"); bWifiConnected=false; xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); } @@ -427,4 +430,5 @@ void app_main() #endif free(fwurl); } + messaging_post_message(MESSAGING_INFO,MESSAGING_CLASS_SYSTEM,"System started"); } From 4f72f284ce7e900cda63ebdb8996ddf60114d218 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Tue, 3 Mar 2020 11:42:25 -0500 Subject: [PATCH 41/46] Additional messages added to messaging bus, increase dft size --- components/services/component.mk | 1 + components/services/messaging.c | 17 +++++++------ components/services/monitor.c | 35 ++++++++++++-------------- components/telnet/telnet.c | 4 +++ components/wifi-manager/code.js | 3 ++- components/wifi-manager/wifi_manager.c | 3 +++ main/platform_esp32.h | 1 - 7 files changed, 36 insertions(+), 28 deletions(-) diff --git a/components/services/component.mk b/components/services/component.mk index ace79fdb..0bf7bd7a 100644 --- a/components/services/component.mk +++ b/components/services/component.mk @@ -9,3 +9,4 @@ COMPONENT_SRCDIRS := . COMPONENT_ADD_INCLUDEDIRS := . +CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG \ No newline at end of file diff --git a/components/services/messaging.c b/components/services/messaging.c index 3d1d9ff6..065de8d3 100644 --- a/components/services/messaging.c +++ b/components/services/messaging.c @@ -27,7 +27,7 @@ typedef struct { RingbufHandle_t buf_handle; } messaging_list_t; static messaging_list_t top; -#define MSG_LENGTH_AVG 201 +#define MSG_LENGTH_AVG 1024 messaging_list_t * get_struct_ptr(messaging_handle_t handle){ return (messaging_list_t *)handle; @@ -176,21 +176,24 @@ esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_m return ESP_FAIL; } void * pItem=NULL; - int passes=0; UBaseType_t res=pdFALSE; - while(passes++<3){ - res = xRingbufferSendAcquire(subscriber->buf_handle, &pItem, message_size, pdMS_TO_TICKS(100)); + while(1){ + ESP_LOGD(tag,"Attempting to reserve %d bytes for %s",message_size, str_or_unknown(subscriber->subscriber_name)); + res = xRingbufferSendAcquire(subscriber->buf_handle, &pItem, message_size, pdMS_TO_TICKS(50)); if(res == pdTRUE && pItem){ + ESP_LOGD(tag,"Reserving complete for %s", str_or_unknown(subscriber->subscriber_name)); memcpy(pItem,message,message_size); xRingbufferSendComplete(subscriber->buf_handle, pItem); break; } - ESP_LOGD(tag,"messaged dropped for %s",str_or_unknown(subscriber->subscriber_name)); + ESP_LOGD(tag,"Dropping for %s",str_or_unknown(subscriber->subscriber_name)); single_message_t * dummy = (single_message_t *)xRingbufferReceive(subscriber->buf_handle, &item_size, pdMS_TO_TICKS(50)); if (dummy== NULL) { - ESP_LOGE(tag,"receive from buffer failed"); + ESP_LOGE(tag,"Dropping message failed"); + break; } else { + ESP_LOGD(tag,"Dropping message of %d bytes for %s",item_size, str_or_unknown(subscriber->subscriber_name)); vRingbufferReturnItem(subscriber->buf_handle, (void *)dummy); } } @@ -216,7 +219,7 @@ void messaging_post_message(messaging_types type,messaging_classes msg_class, ch message->type = type; message->msg_class = msg_class; message->sent_time = esp_timer_get_time() / 1000; - ESP_LOGI(tag,"Post: %s",message->message); + ESP_LOGD(tag,"Post: %s",message->message); while(cur){ messaging_post_to_queue(get_handle_ptr(cur), message, msg_size); cur = get_struct_ptr(cur->next); diff --git a/components/services/monitor.c b/components/services/monitor.c index 04199895..15e861ad 100644 --- a/components/services/monitor.c +++ b/components/services/monitor.c @@ -46,13 +46,12 @@ bool spkfault_svc(void); /**************************************************************************************** * */ -static void task_stats( void ) { +static void task_stats( cJSON* top ) { #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY static struct { TaskStatus_t *tasks; uint32_t total, n; } current, previous; - cJSON * top=cJSON_CreateObject(); cJSON * tlist=cJSON_CreateArray(); current.n = uxTaskGetNumberOfTasks(); current.tasks = malloc( current.n * sizeof( TaskStatus_t ) ); @@ -80,11 +79,6 @@ static void task_stats( void ) { cJSON_AddNumberToObject(t,"st",current.tasks[i].eCurrentState); cJSON_AddNumberToObject(t,"num",current.tasks[i].xTaskNumber); cJSON_AddItemToArray(tlist,t); - char * topsts = cJSON_PrintUnformatted(t); - if(topsts){ - ESP_LOGI(TAG,"task detail: %s",topsts); - FREE_AND_NULL(topsts); - } if (i % 3 == 2 || i == current.n - 1) { ESP_LOGI(TAG, "%s", scratch); n = 0; @@ -104,11 +98,6 @@ static void task_stats( void ) { cJSON_AddStringToObject(t,"st",current.tasks[i].eCurrentState); cJSON_AddNumberToObject(t,"num",current.tasks[i].xTaskNumber); cJSON_AddItemToArray(tlist,t); - char * topsts = cJSON_PrintUnformatted(t); - if(topsts){ - ESP_LOGI(TAG,"task detail: %s",topsts); - FREE_AND_NULL(topsts); - } if (i % 3 == 2 || i == current.n - 1) { ESP_LOGI(TAG, "%s", scratch); n = 0; @@ -116,12 +105,6 @@ static void task_stats( void ) { } #endif cJSON_AddItemToObject(top,"tasks",tlist); - char * top_a= cJSON_PrintUnformatted(top); - if(top_a){ - messaging_post_message(MESSAGING_INFO, MESSAGING_CLASS_STATS,top_a); - FREE_AND_NULL(top_a); - } - cJSON_free(top); if (previous.tasks) free(previous.tasks); previous = current; #endif @@ -131,13 +114,26 @@ static void task_stats( void ) { * */ static void monitor_callback(TimerHandle_t xTimer) { + cJSON * top=cJSON_CreateObject(); + cJSON_AddNumberToObject(top,"free_iram",heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); + cJSON_AddNumberToObject(top,"min_free_iram",heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL)); + cJSON_AddNumberToObject(top,"free_spiram",heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); + cJSON_AddNumberToObject(top,"min_free_spiram",heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM)); + ESP_LOGI(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)); - task_stats(); + task_stats(top); + char * top_a= cJSON_PrintUnformatted(top); + if(top_a){ + messaging_post_message(MESSAGING_INFO, MESSAGING_CLASS_STATS,top_a); + FREE_AND_NULL(top_a); + } + cJSON_free(top); + } /**************************************************************************************** @@ -145,6 +141,7 @@ static void monitor_callback(TimerHandle_t xTimer) { */ static void jack_handler_default(void *id, button_event_e event, button_press_e mode, bool long_press) { ESP_LOGD(TAG, "Jack %s", event == BUTTON_PRESSED ? "inserted" : "removed"); + messaging_post_message(MESSAGING_INFO, MESSAGING_CLASS_SYSTEM,"jack is %s",BUTTON_PRESSED ? "inserted" : "removed"); if (jack_handler_svc) (*jack_handler_svc)(event == BUTTON_PRESSED); } diff --git a/components/telnet/telnet.c b/components/telnet/telnet.c index 526ed468..03bab437 100644 --- a/components/telnet/telnet.c +++ b/components/telnet/telnet.c @@ -38,8 +38,10 @@ #include "config.h" #include "nvs_utilities.h" #include "platform_esp32.h" +#include "messaging.h" #include "trace.h" + /************************************ * Globals */ @@ -119,6 +121,8 @@ void init_telnet(){ buf_handle = xRingbufferCreateStatic(log_buf_size, RINGBUF_TYPE_BYTEBUF, buffer_storage, buffer_struct); if (buf_handle == NULL) { ESP_LOGE(TAG,"Failed to create ring buffer for telnet!"); + messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Failed to allocate memory for telnet buffer"); + return; } diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index 58ca2f01..6a6f12f5 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -683,8 +683,9 @@ function getMessages() { var stats_data = JSON.parse(msg["message"]); console.log(msg_time + " - Number of tasks on the ESP32: " + stats_data["ntasks"]); var stats_tasks = stats_data["tasks"]; + console.log(msg_time + '\tname' + '\tcpu' + '\tstate'+ '\tminstk'+ '\tbprio'+ '\tcprio'+ '\tnum' ); stats_tasks.forEach(function(task) { - console.log(msg_time + " - " + task["nme"] + ' - '+ task["cpu"]); + console.log(msg_time + '\t' + task["nme"] + '\t'+ task["cpu"] + '\t'+ task_state_t[task["st"]]+ '\t'+ task["minstk"]+ '\t'+ task["bprio"]+ '\t'+ task["cprio"]+ '\t'+ task["num"]); }); break; case "MESSAGING_CLASS_SYSTEM": diff --git a/components/wifi-manager/wifi_manager.c b/components/wifi-manager/wifi_manager.c index 667d01d6..430ffd6f 100644 --- a/components/wifi-manager/wifi_manager.c +++ b/components/wifi-manager/wifi_manager.c @@ -361,6 +361,7 @@ esp_err_t wifi_manager_save_sta_config(){ esp_err = nvs_commit(handle); if (esp_err != ESP_OK) { ESP_LOGE(TAG, "Unable to commit changes. Error %s", esp_err_to_name(esp_err)); + messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Unable to save wifi credentials. %s",esp_err_to_name(esp_err)); return esp_err; } nvs_close(handle); @@ -1335,6 +1336,8 @@ void wifi_manager( void * pvParameters ){ else{ /* lost connection ? */ ESP_LOGE(TAG, "WiFi Connection lost."); + messaging_post_message(MESSAGING_WARNING,MESSAGING_CLASS_SYSTEM,"WiFi Connection lost"); + if(wifi_manager_lock_json_buffer( portMAX_DELAY )){ wifi_manager_generate_ip_info_json( UPDATE_LOST_CONNECTION ); wifi_manager_unlock_json_buffer(); diff --git a/main/platform_esp32.h b/main/platform_esp32.h index 3443e069..f0fff28a 100644 --- a/main/platform_esp32.h +++ b/main/platform_esp32.h @@ -20,7 +20,6 @@ */ #pragma once - #include "esp_pthread.h" #ifndef SQUEEZELITE_ESP32_RELEASE_URL #define SQUEEZELITE_ESP32_RELEASE_URL "https://github.com/sle118/squeezelite-esp32/releases" From 95267d4b3e94e998c61690899cd6e9377cc7fa1c Mon Sep 17 00:00:00 2001 From: Christian Herzog Date: Wed, 4 Mar 2020 19:04:57 +0100 Subject: [PATCH 42/46] some cleanup --- components/wifi-manager/code.js | 4 +++- components/wifi-manager/index.html | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index 6a6f12f5..139c8b2f 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -800,21 +800,23 @@ function checkStatus(){ $("#otadiv").show(); $('a[href^="#tab-audio"]').hide(); $('a[href^="#tab-gpio"]').show(); + $('#uploaddiv').show(); $("footer.footer").removeClass('sl'); $("footer.footer").addClass('recovery'); $("#boot-button").html('Reboot'); $("#boot-form").attr('action', '/reboot_ota.json'); + enableStatusTimer = true; } else { recovery = false; $("#otadiv").hide(); $('a[href^="#tab-audio"]').show(); $('a[href^="#tab-gpio"]').hide(); + $('#uploaddiv').hide(); $("footer.footer").removeClass('recovery'); $("footer.footer").addClass('sl'); $("#boot-button").html('Recovery'); $("#boot-form").attr('action', '/recovery.json'); - $('#uploaddiv"]').hide(); enableStatusTimer = false; } diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index 154376f8..cdd97274 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -17,6 +17,7 @@ + From 5badd8fc510039e77976b8244ed753fdab866c3d Mon Sep 17 00:00:00 2001 From: Sebastien Date: Wed, 4 Mar 2020 13:47:18 -0500 Subject: [PATCH 43/46] update make file --- .settings/language.settings.xml | 8 ++++---- Makefile | 2 +- components/wifi-manager/_esp_httpd_main.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 0f39020e..6a5fc805 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -77,7 +77,7 @@ - + diff --git a/Makefile b/Makefile index bfbb0778..5650443a 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ #recovery: EXTRA_CPPFLAGS+=-DRECOVERY_APPLICATION=1 PROJECT_NAME?=squeezelite -EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main -I$(IDF_PATH)/components/esp_http_server/src -I$(IDF_PATH)/components/esp_http_server/src/port/esp32 -I$(IDF_PATH)/components/esp_http_server/src/util +EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main -I$(IDF_PATH)/components/esp_http_server/src -I$(IDF_PATH)/components/esp_http_server/src/port/esp32 -I$(IDF_PATH)/components/esp_http_server/src/util -I$(IDF_PATH)/components/esp_http_server/src/ #/-Wno-error=maybe-uninitialized include $(IDF_PATH)/make/project.mk diff --git a/components/wifi-manager/_esp_httpd_main.c b/components/wifi-manager/_esp_httpd_main.c index af6faefa..255f6d78 100644 --- a/components/wifi-manager/_esp_httpd_main.c +++ b/components/wifi-manager/_esp_httpd_main.c @@ -22,8 +22,8 @@ #include #include <_esp_http_server.h> -#include "../src/esp_httpd_priv.h" -#include "../src/util/ctrl_sock.h" +#include "esp_httpd_priv.h" +#include "ctrl_sock.h" static const char *TAG = "_httpd"; From f613487c4dd1b968500606f0a2333235af96adc1 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Wed, 4 Mar 2020 14:40:44 -0500 Subject: [PATCH 44/46] adjusting makefiles for http compile in linux --- .cproject | 4 +++- Makefile | 3 ++- components/wifi-manager/component.mk | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.cproject b/.cproject index 22fe7e14..0db5e150 100644 --- a/.cproject +++ b/.cproject @@ -233,7 +233,7 @@ - + @@ -399,6 +399,8 @@ + + diff --git a/Makefile b/Makefile index 5650443a..51ac175c 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,8 @@ #recovery: EXTRA_CPPFLAGS+=-DRECOVERY_APPLICATION=1 PROJECT_NAME?=squeezelite -EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main -I$(IDF_PATH)/components/esp_http_server/src -I$(IDF_PATH)/components/esp_http_server/src/port/esp32 -I$(IDF_PATH)/components/esp_http_server/src/util -I$(IDF_PATH)/components/esp_http_server/src/ +EXTRA_CPPFLAGS+= -I$(PROJECT_PATH)/main + #/-Wno-error=maybe-uninitialized include $(IDF_PATH)/make/project.mk diff --git a/components/wifi-manager/component.mk b/components/wifi-manager/component.mk index 4a5d5006..491db5eb 100644 --- a/components/wifi-manager/component.mk +++ b/components/wifi-manager/component.mk @@ -7,7 +7,8 @@ # please read the SDK documents if you need to do this. # COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz -COMPONENT_ADD_INCLUDEDIRS := . $(IDF_PATH)/components/esp_http_server/src $(IDF_PATH)/components/esp_http_server/src/port/esp32 $(IDF_PATH)/components/esp_http_server/src/util +COMPONENT_ADD_INCLUDEDIRS := . +COMPONENT_EXTRA_INCLUDES += $(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/ CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO From 69ba176990aad5939852629ad73015168cdead67 Mon Sep 17 00:00:00 2001 From: Christian Herzog Date: Thu, 5 Mar 2020 18:41:47 +0100 Subject: [PATCH 45/46] get rid of duplicate resource links --- components/wifi-manager/index.html | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index cdd97274..c798b48e 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -5,21 +5,11 @@ - - - - - - - - - - esp32-wifi-manager From 93dbaa516a6da0776fc6f3c8e7fe96822cda32f3 Mon Sep 17 00:00:00 2001 From: Christian Herzog Date: Thu, 5 Mar 2020 20:50:36 +0100 Subject: [PATCH 46/46] start with syslog --- components/wifi-manager/code.js | 31 +++++--- components/wifi-manager/index.html | 114 +++++++++++------------------ components/wifi-manager/style.css | 18 +++-- 3 files changed, 76 insertions(+), 87 deletions(-) diff --git a/components/wifi-manager/code.js b/components/wifi-manager/code.js index 139c8b2f..17093d99 100644 --- a/components/wifi-manager/code.js +++ b/components/wifi-manager/code.js @@ -40,7 +40,6 @@ var commandHeader = 'squeezelite -b 500:2000 -d all=info '; var pname, ver, otapct, otadsc; var blockAjax = false; var blockFlashButton = false; -var lastMsg = ''; var apList = null; var selectedSSID = ""; @@ -655,11 +654,11 @@ function refreshAPHTML(data){ } function getMessages() { - $.getJSON("/messages.json", function(data) { + $.getJSON("/messages.json?1", function(data) { data.forEach(function(msg) { var msg_age = msg["current_time"] - msg["sent_time"]; - var msg_time = new Date( ); - msg_time.setTime( msg_time .getTime() - msg_age ); + var msg_time = new Date(); + msg_time.setTime( msg_time.getTime() - msg_age ); switch (msg["class"]) { case "MESSAGING_CLASS_OTA": //message: "{"ota_dsc":"Erasing flash complete","ota_pct":0}" @@ -681,16 +680,22 @@ function getMessages() { case "MESSAGING_CLASS_STATS": // for task states, check structure : task_state_t var stats_data = JSON.parse(msg["message"]); - console.log(msg_time + " - Number of tasks on the ESP32: " + stats_data["ntasks"]); + console.log(msg_time.toLocaleString() + " - Number of tasks on the ESP32: " + stats_data["ntasks"]); var stats_tasks = stats_data["tasks"]; - console.log(msg_time + '\tname' + '\tcpu' + '\tstate'+ '\tminstk'+ '\tbprio'+ '\tcprio'+ '\tnum' ); + console.log(msg_time.toLocaleString() + '\tname' + '\tcpu' + '\tstate'+ '\tminstk'+ '\tbprio'+ '\tcprio'+ '\tnum' ); stats_tasks.forEach(function(task) { - console.log(msg_time + '\t' + task["nme"] + '\t'+ task["cpu"] + '\t'+ task_state_t[task["st"]]+ '\t'+ task["minstk"]+ '\t'+ task["bprio"]+ '\t'+ task["cprio"]+ '\t'+ task["num"]); + console.log(msg_time.toLocaleString() + '\t' + task["nme"] + '\t'+ task["cpu"] + '\t'+ task_state_t[task["st"]]+ '\t'+ task["minstk"]+ '\t'+ task["bprio"]+ '\t'+ task["cprio"]+ '\t'+ task["num"]); }); break; case "MESSAGING_CLASS_SYSTEM": showMessage(msg["message"], msg["type"],msg_age); - lastMsg = msg; + + $("#syslogTable").append( + ""+ + ""+msg_time.toLocaleString()+""+ + ""+msg["message"]+""+ + "" + ); break; default: break; @@ -703,6 +708,14 @@ function getMessages() { console.log(thrownError); if (thrownError != '') showMessage(thrownError, 'MESSAGING_ERROR'); }); + /* + Minstk is minimum stack space left +Bprio is base priority +cprio is current priority +nme is name +st is task state. I provided a "typedef" that you can use to convert to text +cpu is cpu percent used +*/ } function checkStatus(){ RepeatCheckStatusInterval(); @@ -924,7 +937,6 @@ function getConfig() { function showMessage(message, severity, age=0) { - if (severity == 'MESSAGING_INFO') { $('#message').css('background', '#6af'); } else if (severity == 'MESSAGING_WARNING') { @@ -935,7 +947,6 @@ function showMessage(message, severity, age=0) { $('#message').css('background', '#f00'); } - $('#message').html(message); $("#content").fadeTo("slow", 0.3, function() { $("#message").show(500).delay(5000).hide(500, function() { diff --git a/components/wifi-manager/index.html b/components/wifi-manager/index.html index c798b48e..445bd99a 100644 --- a/components/wifi-manager/index.html +++ b/components/wifi-manager/index.html @@ -67,7 +67,7 @@ Firmware
-
+
@@ -240,72 +240,7 @@

-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
SignalI2S pinSPDIF pin
Bit clock - - - -
Word select - - - -
Data - - - -
-
- -
-
- -
- - - - - - - - - -
KeyValue
-
-
-
- -
-
- -
-
+
@@ -354,11 +289,48 @@
-
+ + +
+ + + + + + + + + +
TimestampMessage
+
+ +
+
+ +
+ + + + + + + + + +
KeyValue
+
+
+
+ +
+
+ +
+
-

squeezelite-esp32, © 2019, philippe44, sle118, daduke
Licensed under the GPL

+

squeezelite-esp32, © 2020, philippe44, sle118, daduke
Licensed under the GPL

This app would not be possible without the following libraries:

@@ -377,7 +349,7 @@
-
+
diff --git a/components/wifi-manager/style.css b/components/wifi-manager/style.css index 1e4ea057..bd2a170a 100644 --- a/components/wifi-manager/style.css +++ b/components/wifi-manager/style.css @@ -212,12 +212,6 @@ input[type='text'], input[type='password'], textarea { padding: 4px; } -input.gpio { - width: 2em; - color: #000; - height: 1.8em; -} - .custom-switch { margin-left: 8px; } @@ -273,6 +267,18 @@ textarea#autoexec1, textarea#fwurl, div#upload { width: 80%; } +table tr.MESSAGING_INFO { + background: #123; +} + +table tr.MESSAGING_WARNING { + background: #330; +} + +table tr.MESSAGING_ERROR { + background: #300; +} + input, textarea { border-radius: 3px; border: 1px solid transparent;