prepare FW upload

This commit is contained in:
Christian Herzog
2019-11-23 20:09:09 +01:00
105 changed files with 3086 additions and 40198 deletions

View File

@@ -1,7 +1,8 @@
idf_component_register(SRCS "dns_server.c" "http_server.c" "json.c" "wifi_manager.c"
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 json
PRIV_REQUIRES newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant cmd_system
EMBED_FILES style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz
)

View File

@@ -28,7 +28,7 @@ var checkStatusInterval = null;
var StatusIntervalActive = false;
var RefreshAPIIntervalActive = false;
var LastRecoveryState=null;
var output = '';
function stopCheckStatusInterval(){
@@ -54,7 +54,7 @@ function startCheckStatusInterval(){
function startRefreshAPInterval(){
RefreshAPIIntervalActive = true;
refreshAPInterval = setTimeout(refreshAP(false), 2800);
refreshAPInterval = setTimeout(refreshAP(false), 4500); // leave enough time for the initial scan
}
function RepeatCheckStatusInterval(){
@@ -176,6 +176,16 @@ $(document).ready(function(){
$( "#wifi" ).slideDown( "fast", function() {})
});
$("input#show-nvs").on("click", function() {
this.checked=this.checked?1:0;
if(this.checked){
$('a[href^="#tab-nvs"]').show();
} else {
$('a[href^="#tab-nvs"]').hide();
}
});
$("input#autoexec-cb").on("click", function() {
var data = { 'timestamp': Date.now() };
autoexec = (this.checked)?1:0;
@@ -200,7 +210,7 @@ $(document).ready(function(){
console.log('sent config JSON with headers:', autoexec);
console.log('now triggering reboot');
$.ajax({
url: '/reboot.json',
url: '/reboot_ota.json',
dataType: 'text',
method: 'POST',
cache: false,
@@ -279,14 +289,17 @@ $(document).ready(function(){
var val = $(this).val();
if (key != '') {
headers["X-Custom-"+key] = val;
data[key] = val;
data[key] = {};
data[key].value = val;
data[key].type = 33;
}
});
var key = $("#nvs-new-key").val();
var val = $("#nvs-new-value").val();
if (key != '') {
headers["X-Custom-"+key] = val;
data[key] = val;
data[key] = {};
data[key].value = val;
}
$.ajax({
url: '/config.json',
@@ -429,7 +442,10 @@ $(document).ready(function(){
$('#boot-button').on("click", function(){
enableStatusTimer = true;
});
$('#reboot-button').on("click", function(){
enableStatusTimer = true;
});
$('#updateAP').on("click", function(){
refreshAP(true);
console.log("refresh AP");
@@ -441,7 +457,7 @@ $(document).ready(function(){
//start timers
startCheckStatusInterval();
startRefreshAPInterval();
//startRefreshAPInterval();
$('[data-toggle="tooltip"]').tooltip({
html: true,
@@ -572,7 +588,7 @@ function checkStatus(){
//update wait screen
$( "#loading" ).hide();
$( "#connect-success" ).append("<p>Your IP address now is: " + text(data["ip"]) + "</p>");
$( "#connect-success" ).text("Your IP address now is: " + data["ip"] );
$( "#connect-success" ).show();
$( "#connect-fail" ).hide();
@@ -628,23 +644,31 @@ function checkStatus(){
enableStatusTimer = true;
}
if (data.hasOwnProperty('recovery')) {
if(LastRecoveryState != data["recovery"]){
LastRecoveryState = data["recovery"];
$("input#show-nvs")[0].checked=LastRecoveryState==1?true:false;
}
if($("input#show-nvs")[0].checked){
$('a[href^="#tab-nvs"]').show();
} else{
$('a[href^="#tab-nvs"]').hide();
}
if (data["recovery"] === 1) {
recovery = true;
$("#otadiv").show();
$('a[href^="#tab-audio"]').hide();
$('a[href^="#tab-gpio"]').show();
$('a[href^="#tab-nvs"]').show();
$("footer.footer").removeClass('sl');
$("footer.footer").addClass('recovery');
$("#boot-button").html('Reboot');
$("#boot-form").attr('action', '/reboot.json');
$("#boot-form").attr('action', '/reboot_ota.json');
enableStatusTimer = true;
} else {
recovery = false;
$("#otadiv").hide();
$('a[href^="#tab-audio"]').show();
$('a[href^="#tab-gpio"]').hide();
$('a[href^="#tab-nvs"]').hide();
$("footer.footer").removeClass('recovery');
$("footer.footer").addClass('sl');
$("#boot-button").html('Recovery');
@@ -697,16 +721,16 @@ function getConfig() {
Object.keys(data).sort().forEach(function(key, i) {
if (data.hasOwnProperty(key)) {
if (key == 'autoexec') {
if (data["autoexec"] === "1") {
if (data["autoexec"].value === "1") {
$("#autoexec-cb")[0].checked=true;
} else {
$("#autoexec-cb")[0].checked=false;
}
} else if (key == 'autoexec1') {
$("textarea#autoexec1").val(data[key]);
$("textarea#autoexec1").val(data[key].value);
} else if (key == 'host_name') {
$("dhcp-name1").val(data[key]);
$("dhcp-name2").val(data[key]);
$("dhcp-name1").val(data[key].value);
$("dhcp-name2").val(data[key].value);
}
$("tbody#nvsTable").append(
@@ -717,7 +741,7 @@ function getConfig() {
"</td>"+
"</tr>"
);
$("input#"+key).val(data[key]);
$("input#"+key).val(data[key].value);
}
});
$("tbody#nvsTable").append(

View File

@@ -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
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

View File

@@ -42,14 +42,20 @@ function to process requests, decode URLs, serve files, etc. etc.
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "config.h"
#define NVS_PARTITION_NAME "nvs"
#define NUM_BUFFER_LEN 101
#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;
/**
@@ -86,13 +92,11 @@ const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: htt
const static char http_redirect_hdr_end[] = "/\n\n";
void http_server_start() {
ESP_LOGD(TAG, "http_server_start ");
if(task_http_server == NULL) {
xTaskCreate(&http_server, "http_server", 1024*5, NULL, WIFI_MANAGER_TASK_PRIORITY, &task_http_server);
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) {
@@ -102,7 +106,7 @@ void http_server(void *pvParameters) {
conn = netconn_new(NETCONN_TCP);
netconn_bind(conn, IP_ADDR_ANY, 80);
netconn_listen(conn);
ESP_LOGI(TAG, "HTTP Server listening on 80/tcp");
ESP_LOGI(TAG, "HTTP Server listening on 80/tcp");
do {
err = netconn_accept(conn, &newconn);
if(err == ERR_OK) {
@@ -111,7 +115,7 @@ void http_server(void *pvParameters) {
}
else
{
ESP_LOGE(TAG,"Error accepting new connection. Terminating HTTP server");
ESP_LOGE(TAG, "Error accepting new connection. Terminating HTTP server");
}
taskYIELD(); /* allows the freeRTOS scheduler to take over if needed. */
} while(err == ERR_OK);
@@ -147,7 +151,7 @@ char* http_server_search_header(char *request, char *header_name, int *len, char
char *ptr = NULL;
int currentLength=0;
ESP_LOGV(TAG, "searching for header name: [%s]", header_name);
ESP_LOGV(TAG, "searching for header name: [%s]", header_name);
ptr = strstr(request, header_name);
@@ -155,23 +159,23 @@ char* http_server_search_header(char *request, char *header_name, int *len, char
ret = ptr + strlen(header_name);
ptr = ret;
currentLength=(int)(ptr-request);
ESP_LOGV(TAG, "found string at %d", currentLength);
ESP_LOGV(TAG, "found string at %d", currentLength);
while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r' && *ptr != ':' && ptr<bufEnd) {
ptr++;
}
if(*ptr==':') {
currentLength=(int)(ptr-ret);
ESP_LOGV(TAG, "Found parameter name end, length : %d", currentLength);
ESP_LOGV(TAG, "Found parameter name end, length : %d", currentLength);
// save the parameter name: the string between header name and ":"
*parm_name=malloc(currentLength+1);
if(*parm_name==NULL) {
ESP_LOGE(TAG, "Unable to allocate memory for new header name");
ESP_LOGE(TAG, "Unable to allocate memory for new header name");
return NULL;
}
memset(*parm_name, 0x00,currentLength+1);
strncpy(*parm_name,ret,currentLength);
ESP_LOGV(TAG, "Found parameter name : %s ", *parm_name);
ESP_LOGV(TAG, "Found parameter name : %s ", *parm_name);
ptr++;
while (*ptr == ' ' && ptr<bufEnd) {
ptr++;
@@ -186,12 +190,12 @@ char* http_server_search_header(char *request, char *header_name, int *len, char
// Terminate value inside its actual buffer so we can treat it as individual string
*ptr='\0';
currentLength=(int)(ptr-ret);
ESP_LOGV(TAG, "Found parameter value end, length : %d, value: %s", currentLength,ret );
ESP_LOGV(TAG, "Found parameter value end, length : %d, value: %s", currentLength,ret );
*next_position=++ptr;
return ret;
}
ESP_LOGD(TAG, "No more match for : %s", header_name);
ESP_LOGD(TAG, "No more match for : %s", header_name);
return NULL;
}
void http_server_send_resource_file(struct netconn *conn,const uint8_t * start, const uint8_t * end, char * content_type,char * encoding) {
@@ -199,7 +203,7 @@ void http_server_send_resource_file(struct netconn *conn,const uint8_t * start,
size_t buff_length= sizeof(http_hdr_template)+strlen(content_type)+strlen(encoding);
char * http_hdr=malloc(buff_length);
if( http_hdr == NULL) {
ESP_LOGE(TAG,"Cound not allocate %d bytes for headers.",buff_length);
ESP_LOGE(TAG, "Cound not allocate %d bytes for headers.",buff_length);
netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
}
else
@@ -207,73 +211,25 @@ void http_server_send_resource_file(struct netconn *conn,const uint8_t * start,
memset(http_hdr,0x00,buff_length);
snprintf(http_hdr, buff_length-1,http_hdr_template,content_type,len,encoding);
netconn_write(conn, http_hdr, strlen(http_hdr), NETCONN_NOCOPY);
ESP_LOGD(TAG,"sending response : %s",http_hdr);
ESP_LOGD(TAG, "sending response : %s",http_hdr);
netconn_write(conn, start, end - start, NETCONN_NOCOPY);
free(http_hdr);
}
}
err_t http_server_nvs_dump(struct netconn *conn, nvs_type_t nvs_type) {
nvs_entry_info_t info;
char * num_buffer = NULL;
cJSON * nvs_json = cJSON_CreateObject();
num_buffer = malloc(NUM_BUFFER_LEN);
nvs_iterator_t it = nvs_entry_find(settings_partition, NULL, nvs_type);
if(it == NULL) {
ESP_LOGW(TAG, "No nvs entry found in %s",NVS_PARTITION_NAME );
err_t http_server_send_config_json(struct netconn *conn) {
char * json = config_alloc_get_json(false);
if(json!=NULL){
ESP_LOGD(TAG, "config json : %s",json );
netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY);
netconn_write(conn, json, strlen(json), NETCONN_NOCOPY);
free(json);
}
while (it != NULL) {
nvs_entry_info(it, &info);
memset(num_buffer,0x00,NUM_BUFFER_LEN);
if(strstr(info.namespace_name, current_namespace)) {
void * value = get_nvs_value_alloc(nvs_type,info.key);
if(value==NULL)
{
ESP_LOGE(TAG,"nvs read failed.");
netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY); //200ok
free(num_buffer);
cJSON_Delete(nvs_json);
return ESP_FAIL;
}
switch (nvs_type) {
case NVS_TYPE_I8:
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%i", *(int8_t*)value);
break;
case NVS_TYPE_I16:
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%i", *(int16_t*)value);
break;
case NVS_TYPE_I32:
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%i", *(int32_t*)value);
break;
case NVS_TYPE_U8:
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%u", *(uint8_t*)value);
break;
case NVS_TYPE_U16:
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%u", *(uint16_t*)value);
break;
case NVS_TYPE_U32:
snprintf(num_buffer, NUM_BUFFER_LEN-1, "%u", *(uint32_t*)value);
break;
case NVS_TYPE_STR:
// string will be processed directly below
break;
case NVS_TYPE_I64:
case NVS_TYPE_U64:
default:
ESP_LOGE(TAG, "nvs type %u not supported", nvs_type);
break;
}
cJSON_AddItemToObject(nvs_json, info.key, cJSON_CreateString((nvs_type==NVS_TYPE_STR)?(char *)value:num_buffer));
free(value );
}
it = nvs_entry_next(it);
else{
ESP_LOGD(TAG, "Error retrieving config json string. ");
netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
}
ESP_LOGD(TAG,"config json : %s\n", cJSON_Print(nvs_json));
netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY);
netconn_write(conn, cJSON_Print(nvs_json), strlen(cJSON_Print(nvs_json)), NETCONN_NOCOPY);
cJSON_Delete(nvs_json);
free(num_buffer);
return ESP_OK;
}
@@ -288,8 +244,8 @@ void http_server_process_config(struct netconn *conn, char *inbuf) {
// /* extract the first line of the request */
// char *save_ptr = buf;
// char *line = strtok_r(save_ptr, new_line, &save_ptr);
// ESP_LOGD(TAG,"Processing line %s",line);
ESP_LOGD(TAG,"Processing request buffer: \n%s",inbuf);
// ESP_LOGD(TAG, "Processing line %s",line);
ESP_LOGD(TAG, "Processing request buffer: \n%s",inbuf);
char *last = NULL;
char *ptr = NULL;
last = ptr = inbuf;
@@ -302,7 +258,7 @@ void http_server_process_config(struct netconn *conn, char *inbuf) {
}
// terminate the header string
if( *(ptr) == '\0' ) {
ESP_LOGD(TAG, "End of buffer found");
ESP_LOGD(TAG, "End of buffer found");
return;
}
*ptr = '\0';
@@ -311,21 +267,21 @@ void http_server_process_config(struct netconn *conn, char *inbuf) {
ptr+=2;
}
if(ptr==last) {
ESP_LOGD(TAG,"Processing body. ");
ESP_LOGD(TAG, "Processing body. ");
break;
}
if(strlen(last)>0) {
ESP_LOGD(TAG,"Found Header Line %s ", last);
ESP_LOGD(TAG, "Found Header Line %s ", last);
//Content-Type: application/json
}
else {
ESP_LOGD(TAG,"Found end of headers");
ESP_LOGD(TAG, "Found end of headers");
bHeaders = false;
}
last=ptr;
}
else {
//ESP_LOGD(TAG,"Body content: %s", last);
//ESP_LOGD(TAG, "Body content: %s", last);
//cJSON * json = cJSON_Parse(last);
//cJSON_Delete(json);
//todo: implement body json parsing
@@ -339,13 +295,13 @@ void http_server_process_config(struct netconn *conn, char *inbuf) {
void dump_net_buffer(void * buf, u16_t buflen) {
char * curbuf = malloc(buflen+1);
ESP_LOGD(TAG,"netconn buffer, length=%u",buflen);
ESP_LOGV(TAG, "netconn buffer, length=%u",buflen);
if(curbuf==NULL) {
ESP_LOGE(TAG,"Unable to show netconn buffer. Malloc failed");
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);
ESP_LOGV(TAG, "netconn buffer content:\n%s",curbuf);
free(curbuf);
}
@@ -355,39 +311,59 @@ void http_server_netconn_serve(struct netconn *conn) {
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);
ESP_LOGD(TAG,"http_server_netconn_serve Processing line %s",line);
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 */
int lenH = 0;
char *host = http_server_get_header(save_ptr, "Host: ", &lenH);
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));
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?strstr(host, wifi_manager_get_sta_ip_string()):false;
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) && strstr(host, host_name);
bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name);
if(lenH > 0 && !strstr(host, DEFAULT_AP_IP) && !(access_from_sta_ip || access_from_host_name)) {
ESP_LOGI(TAG,"Redirecting to default AP IP Address : %s", DEFAULT_AP_IP);
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, DEFAULT_AP_IP, sizeof(DEFAULT_AP_IP) - 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 {
@@ -419,32 +395,43 @@ void http_server_netconn_serve(struct netconn *conn) {
}
//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");
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_get_ap_list_json();
netconn_write(conn, buff, strlen(buff), 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");
ESP_LOGE(TAG, "http_server_netconn_serve: GET /ap.json failed to obtain mutex");
}
/* request a wifi scan */
ESP_LOGI(TAG,"Starting wifi scan");
ESP_LOGI(TAG, "Starting wifi scan");
wifi_manager_scan_async();
ESP_LOGI(TAG,"Done serving ap.json");
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_nvs_dump(conn,NVS_TYPE_STR);
ESP_LOGD(TAG,"Done serving 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");
ESP_LOGI(TAG, "Serving POST config.json");
int lenA=0;
char * last_parm=save_ptr;
char * next_parm=save_ptr;
@@ -457,20 +444,21 @@ void http_server_netconn_serve(struct netconn *conn) {
while(last_parm!=NULL) {
// Search will return
ESP_LOGD(TAG, "Getting parameters from X-Custom headers");
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);
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!");
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");
err= store_nvs_value(NVS_TYPE_STR, last_parm_name , last_parm);
if(err!=ESP_OK) ESP_LOGE(TAG,"Unable to save nvs value. Error: %s",esp_err_to_name(err));
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) {
@@ -484,106 +472,121 @@ void http_server_netconn_serve(struct netconn *conn) {
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);
ESP_LOGW(TAG, "Starting process OTA for url %s",otaURL);
#else
ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL);
// close the connection cleanly
netconn_close(conn);
netconn_delete(conn);
ESP_LOGW(TAG, "Restarting system to process OTA for url %s",otaURL);
#endif
start_ota(otaURL,false);
wifi_manager_reboot_ota(otaURL);
free(otaURL);
}
}
ESP_LOGI(TAG,"Done Serving POST config.json");
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");
ESP_LOGI(TAG, "http_server_netconn_serve: POST /connect.json");
bool found = false;
int lenS = 0, lenP = 0;
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", ssid, password);
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_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");
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");
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");
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_close(conn);
netconn_delete(conn);
guided_restart_ota();
ESP_LOGI(TAG, "http_server_netconn_serve: done serving 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_close(conn);
netconn_delete(conn);
guided_factory();
ESP_LOGI(TAG, "http_server_netconn_serve: done serving 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");
ESP_LOGI(TAG, "Serving status.json");
if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) {
char *buff = wifi_manager_get_ip_info_json();
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);
}
wifi_manager_unlock_json_buffer();
}
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_LOGE(TAG, "http_server_netconn_serve: GET /status failed to obtain mutex");
}
ESP_LOGI(TAG,"Done Serving status.json");
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");
ESP_LOGE(TAG, "bad request from host: %s, request %s",remote_address, line);
}
}
}
else {
ESP_LOGE(TAG, "URL Not found. Sending 404.");
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);
}
//-1 if there is no next part
// 1 if moved to the next part but now there is no next part
// 0 if moved to the next part and there are still more parts
while(netbuf_next(inbuf) != -1) {
ESP_LOGD(TAG,"More data found from the connection!");
netbuf_data(inbuf, (void**)&buf, &buflen);
dump_net_buffer(buf, buflen);
}
free(ap_ip_address);
free(remote_address);
netconn_close(conn);
netbuf_delete(inbuf);
/* free the buffer */
@@ -591,26 +594,26 @@ void http_server_netconn_serve(struct netconn *conn) {
}
bool http_server_lock_json_object(TickType_t xTicksToWait) {
ESP_LOGD(TAG,"Locking config json object");
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!");
ESP_LOGV(TAG, "config Json object locked!");
return true;
}
else {
ESP_LOGW(TAG,"Semaphore take failed. Unable to lock config Json object mutex");
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");
ESP_LOGW(TAG, "Unable to lock config Json object mutex");
return false;
}
}
void http_server_unlock_json_object() {
ESP_LOGD(TAG,"Unlocking json buffer!");
ESP_LOGD(TAG, "Unlocking json buffer!");
xSemaphoreGive( http_server_config_mutex );
}

View File

@@ -266,6 +266,11 @@
</tbody>
</table>
<div class="buttons">
<div id="boot-div">
<form id="reboot-form" action="/reboot.json" method="post" target="dummyframe">
<button id="reboot-button" type="submit" class="btn btn-primary">Reboot</button>
</form>
</div>
<input id="save-nvs" type="button" class="btn btn-success" value="Save" />
</div>
</div>
@@ -298,7 +303,7 @@
</tbody>
</table>
<h2>Firmware URL:</h2>
<textarea id="fwurl" maxlength="120"></textarea>
<textarea id="fwurl" maxlength="350"></textarea>
<!--
<br />OR<br />
<div class="input-group mb-3" id="upload">
@@ -312,7 +317,7 @@
</div>
-->
<div class="buttons">
<input type="button" id="flash" class="btn btn-danger" value="Flash!" /><span id="flash-status"></span>
<input type="button" id="flash" class="btn btn-danger" value="Flash!" /><span id="flash-status"></span>
</div>
<div id="otadiv">
<div class="progress" id="progress">
@@ -337,8 +342,12 @@
<li>cJSON, &copy; 2009-2017, Dave Gamble and cJSON contributors. Licensed under the MIT License.</li>
</ul>
</div>
<h2>Show NVS Editor</h2>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="show-nvs" checked="checked">
<label class="custom-control-label" for="show-nvs"></label>
</div>
</div>
</div>
<footer class="footer"><span id="foot-fw"></span><span id="foot-wifi"></span></footer>
<iframe width="0" height="0" border="0" name="dummyframe" id="dummyframe"></iframe>

View File

@@ -1,144 +0,0 @@
/*
@file json.c
@brief handles very basic JSON with a minimal footprint on the system
This code is a lightly modified version of cJSON 1.4.7. cJSON is licensed under the MIT license:
Copyright (c) 2009 Dave Gamble
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.
@see https://github.com/DaveGamble/cJSON
*/
#include "json.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool json_print_string(const unsigned char *input, unsigned char *output_buffer)
{
const unsigned char *input_pointer = NULL;
unsigned char *output = NULL;
unsigned char *output_pointer = NULL;
size_t output_length = 0;
/* numbers of additional characters needed for escaping */
size_t escape_characters = 0;
if (output_buffer == NULL)
{
return false;
}
/* empty string */
if (input == NULL)
{
//output = ensure(output_buffer, sizeof("\"\""), hooks);
if (output == NULL)
{
return false;
}
strcpy((char*)output, "\"\"");
return true;
}
/* set "flag" to 1 if something needs to be escaped */
for (input_pointer = input; *input_pointer; input_pointer++)
{
if (strchr("\"\\\b\f\n\r\t", *input_pointer))
{
/* one character escape sequence */
escape_characters++;
}
else if (*input_pointer < 32)
{
/* UTF-16 escape sequence uXXXX */
escape_characters += 5;
}
}
output_length = (size_t)(input_pointer - input) + escape_characters;
/* in the original cJSON it is possible to realloc here in case output buffer is too small.
* This is overkill for an embedded system. */
output = output_buffer;
/* no characters have to be escaped */
if (escape_characters == 0)
{
output[0] = '\"';
memcpy(output + 1, input, output_length);
output[output_length + 1] = '\"';
output[output_length + 2] = '\0';
return true;
}
output[0] = '\"';
output_pointer = output + 1;
/* copy the string */
for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
{
if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
{
/* normal character, copy */
*output_pointer = *input_pointer;
}
else
{
/* character needs to be escaped */
*output_pointer++ = '\\';
switch (*input_pointer)
{
case '\\':
*output_pointer = '\\';
break;
case '\"':
*output_pointer = '\"';
break;
case '\b':
*output_pointer = 'b';
break;
case '\f':
*output_pointer = 'f';
break;
case '\n':
*output_pointer = 'n';
break;
case '\r':
*output_pointer = 'r';
break;
case '\t':
*output_pointer = 't';
break;
default:
/* escape and print as unicode codepoint */
sprintf((char*)output_pointer, "u%04x", *input_pointer);
output_pointer += 4;
break;
}
}
}
output[output_length + 1] = '\"';
output[output_length + 2] = '\0';
return true;
}

View File

@@ -1,47 +0,0 @@
/*
@file json.h
@brief handles very basic JSON with a minimal footprint on the system
This code is a lightly modified version of cJSON 1.4.7. cJSON is licensed under the MIT license:
Copyright (c) 2009 Dave Gamble
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.
@see https://github.com/DaveGamble/cJSON
*/
#ifndef JSON_H_INCLUDED
#define JSON_H_INCLUDED
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Render the cstring provided to a JSON escaped version that can be printed.
* @param input the input buffer to be escaped.
* @param output_buffer the output buffer to write to. You must ensure it is big enough to contain the final string.
* @see cJSON equivlaent static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
*/
bool json_print_string(const unsigned char *input, unsigned char *output_buffer);
#ifdef __cplusplus
}
#endif
#endif /* JSON_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@@ -48,13 +48,12 @@ extern "C" {
#if RECOVERY_APPLICATION==1
#elif RECOVERY_APPLICATION==0
#warning "compiling for squeezelite."
#pragma message "compiling for squeezelite."
#else
#error "unknown configuration"
#endif
#define DEFAULT_COMMAND_LINE CONFIG_DEFAULT_COMMAND_LINE
/**
* @brief Defines the maximum size of a SSID name. 32 is IEEE standard.
@@ -113,8 +112,6 @@ extern "C" {
*/
#define DEFAULT_AP_PASSWORD CONFIG_DEFAULT_AP_PASSWORD
/** @brief Defines the hostname broadcasted by mDNS */
#define DEFAULT_HOSTNAME "esp32"
/** @brief Defines access point's bandwidth.
* Value: WIFI_BW_HT20 for 20 MHz or WIFI_BW_HT40 for 40 MHz
@@ -203,10 +200,24 @@ typedef enum message_code_t {
EVENT_SCAN_DONE = 13,
EVENT_STA_GOT_IP = 14,
EVENT_REFRESH_OTA = 15,
MESSAGE_CODE_COUNT = 16 /* important for the callback array */
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 */
}message_code_t;
typedef enum reboot_type_t{
OTA,
RECOVERY,
RESTART,
} reboot_type_t;
void wifi_manager_reboot(reboot_type_t rtype);
void wifi_manager_reboot_ota(char * url);
/**
* @brief simplified reason codes for a lost connection.
*
@@ -229,21 +240,15 @@ typedef enum connection_request_made_by_code_t{
}connection_request_made_by_code_t;
/**
* The actual WiFi settings in use
* The wifi manager settings in use
*/
struct wifi_settings_t{
uint8_t ap_ssid[MAX_SSID_SIZE];
uint8_t ap_pwd[MAX_PASSWORD_SIZE];
uint8_t ap_channel;
uint8_t ap_ssid_hidden;
wifi_bandwidth_t ap_bandwidth;
bool sta_only;
wifi_ps_type_t sta_power_save;
bool sta_static_ip;
tcpip_adapter_ip_info_t sta_static_ip_config;
};
extern struct wifi_settings_t wifi_settings;
//struct wifi_settings_t{
// bool sta_only;
// bool sta_static_ip;
// wifi_ps_type_t sta_power_save;
// tcpip_adapter_ip_info_t sta_static_ip_config;
//};
//extern struct wifi_settings_t wifi_settings;
/**
* @brief Structure used to store one message in the queue.
@@ -276,9 +281,9 @@ void filter_unique( wifi_ap_record_t * aplist, uint16_t * ap_num);
void wifi_manager( void * pvParameters );
char* wifi_manager_get_ap_list_json();
char* wifi_manager_get_ip_info_json();
char* wifi_manager_alloc_get_ap_list_json();
char* wifi_manager_alloc_get_ip_info_json();
cJSON * wifi_manager_clear_ap_list_json(cJSON **old);
/**
* @brief saves the current STA wifi config to flash ram storage.
@@ -300,6 +305,13 @@ wifi_config_t* wifi_manager_get_wifi_sta_config();
esp_err_t wifi_manager_event_handler(void *ctx, system_event_t *event);
/**
* @brief Registers handler for wifi and ip events
*/
void wifi_manager_register_handlers();
/**
* @brief requests a connection to an access point that will be process in the main task thread.
*/
@@ -352,7 +364,7 @@ cJSON * wifi_manager_get_new_json(cJSON **old);
* @brief Generates the list of access points after a wifi scan.
* @note This is not thread-safe and should be called only if wifi_manager_lock_json_buffer call is successful.
*/
void wifi_manager_generate_acess_points_json();
void wifi_manager_generate_access_points_json(cJSON ** ap_list);
/**
* @brief Clear the list of access points.
@@ -378,7 +390,7 @@ char* wifi_manager_get_sta_ip_string();
/**
* @brief thread safe char representation of the STA IP update
*/
void wifi_manager_safe_update_sta_ip_string(uint32_t ip);
void wifi_manager_safe_update_sta_ip_string(struct ip4_addr * ip4);
/**