big merge

This commit is contained in:
Philippe G
2021-12-18 21:04:23 -08:00
parent 955692f8ad
commit 898998efb0
583 changed files with 84472 additions and 1965 deletions

View File

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

View File

@@ -1,98 +0,0 @@
// 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 <stdio.h>
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <http_parser.h>
#include <sdkconfig.h>
#include <esp_err.h>
#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_ */

View File

@@ -1,374 +0,0 @@
// 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 <string.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <errno.h>
#include <esp_log.h>
#include <esp_err.h>
#include <assert.h>
#include <esp_http_server.h>
#include <_esp_http_server.h>
#include "esp_httpd_priv.h"
#include "ctrl_sock.h"
#include "globdefs.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 = malloc_init_external(sizeof(struct httpd_data));
if (!hd) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance"));
return NULL;
}
hd->hd_calls = malloc_init_external(config->max_uri_handlers* sizeof(httpd_uri_t *));
if (!hd->hd_calls) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers"));
free(hd);
return NULL;
}
hd->hd_sd = malloc_init_external(config->max_open_sockets* sizeof(struct sock_db));
if (!hd->hd_sd) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data"));
free(hd->hd_calls);
free(hd);
return NULL;
}
struct httpd_req_aux *ra = &hd->hd_req_aux;
ra->resp_hdrs = malloc_init_external(config->max_resp_headers* sizeof(struct resp_hdr));
if (!ra->resp_hdrs) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers"));
free(hd->hd_sd);
free(hd->hd_calls);
free(hd);
return NULL;
}
hd->err_handler_fns = malloc_init_external(HTTPD_ERR_CODE_MAX* sizeof(httpd_err_handler_func_t));
if (!hd->err_handler_fns) {
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers"));
free(ra->resp_hdrs);
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;
}

View File

@@ -20,7 +20,6 @@ Copyright (c) 2017-2021 Sebastien L
#include "esp_vfs.h"
#include "messaging.h"
#include "platform_esp32.h"
#include "trace.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "platform_console.h"
@@ -28,7 +27,7 @@ Copyright (c) 2017-2021 Sebastien L
#include "webapp/webpack.h"
#include "network_wifi.h"
#include "network_status.h"
#include "globdefs.h"
#include "tools.h"
#define HTTP_STACK_SIZE (5*1024)
const char str_na[]="N/A";
@@ -481,7 +480,8 @@ esp_err_t console_cmd_post_handler(httpd_req_t *req){
}
else{
// navigate to the first child of the config structure
if(run_command(cJSON_GetStringValue(item))!=ESP_OK){
char *cmd = cJSON_GetStringValue(item);
if(!console_push(cmd, strlen(cmd) + 1)){
httpd_resp_send(req, (const char *)failed, strlen(failed));
}
else {

View File

@@ -1,6 +1,6 @@
#include "esp_eth.h"
#include "globdefs.h"
#include "network_ethernet.h"
static EXT_RAM_ATTR network_ethernet_driver_t W5500;
static EXT_RAM_ATTR spi_device_interface_config_t devcfg;
static EXT_RAM_ATTR esp_netif_config_t cfg_spi;

View File

@@ -3,15 +3,13 @@
#endif
#include "network_ethernet.h"
#include "freertos/timers.h"
#include "globdefs.h"
#include "messaging.h"
#include "network_status.h"
#include "platform_config.h"
#include "trace.h"
#include "tools.h"
#include "accessors.h"
#include "esp_log.h"
//#include "dnserver.h"
#include "globdefs.h"
static char TAG[] = "network_ethernet";
TimerHandle_t ETH_timer;
@@ -117,40 +115,9 @@ void init_network_ethernet() {
xEventGroupClearBits(ethernet_event_group, LINK_UP_BIT);
spi_device_handle_t spi_handle = NULL;
if (network_driver->spi) {
spi_host_device_t host = SPI3_HOST;
if (eth.host != -1) {
// don't use system's shared SPI
spi_bus_config_t buscfg = {
.miso_io_num = eth.miso,
.mosi_io_num = eth.mosi,
.sclk_io_num = eth.clk,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
// can't use SPI0
if (eth.host == 0)
{
ESP_LOGW(TAG,"Cannot use SPI1 host. Defaulting to SPI2");
host = SPI2_HOST;
}
else {
host = eth.host;
}
ESP_LOGI(TAG, "Initializing SPI bus on host %d (SPI%d) with mosi %d and miso %d", host,host+1, eth.mosi, eth.miso);
err = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI bus init failed : %s", esp_err_to_name(err));
}
} else {
// when we use shared SPI, we assume it has been initialized
host = spi_system_host;
}
if (err == ESP_OK) {
ESP_LOGI(TAG, "Adding ethernet SPI on host %d (SPI%d) with mosi %d and miso %d", host,host+1, eth.mosi, eth.miso);
err = spi_bus_add_device(host, network_driver->devcfg, &spi_handle);
if (err == ESP_OK) {
ESP_LOGI(TAG, "Adding ethernet SPI on host %d (SPI%d) with mosi %d and miso %d", eth.host, eth.host+1, eth.mosi, eth.miso);
err = spi_bus_add_device(eth.host, network_driver->devcfg, &spi_handle);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI host failed : %s", esp_err_to_name(err));

View File

@@ -39,11 +39,11 @@ Copyright (c) 2017-2021 Sebastien L
#include "messaging.h"
#include "platform_config.h"
#include "tools.h"
#include "trace.h"
#include "accessors.h"
#include "esp_err.h"
#include "globdefs.h"
#include "http_server_handlers.h"
#include "network_manager.h"

View File

@@ -39,7 +39,7 @@
#include "accessors.h"
#include "esp_err.h"
#include "globdefs.h"
#include "tools.h"
#include "http_server_handlers.h"
#include "network_manager.h"

View File

@@ -6,7 +6,6 @@
#include <string.h>
#include "bt_app_core.h"
#include "esp_log.h"
#include "globdefs.h"
#include "lwip/inet.h"
#include "monitor.h"
#include "network_ethernet.h"

View File

@@ -10,7 +10,6 @@
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "globdefs.h"
#include "lwip/sockets.h"
#include "messaging.h"
#include "network_status.h"

View File

@@ -25,7 +25,6 @@
#include "http_server_handlers.h"
#include "esp_log.h"
#include "esp_http_server.h"
#include "_esp_http_server.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@@ -34,14 +33,20 @@
#include "freertos/task.h"
#include "messaging.h"
#include "platform_esp32.h"
#include "globdefs.h"
#include "trace.h"
#include "tools.h"
static const char TAG[] = "http_server";
EXT_RAM_ATTR static httpd_handle_t _server = NULL;
EXT_RAM_ATTR static int _port;
EXT_RAM_ATTR rest_server_context_t *rest_context = NULL;
EXT_RAM_ATTR RingbufHandle_t messaging=NULL;
httpd_handle_t get_http_server(int *port) {
if (port) *port = _port;
return _server;
}
void register_common_handlers(httpd_handle_t server){
httpd_uri_t css_get = { .uri = "/css/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
httpd_register_uri_handler(server, &css_get);
@@ -143,14 +148,17 @@ esp_err_t http_server_start()
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 30;
config.max_open_sockets = 8;
config.max_open_sockets = 3;
config.lru_purge_enable = true;
config.backlog_conn = 1;
config.uri_match_fn = httpd_uri_match_wildcard;
config.task_priority = ESP_TASK_PRIO_MIN;
_port = config.server_port;
//todo: use the endpoint below to configure session token?
// config.open_fn
MEMTRACE_PRINT_DELTA_MESSAGE( "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");
}