diff --git a/components/display/CMakeLists.txt b/components/display/CMakeLists.txt index 51ccf43a..f4be08e0 100644 --- a/components/display/CMakeLists.txt +++ b/components/display/CMakeLists.txt @@ -2,7 +2,7 @@ idf_component_register(SRC_DIRS . core core/ifaces fonts INCLUDE_DIRS . fonts core REQUIRES platform_config tools esp_common - PRIV_REQUIRES services freertos driver + PRIV_REQUIRES services freertos driver ) set_source_files_properties(display.c diff --git a/components/display/core/ifaces/default_if_i2c.c b/components/display/core/ifaces/default_if_i2c.c index a7545b45..661de93e 100644 --- a/components/display/core/ifaces/default_if_i2c.c +++ b/components/display/core/ifaces/default_if_i2c.c @@ -15,6 +15,7 @@ #include "gds_err.h" #include "gds_private.h" #include "gds_default_if.h" +#include "messaging.h" static int I2CPortNumber; static int I2CWait; @@ -89,6 +90,12 @@ bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int static bool I2CDefaultWriteBytes( int Address, bool IsCommand, const uint8_t* Data, size_t DataLength ) { i2c_cmd_handle_t* CommandHandle = NULL; static uint8_t ModeByte = 0; + static uint32_t failures=0; + if(failures > 1000){ + ESP_LOGE("I2C_Display","I2C Write failure"); + failures = 1; + return false; + } NullCheck( Data, return false ); @@ -108,6 +115,10 @@ static bool I2CDefaultWriteBytes( int Address, bool IsCommand, const uint8_t* Da return true; error: + + if(++failures == 1){ + messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM, "Display communication failed."); + } if (CommandHandle) i2c_cmd_link_delete( CommandHandle ); return false; } diff --git a/components/platform_console/CMakeLists.txt b/components/platform_console/CMakeLists.txt index 8dc3e512..4eedf5b3 100644 --- a/components/platform_console/CMakeLists.txt +++ b/components/platform_console/CMakeLists.txt @@ -7,6 +7,6 @@ idf_component_register( SRCS platform_console.c INCLUDE_DIRS . REQUIRES nvs_flash - PRIV_REQUIRES console tools services spi_flash app_update platform_config vfs pthread wifi-manager platform_config newlib telnet display) + PRIV_REQUIRES console tools services spi_flash app_update platform_config vfs pthread wifi-manager platform_config newlib telnet ) target_link_libraries(${COMPONENT_LIB} ${build_dir}/esp-idf/$/lib$.a ) diff --git a/components/platform_console/cmd_system.c b/components/platform_console/cmd_system.c index f6ee7bc8..c4509556 100644 --- a/components/platform_console/cmd_system.c +++ b/components/platform_console/cmd_system.c @@ -146,7 +146,7 @@ else { if(err!=ESP_OK){ ESP_LOGE(TAG,"Unable to set partition as active for next boot. %s",esp_err_to_name(err)); bFound=false; - messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Unable to select partition for reboot."); + messaging_post_message(MESSAGING_ERROR,MESSAGING_CLASS_SYSTEM,"Unable to select partition for reboot: %s",esp_err_to_name(err)); } else{ ESP_LOGW(TAG, "Application partition %s sub type %u is selected for boot", partition->label,partition_subtype); diff --git a/components/platform_console/platform_console.c b/components/platform_console/platform_console.c index 73f9309e..eaabd120 100644 --- a/components/platform_console/platform_console.c +++ b/components/platform_console/platform_console.c @@ -29,12 +29,7 @@ #include "platform_config.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 "display.h" + #include "config.h" pthread_t thread_console; @@ -48,6 +43,7 @@ extern void register_squeezelite(); * This can be customized, made dynamic, etc. */ const char* prompt = LOG_COLOR_I "squeezelite-esp32> " LOG_RESET_COLOR; +const char* recovery_prompt = LOG_COLOR_E "recovery-squeezelite-esp32> " LOG_RESET_COLOR; /* Console command history can be stored to and loaded from a file. * The easiest way to do this is to use FATFS filesystem on top of @@ -161,11 +157,6 @@ void initialize_console() { } void console_start() { - if(is_recovery_running){ - 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"); - } if(!is_serial_suppressed()){ initialize_console(); } @@ -224,13 +215,18 @@ void console_start() { /* Since the terminal doesn't support escape sequences, * don't use color codes in the prompt. */ + if(is_recovery_running){ + recovery_prompt= "recovery-squeezelite-esp32>"; + } 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(is_recovery_running){ + prompt = recovery_prompt; cfg.stack_size = 4096 ; } esp_pthread_set_cfg(&cfg); diff --git a/components/squeezelite-ota/squeezelite-ota.c b/components/squeezelite-ota/squeezelite-ota.c index 16e541ab..bf322810 100644 --- a/components/squeezelite-ota/squeezelite-ota.c +++ b/components/squeezelite-ota/squeezelite-ota.c @@ -110,6 +110,9 @@ typedef struct _progress { } progress_t; static progress_t * loc_displayer_get_progress_dft(){ + if(!display){ + return; + } int start_coord_offset=0; static progress_t def={ .border_thickness = 2, @@ -141,6 +144,9 @@ static progress_t * loc_displayer_get_progress_dft(){ } static void loc_displayer_progressbar(uint8_t pct){ static progress_t * progress_coordinates; + if(!display){ + return; + } 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); @@ -182,7 +188,10 @@ void sendMessaging(messaging_types type,const char * fmt, ...){ } va_end(args); if(type!=MESSAGING_INFO){ - GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, msg_str); + + if(display) { + GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, msg_str); + } } cJSON_AddStringToObject(msg,"ota_dsc",str_or_unknown(msg_str)); diff --git a/components/wifi-manager/http_server.c b/components/wifi-manager/http_server.c deleted file mode 100644 index d6fdc248..00000000 --- a/components/wifi-manager/http_server.c +++ /dev/null @@ -1,652 +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 "platform_config.h" -#include "platform_esp32.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; -static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE]; -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(is_recovery_running){ - ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL); - } - else{ - ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL); - } - 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/http_server.h b/components/wifi-manager/http_server.h deleted file mode 100644 index 5472d96c..00000000 --- a/components/wifi-manager/http_server.h +++ /dev/null @@ -1,104 +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.h -@author Tony Pottier -@brief Defines all functions necessary for the HTTP server to run. - -Contains the freeRTOS task for the HTTP listener and all necessary support -function to process requests, decode URLs, serve files, etc. etc. - -@note http_server task cannot run without the wifi_manager task! -@see https://idyl.io -@see https://github.com/tonyp7/esp32-wifi-manager -*/ - -#ifndef HTTP_SERVER_H_INCLUDED -#define HTTP_SERVER_H_INCLUDED -#include -#include -#include -#include -#include "wifi_manager.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" -#include "esp_wifi.h" -#include "esp_event_loop.h" -#include "nvs_flash.h" -#include "esp_log.h" -#include "driver/gpio.h" -#include "mdns.h" -#include "lwip/api.h" -#include "lwip/err.h" -#include "lwip/netdb.h" -#include "lwip/opt.h" -#include "lwip/memp.h" -#include "lwip/ip.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/priv/api_msg.h" -#include "lwip/priv/tcp_priv.h" -#include "lwip/priv/tcpip_priv.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief RTOS task for the HTTP server. Do not start manually. - * @see void http_server_start() - */ -void http_server(void *pvParameters); - -/* @brief helper function that processes one HTTP request at a time */ -void http_server_netconn_serve(struct netconn *conn); - -/* @brief create the task for the http server */ -void http_server_start(); - -/** - * @brief gets a char* pointer to the first occurence of header_name withing the complete http request request. - * - * For optimization purposes, no local copy is made. memcpy can then be used in coordination with len to extract the - * data. - * - * @param request the full HTTP raw request. - * @param header_name the header that is being searched. - * @param len the size of the header value if found. - * @return pointer to the beginning of the header value. - */ -char* http_server_get_header(char *request, char *header_name, int *len); - -void strreplace(char *src, char *str, char *rep); -/* @brief lock the json config object */ -bool http_server_lock_json_object(TickType_t xTicksToWait); -/* @brief unlock the json config object */ -void http_server_unlock_json_object(); -#define PROTECTED_JSON_CALL(a) if(http_server_lock_json_object( portMAX_DELAY )){ \ a; http_server_unlocklock_json_object(); } else{ ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan"); } - - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/wifi-manager/http_server_handlers.c b/components/wifi-manager/http_server_handlers.c index 6607d912..d16e4be4 100644 --- a/components/wifi-manager/http_server_handlers.c +++ b/components/wifi-manager/http_server_handlers.c @@ -32,7 +32,7 @@ function to process requests, decode URLs, serve files, etc. etc. */ #include "http_server_handlers.h" - +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include "esp_http_server.h" #include "cmd_system.h" #include @@ -101,19 +101,6 @@ 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"; esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error); @@ -393,6 +380,7 @@ esp_err_t root_get_handler(httpd_req_t *req){ if(err == ESP_OK){ httpd_resp_send(req, (const char *)index_html_start, file_size); } + ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri); return err; } @@ -495,6 +483,7 @@ esp_err_t ap_get_handler(httpd_req_t *req){ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "AP list unavailable"); ESP_LOGE_LOC(TAG, "GET /ap.json failed to obtain mutex"); } + ESP_LOGD_LOC(TAG, "done serving [%s]", req->uri); return err; } diff --git a/components/wifi-manager/wifi_manager_http_server.c b/components/wifi-manager/wifi_manager_http_server.c index 207283a8..73c81304 100644 --- a/components/wifi-manager/wifi_manager_http_server.c +++ b/components/wifi-manager/wifi_manager_http_server.c @@ -125,7 +125,7 @@ esp_err_t http_server_start() httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.max_uri_handlers = 25; - config.max_open_sockets = 5; + config.max_open_sockets = 8; config.uri_match_fn = httpd_uri_match_wildcard; //todo: use the endpoint below to configure session token? // config.open_fn diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 2186e0b4..0acea0a6 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRC_DIRS . - PRIV_REQUIRES esp_common wifi-manager pthread squeezelite-ota platform_console telnet + PRIV_REQUIRES esp_common display wifi-manager pthread squeezelite-ota platform_console telnet INCLUDE_DIRS . EMBED_FILES ../server_certs/github.pem ) diff --git a/main/esp_app_main.c b/main/esp_app_main.c index 1650ccda..3361e9fc 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -49,7 +49,12 @@ #include "platform_config.h" #include "telnet.h" #include "messaging.h" - +#include "gds.h" +#include "gds_default_if.h" +#include "gds_draw.h" +#include "gds_text.h" +#include "gds_font.h" +#include "display.h" static const char certs_namespace[] = "certificates"; static const char certs_key[] = "blob"; static const char certs_version[] = "version"; @@ -386,6 +391,11 @@ void app_main() ESP_LOGI(TAG,"Initializing display"); display_init("SqueezeESP32"); + if(is_recovery_running && display){ + 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"); + } if(!is_recovery_running){ ESP_LOGI(TAG,"Checking if certificates need to be updated"); diff --git a/partitions.csv b/partitions.csv index e166f2a7..6fccc679 100644 --- a/partitions.csv +++ b/partitions.csv @@ -3,8 +3,8 @@ nvs, data, nvs, 0x9000, 0x4000, otadata, data, ota, 0xD000, 0x2000, phy_init, data, phy, 0xF000, 0x1000, -recovery, app, factory, 0x10000, 0x155f90 -ota_0, app, ota_0, , 0x270070, +recovery, app, factory, 0x10000, 0x140000, +ota_0, app, ota_0, , 0x2A0000, #ota_0, app, ota_0, 0x10000, 0x140000, #recovery, app, factory, , 0x2A0000, -settings, data, nvs, , 0x10000, +settings, data, nvs, , 0x10000, \ No newline at end of file