Compare commits

..

21 Commits

Author SHA1 Message Date
Raoul Rubien
37cd2e2b48 fix esp_https_ota_begin(): implements handling of HttpStatus_PartialContent-code 206 2025-12-03 13:33:05 +01:00
c6d093b1a1 Implement i2c_master_multi_buffer_transmit_receive() 2025-12-01 12:45:07 +01:00
688c818c2f Avoid cmake error when variable is not defined 2025-11-27 11:11:21 +01:00
c9281dc1e3 fix(cmake): Allow disabling component validation
Allow disabling component validation by setting
ESP_IDF_DISABLE_COMPONENT_VALIDATION=1 in the environment.
2025-11-27 11:11:21 +01:00
a4f4040ef0 fix(esp_phy): Make config argument const for esp_phy_set_ant_gpio() 2025-11-27 11:11:21 +01:00
fdb3a300b3 Allow the https server to request client certs only with OPTIONAL 2025-11-27 11:11:21 +01:00
d0cba05798 Update esp-mqtt submodule to my fork with async stop api 2025-11-27 11:11:21 +01:00
f34b2966d9 Show stacktrace of task which failed timeout in task watchdog 2025-11-27 11:11:21 +01:00
11769a9eb7 Add uart_read_some_bytes() to allow reading into a buffer without waiting until that buffer is full 2025-11-27 11:11:21 +01:00
c9dcfbace5 Add filename and line number back to esp log 2025-11-27 11:11:21 +01:00
Peter Pötzi
2d0af32c8f add function to start spi transaction from isr 2025-11-27 11:11:21 +01:00
1c715e372a set_server_config() set ssl authmode to OPTIONAL 2025-11-27 11:11:21 +01:00
b76c9b20de Show websocket network errors 2025-11-27 11:11:21 +01:00
Tobias Schramm
888952efaa bootloader_support: burn security efuses if flash encryption is enabled
Previously security eFuses were only burnt if the flash was not encrypted
yet.
To enhance robustness of the security eFuse settings their correct setup
should be verified on each bootup. Else it would be possible for an
already encrypted ESP to be reflashed with firmware containing updated,
more restrictive eFuse settings without them ever being applied.
Additionally this change enables easy, secure use of ESPs with host sidee
flash preencryption. Flash preencryption by the host computer performing
the programming procedure can speed up the programming process by a great
deal since the flash no longer needs to be read, erased and written again
by the bootloader self-encryption routines. Additionally it avoids
bricking of ESPs through interruption of the self-ecnryption procedure.
Without this change the host would have to set up all fuses in the ESP
correctly by itself, duplicating the fuse configuration code already
present in the bootloader and creating additional maintenance burden for
the host software if anything about the fuse setup logic changes.
This commit changes the security eFuse configuration logic to always burn
any configured security eFuses on bootup, regardless of current flash
encryption status.
2025-11-27 11:11:21 +01:00
86e4391bde Show remote ip address when somebody requests and invalid path to ease debugging 2025-11-27 11:11:21 +01:00
6846f9846c Return ESP_ERR_HTTP_EAGAIN in http client perform 2025-11-27 11:11:21 +01:00
55092b1409 Less tcp packet fragmentation 2025-11-27 11:11:21 +01:00
0e63b97662 Add missing header include to netif ppp 2025-11-27 11:11:20 +01:00
cc60dc1410 Return EAGAIN in http client perform 2025-11-27 11:11:20 +01:00
74cf5f130a Add support for X-WWW-Authenticate header 2025-11-27 11:11:20 +01:00
c740d3179b Fix compilation under C++ again 2025-11-27 11:11:20 +01:00
32 changed files with 430 additions and 19 deletions

3
.gitmodules vendored
View File

@@ -56,7 +56,8 @@
[submodule "components/mqtt/esp-mqtt"]
path = components/mqtt/esp-mqtt
url = ../../espressif/esp-mqtt.git
# url = ../../espressif/esp-mqtt.git
url = ../../0xFEEDC0DE64/esp-mqtt.git
[submodule "components/protobuf-c/protobuf-c"]
path = components/protobuf-c/protobuf-c

View File

@@ -333,7 +333,10 @@ endforeach()
# Only run validation for the main project, not subprojects like bootloader
idf_build_get_property(bootloader_build BOOTLOADER_BUILD)
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
if(NOT bootloader_build AND NOT esp_tee_build)
if((NOT DEFINED ENV{ESP_IDF_DISABLE_COMPONENT_VALIDATION}
OR "$ENV{ESP_IDF_DISABLE_COMPONENT_VALIDATION}" STREQUAL ""
OR "$ENV{ESP_IDF_DISABLE_COMPONENT_VALIDATION}" STREQUAL "0")
AND NOT bootloader_build AND NOT esp_tee_build)
include("${CMAKE_CURRENT_LIST_DIR}/tools/cmake/component_validation.cmake")
__component_validation_run_checks()
endif()

View File

@@ -717,7 +717,25 @@ static void load_image(const esp_image_metadata_t *image_data)
*/
ESP_LOGI(TAG, "Checking flash encryption...");
bool flash_encryption_enabled = esp_flash_encrypt_state();
if (!flash_encryption_enabled) {
if (flash_encryption_enabled) {
#if BOOTLOADER_BUILD
/* Ensure security eFuses are burnt */
esp_efuse_batch_write_begin();
esp_err_t err = esp_flash_encryption_enable_secure_features();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error setting security eFuses (err=0x%x).", err);
esp_efuse_batch_write_cancel();
return;
}
err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
return;
}
ESP_LOGI(TAG, "Security eFuses are burnt");
#endif // BOOTLOADER_BUILD
} else {
#ifdef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED is set, refusing to boot.");
return;

View File

@@ -129,7 +129,7 @@ static ssize_t tcp_read(esp_tls_t *tls, char *data, size_t datalen)
static ssize_t tcp_write(esp_tls_t *tls, const char *data, size_t datalen)
{
return send(tls->sockfd, data, datalen, 0);
return send(tls->sockfd, data, datalen, MSG_MORE);
}
ssize_t esp_tls_conn_read(esp_tls_t *tls, void *data, size_t datalen)

View File

@@ -297,6 +297,9 @@ typedef struct esp_tls_cfg_server {
unsigned int cacert_pem_bytes; /*!< Size of client CA certificate legacy name */
};
bool cacert_authmode_optional; /*!< Enable this option to set the authmode
to OPTIONAL (only useful when cacert is set) */
union {
const unsigned char *servercert_buf; /*!< Server certificate in a buffer
This buffer should be NULL terminated */

View File

@@ -757,6 +757,8 @@ static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
if (esp_ret != ESP_OK) {
return esp_ret;
}
if (cfg->cacert_authmode_optional)
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
} else {
#ifdef CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);

View File

@@ -1314,6 +1314,51 @@ esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uin
return ret;
}
esp_err_t i2c_master_multi_buffer_transmit_receive(i2c_master_dev_handle_t i2c_dev, i2c_master_transmit_multi_buffer_info_t *buffer_info_array, size_t array_size, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms)
{
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");
ESP_RETURN_ON_FALSE(array_size <= (SOC_I2C_CMD_REG_NUM - 2 - 3), ESP_ERR_INVALID_ARG, TAG, "i2c command list cannot contain so many commands");
ESP_RETURN_ON_FALSE(buffer_info_array != NULL, ESP_ERR_INVALID_ARG, TAG, "buffer info array is empty");
esp_err_t ret = ESP_OK;
size_t op_index = 0;
i2c_operation_t i2c_ops[SOC_I2C_CMD_REG_NUM] = {};
i2c_ops[op_index++].hw_cmd.op_code = I2C_LL_CMD_RESTART;
int i;
for (i = 0; i < array_size; i++) {
if (buffer_info_array[i].buffer_size == 0) {
continue;
}
i2c_ops[op_index].hw_cmd.ack_en = i2c_dev->ack_check_disable ? false : true;
i2c_ops[op_index].hw_cmd.op_code = I2C_LL_CMD_WRITE;
i2c_ops[op_index].data = (uint8_t*)buffer_info_array[i].write_buffer;
i2c_ops[op_index].total_bytes = buffer_info_array[i].buffer_size;
i2c_ops[op_index].bytes_used = 0;
op_index++;
}
i2c_ops[op_index++].hw_cmd.op_code = I2C_LL_CMD_RESTART;
i2c_ops[op_index].hw_cmd.op_code = I2C_LL_CMD_READ;
i2c_ops[op_index].hw_cmd.ack_val = I2C_ACK_VAL;
i2c_ops[op_index].data = read_buffer;
i2c_ops[op_index++].total_bytes = read_size - 1;
i2c_ops[op_index].hw_cmd.op_code = I2C_LL_CMD_READ;
i2c_ops[op_index].hw_cmd.ack_val = I2C_NACK_VAL;
i2c_ops[op_index].data = (read_buffer + read_size - 1);
i2c_ops[op_index++].total_bytes = 1;
i2c_ops[op_index++].hw_cmd.op_code = I2C_LL_CMD_STOP;
if (i2c_dev->master_bus->async_trans == false) {
ret = s_i2c_synchronous_transaction(i2c_dev, i2c_ops, op_index, xfer_timeout_ms);
} else {
ret = s_i2c_asynchronous_transaction(i2c_dev, i2c_ops, op_index, xfer_timeout_ms);
}
return ret;
}
esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms)
{
ESP_RETURN_ON_FALSE(i2c_dev != NULL, ESP_ERR_INVALID_ARG, TAG, "i2c handle not initialized");

View File

@@ -214,6 +214,29 @@ esp_err_t i2c_master_multi_buffer_transmit(i2c_master_dev_handle_t i2c_dev, i2c_
*/
esp_err_t i2c_master_transmit_receive(i2c_master_dev_handle_t i2c_dev, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms);
/**
* @brief Perform a multi-write-read transaction on the I2C bus.
* This function transmits multiple buffers of data and then reads.
* The transaction will be undergoing until it finishes or it reaches
* the timeout provided.
*
* @note If a callback was registered with `i2c_master_register_event_callbacks`, the transaction will be asynchronous, and thus, this function will return directly, without blocking.
* You will get finish information from callback. Besides, data buffer should always be completely prepared when callback is registered, otherwise, the data will get corrupt.
*
* @param[in] i2c_dev I2C master device handle that created by `i2c_master_bus_add_device`.
* @param[in] buffer_info_array Pointer to buffer information array.
* @param[in] array_size size of buffer information array.
* @param[out] read_buffer Data bytes received from i2c bus.
* @param[in] read_size Size, in bytes, of the read buffer.
* @param[in] xfer_timeout_ms Wait timeout, in ms. Note: -1 means wait forever.
* @return
* - ESP_OK: I2C master transmit-receive success.
* - ESP_ERR_INVALID_RESPONSE: I2C master transmit-receive receives NACK.
* - ESP_ERR_INVALID_ARG: I2C master transmit parameter invalid.
* - ESP_ERR_TIMEOUT: Operation timeout(larger than xfer_timeout_ms) because the bus is busy or hardware crash.
*/
esp_err_t i2c_master_multi_buffer_transmit_receive(i2c_master_dev_handle_t i2c_dev, i2c_master_transmit_multi_buffer_info_t *buffer_info_array, size_t array_size, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms);
/**
* @brief Perform a read transaction on the I2C bus.
* The transaction will be undergoing until it finishes or it reaches

View File

@@ -407,6 +407,9 @@ int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns);
*/
esp_err_t spi_bus_get_max_transaction_len(spi_host_device_t host_id, size_t *max_bytes);
intr_handle_t spi_bus_get_intr(spi_host_device_t host);
void spi_dma_reset_start(spi_device_handle_t handle);
#ifdef __cplusplus
}
#endif

View File

@@ -726,6 +726,22 @@ static void SPI_MASTER_ISR_ATTR spi_bus_intr_disable(void *host)
#define spi_dma_start(chan, addr) gdma_start(chan, (intptr_t)(addr))
#endif
void SPI_MASTER_ISR_ATTR spi_dma_reset_start(spi_device_handle_t handle){
spi_host_t *host = handle->host;
spi_hal_context_t *hal = &(host->hal);
const spi_dma_ctx_t *dma_ctx = host->dma_ctx;
spi_dma_reset(dma_ctx->rx_dma_chan);
spi_hal_hw_prepare_rx(hal->hw);
spi_dma_start(dma_ctx->rx_dma_chan, dma_ctx->dmadesc_rx);
spi_dma_reset(dma_ctx->tx_dma_chan);
spi_hal_hw_prepare_tx(hal->hw);
spi_dma_start(dma_ctx->tx_dma_chan, dma_ctx->dmadesc_tx);
}
static void SPI_MASTER_ISR_ATTR s_spi_dma_prepare_data(spi_host_t *host, spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
{
const spi_dma_ctx_t *dma_ctx = host->dma_ctx;
@@ -1518,6 +1534,10 @@ esp_err_t spi_bus_get_max_transaction_len(spi_host_device_t host_id, size_t *max
return ESP_OK;
}
intr_handle_t spi_bus_get_intr(spi_host_device_t host) {
return bus_driver_ctx[host]->intr;
}
#if SOC_SPI_SCT_SUPPORTED
/*-----------------------------------------------------------

View File

@@ -576,6 +576,7 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const void* src, size_t si
/**
* @brief UART read bytes from UART buffer
* Blocks until the buffer to fill is filled completely or timeout is expired
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param buf pointer to the buffer.
@@ -588,6 +589,21 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const void* src, size_t si
*/
int uart_read_bytes(uart_port_t uart_num, void* buf, uint32_t length, TickType_t ticks_to_wait);
/**
* @brief UART read bytes from UART buffer
* Blocks until there is at least something to read (might be smaller than length!) or timeout is expired
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param buf pointer to the buffer.
* @param length data length
* @param ticks_to_wait sTimeout, count in RTOS ticks
*
* @return
* - (-1) Error
* - OTHERS (>=0) The number of bytes read from UART buffer
*/
int uart_read_some_bytes(uart_port_t uart_num, void* buf, uint32_t length, TickType_t ticks_to_wait);
/**
* @brief Alias of uart_flush_input.
* UART ring buffer flush. This will discard all data in the UART RX buffer.

View File

@@ -1731,6 +1731,34 @@ int uart_read_bytes(uart_port_t uart_num, void *buf, uint32_t length, TickType_t
return copy_len;
}
int uart_read_some_bytes(uart_port_t uart_num, void *buf, uint32_t length, TickType_t ticks_to_wait)
{
ESP_RETURN_ON_FALSE((uart_num < UART_NUM_MAX), (-1), UART_TAG, "uart_num error");
ESP_RETURN_ON_FALSE((buf), (-1), UART_TAG, "uart data null");
ESP_RETURN_ON_FALSE((p_uart_obj[uart_num]), (-1), UART_TAG, "uart driver error");
uint8_t *data = NULL;
size_t size = 0;
if (xSemaphoreTake(p_uart_obj[uart_num]->rx_mux, (TickType_t)ticks_to_wait) != pdTRUE) {
return -1;
}
data = (uint8_t *) xRingbufferReceiveUpTo(p_uart_obj[uart_num]->rx_ring_buf, &size, (TickType_t) ticks_to_wait, length);
if (!data) {
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
return 0;
}
memcpy((uint8_t *)buf, data, size);
UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock));
p_uart_obj[uart_num]->rx_buffered_len -= size;
uart_pattern_queue_update(uart_num, size);
UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock));
vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, data);
uart_check_buf_full(uart_num);
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
return size;
}
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t *size)
{
ESP_RETURN_ON_FALSE((uart_num < UART_NUM_MAX), ESP_FAIL, UART_TAG, "uart_num error");

View File

@@ -302,7 +302,8 @@ static int http_on_header_value(http_parser *parser, const char *at, size_t leng
} else if (strcasecmp(client->current_header_key, "Transfer-Encoding") == 0
&& memcmp(at, "chunked", length) == 0) {
client->response->is_chunked = true;
} else if (strcasecmp(client->current_header_key, "WWW-Authenticate") == 0) {
} else if (strcasecmp(client->current_header_key, "WWW-Authenticate") == 0 ||
strcasecmp(client->current_header_key, "X-WWW-Authenticate") == 0) {
HTTP_RET_ON_FALSE_DBG(http_utils_append_string(&client->auth_header, at, length), -1, TAG, "Failed to append string");
}
HTTP_RET_ON_FALSE_DBG(http_utils_append_string(&client->current_header_value, at, length), -1, TAG, "Failed to append string");
@@ -1421,7 +1422,7 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len)
esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
{
esp_err_t err = ESP_FAIL;
do {
//do {
if (client->process_again) {
esp_http_client_prepare(client);
}
@@ -1561,7 +1562,9 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
default:
break;
}
} while (client->process_again && err == ESP_OK);
//} while (client->process_again && err == ESP_OK);
if (client->process_again && err == ESP_OK)
return ESP_ERR_HTTP_EAGAIN;
return err;
}

View File

@@ -57,7 +57,7 @@ int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len)
}
struct httpd_req_aux *ra = r->aux;
int ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
int ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, MSG_MORE);
if (ret < 0) {
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
return ret;
@@ -71,7 +71,7 @@ static esp_err_t httpd_send_all(httpd_req_t *r, const char *buf, size_t buf_len)
int ret;
while (buf_len > 0) {
ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, MSG_MORE);
if (ret < 0) {
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
return ESP_FAIL;

View File

@@ -303,10 +303,31 @@ esp_err_t httpd_uri(struct httpd_data *hd)
/* If URI with method not found, respond with error code */
if (uri == NULL) {
switch (err) {
case HTTPD_404_NOT_FOUND:
ESP_LOGW(TAG, LOG_FMT("URI '%s' not found"), req->uri);
{
char ipstr[INET6_ADDRSTRLEN] = "UNKNOWN";
const int sockfd = httpd_req_to_sockfd(req);
if (sockfd < 0)
ESP_LOGW(TAG, "httpd_req_to_sockfd() failed with %i", sockfd);
else
{
struct sockaddr_in6 addr; // esp_http_server uses IPv6 addressing
socklen_t addr_size = sizeof(addr);
const int result = getpeername(sockfd, (struct sockaddr *)&addr, &addr_size);
if (result < 0)
ESP_LOGW(TAG, "getpeername() failed with %i", result);
else
inet_ntop(AF_INET, &addr.sin6_addr.un.u32_addr[3], ipstr, sizeof(ipstr));
}
ESP_LOGW(TAG, LOG_FMT("URI '%s' not found for %s"), req->uri, ipstr);
return httpd_req_handle_err(req, HTTPD_404_NOT_FOUND);
}
case HTTPD_405_METHOD_NOT_ALLOWED:
ESP_LOGW(TAG, LOG_FMT("Method '%d' not allowed for URI '%s'"),
req->method, req->uri);

View File

@@ -445,14 +445,14 @@ esp_err_t httpd_ws_send_frame_async(httpd_handle_t hd, int fd, httpd_ws_frame_t
}
/* Send off header */
if (sess->send_fn(hd, fd, (const char *)header_buf, tx_len, 0) < 0) {
if (sess->send_fn(hd, fd, (const char *)header_buf, tx_len, MSG_MORE) < 0) {
ESP_LOGW(TAG, LOG_FMT("Failed to send WS header"));
return ESP_FAIL;
}
/* Send off payload */
if(frame->len > 0 && frame->payload != NULL) {
if (sess->send_fn(hd, fd, (const char *)frame->payload, frame->len, 0) < 0) {
if (sess->send_fn(hd, fd, (const char *)frame->payload, frame->len, MSG_MORE) < 0) {
ESP_LOGW(TAG, LOG_FMT("Failed to send WS payload"));
return ESP_FAIL;
}

View File

@@ -135,6 +135,13 @@ static esp_err_t _http_handle_response_code(esp_https_ota_t *https_ota_handle, i
} else if (status_code >= HttpStatus_InternalError) {
ESP_LOGE(TAG, "Server error (%d)", status_code);
return ESP_FAIL;
} else if (https_ota_handle->binary_file_len > 0
#if CONFIG_ESP_HTTPS_OTA_ENABLE_PARTIAL_DOWNLOAD
&& !https_ota_handle->partial_http_download
#endif
&& status_code != HttpStatus_PartialContent) {
ESP_LOGE(TAG, "Requested range header ignored by server");
return ESP_ERR_HTTP_RANGE_NOT_SATISFIABLE;
}
char upgrade_data_buf[256];

View File

@@ -91,6 +91,9 @@ struct httpd_ssl_config {
/** CA certificate byte length */
size_t cacert_len;
/** CA certificate verification optional */
bool cacert_authmode_optional;
/** Private key */
const uint8_t *prvtkey_pem;

View File

@@ -278,6 +278,7 @@ static esp_err_t create_secure_context(const struct httpd_ssl_config *config, ht
cfg->userdata = config->ssl_userdata;
cfg->alpn_protos = config->alpn_protos;
cfg->tls_handshake_timeout_ms = config->tls_handshake_timeout_ms;
cfg->cacert_authmode_optional = config->cacert_authmode_optional;
cfg->tls_version = config->tls_version;
cfg->ciphersuites_list = config->ciphersuites_list;

View File

@@ -8,6 +8,8 @@
#ifndef _ESP_NETIF_PPP_H_
#define _ESP_NETIF_PPP_H_
#include "esp_netif_types.h"
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -72,7 +72,7 @@ typedef struct {
* - ESP_OK : success
* - other : failed
*/
esp_err_t esp_phy_set_ant_gpio(esp_phy_ant_gpio_config_t *config);
esp_err_t esp_phy_set_ant_gpio(const esp_phy_ant_gpio_config_t *config);
/**
* @brief Get current antenna GPIO configuration

View File

@@ -177,7 +177,7 @@ static void phy_ant_set_gpio_output(uint32_t io_num)
gpio_config(&io_conf);
}
esp_err_t esp_phy_set_ant_gpio(esp_phy_ant_gpio_config_t *config)
esp_err_t esp_phy_set_ant_gpio(const esp_phy_ant_gpio_config_t *config)
{
if (config == NULL) {
ESP_LOGE(TAG, "Invalid configuration");

View File

@@ -18,6 +18,9 @@ extern "C" {
#include "esp_err.h"
#include "esp_cpu.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
/*
* @brief Structure used for backtracing
*
@@ -129,6 +132,8 @@ esp_err_t esp_backtrace_print(int depth);
*/
esp_err_t esp_backtrace_print_all_tasks(int depth);
esp_err_t esp_backtrace_print_task(TaskHandle_t pxTask, int depth, bool panic);
/**
* @brief Set a watchpoint to break/panic when a certain memory range is accessed.
* Superseded by esp_cpu_set_watchpoint in esp_cpu.h.

View File

@@ -250,3 +250,70 @@ ipc_err:
malloc_err:
return ret;
}
esp_err_t esp_backtrace_print_task(TaskHandle_t pxTask, int depth, bool panic)
{
esp_err_t ret = ESP_OK;
TaskSnapshot_t task_snapshot;
cur_task_backtrace_ctrl_t ctrl = {0};
// Suspend the scheduler to prevent task switching
vTaskSuspend(pxTask);
/*
Initialize backtracing for this core:
- Flush current core's register windows back onto current task's stack using esp_backtrace_get_start()
- Get starting frame for backtracing (starting frame is the caller of this function) using esp_backtrace_get_start()
- Save the starting frame details into the control block
*/
BaseType_t core_id = xPortGetCoreID(); // Get core ID now that task switching is disabled
ctrl.cur_tasks[core_id].task_hdl = xTaskGetCurrentTaskHandle();
esp_backtrace_get_start(&ctrl.cur_tasks[core_id].starting_pc,
&ctrl.cur_tasks[core_id].starting_sp,
&ctrl.cur_tasks[core_id].next_pc);
vTaskGetSnapshot(pxTask, &task_snapshot);
// Print the backtrace of the task
bool cur_running = false;
TaskHandle_t task_hdl = (TaskHandle_t) task_snapshot.pxTCB;
esp_backtrace_frame_t stk_frame = {0};
// Check if the task is one of the currently running tasks
for (BaseType_t core_id = 0; core_id < configNUMBER_OF_CORES; core_id++) {
if (task_hdl == ctrl.cur_tasks[core_id].task_hdl) {
cur_running = true;
break;
}
}
// Initialize the starting backtrace frame of the task
if (cur_running) {
/*
Setting the starting backtrace frame for currently running tasks is different. We cannot
use the current frame of each running task as the starting frame (due to the possibility
of the SP changing). Thus, each currently running task will have initialized their callers
as the starting frame for backtracing, which is saved inside the
cur_task_backtrace_ctrl_t block.
*/
stk_frame.pc = ctrl.cur_tasks[core_id].starting_pc;
stk_frame.sp = ctrl.cur_tasks[core_id].starting_sp;
stk_frame.next_pc = ctrl.cur_tasks[core_id].next_pc;
} else {
// Set the starting backtrace frame using the task's saved stack pointer
XtExcFrame* exc_frame = (XtExcFrame*) task_snapshot.pxTopOfStack;
stk_frame.pc = exc_frame->pc;
stk_frame.sp = exc_frame->a1;
stk_frame.next_pc = exc_frame->a0;
}
// Print backtrace
esp_err_t bt_ret = esp_backtrace_print_from_frame(depth, &stk_frame, panic);
if (bt_ret != ESP_OK) {
ret = bt_ret;
}
// Resume the scheduler to allow task switching again
vTaskResume(pxTask);
return ret;
}

View File

@@ -819,7 +819,10 @@ esp_err_t esp_task_wdt_print_triggered_tasks(task_wdt_msg_handler msg_handler, v
msg_handler(opaque, name);
msg_handler(opaque, cpu);
}
esp_backtrace_print_task(entry->task_handle, 100, true);
}
}
return ESP_OK;
}

View File

@@ -19,7 +19,7 @@ extern "C" {
#include "core_dump_checksum.h"
#if CONFIG_ESP_COREDUMP_LOGS
#define ESP_COREDUMP_LOG( level, format, ... ) if (LOG_LOCAL_LEVEL >= level) { esp_rom_printf((format), esp_log_early_timestamp(), (const char *)TAG, ##__VA_ARGS__); }
#define ESP_COREDUMP_LOG( level, format, ... ) if (LOG_LOCAL_LEVEL >= level) { esp_rom_printf(format, esp_log_early_timestamp(), (const char *)TAG, ##__VA_ARGS__); }
#else
#define ESP_COREDUMP_LOG( level, format, ... ) // dummy define doing nothing
#endif

View File

@@ -11,8 +11,12 @@ extern "C" {
#endif
/** @cond */
#define ESP_LOG_STRINGIFY2(x) #x
#define ESP_LOG_STRINGIFY(x) ESP_LOG_STRINGIFY2(x)
// For backward compatibility (these macros are not used in the log v2).
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%" PRIu32 ") %s: " format LOG_RESET_COLOR "\n"
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " %s:" ESP_LOG_STRINGIFY(__LINE__) " (%" PRIu32 ") %s: " format LOG_RESET_COLOR "\n", (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)
#define _ESP_LOG_DRAM_LOG_FORMAT(letter, format) DRAM_STR(#letter " %s: " format "\n")
#define LOG_SYSTEM_TIME_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%s) %s: " format LOG_RESET_COLOR "\n"
/** @endcond */

View File

@@ -11,7 +11,7 @@ extern "C" {
#include <stdint.h>
typedef struct emac_ext_dev_s {
typedef volatile struct emac_ext_dev_s {
volatile union {
struct {
uint32_t div_num : 4;

View File

@@ -17,6 +17,11 @@ extern "C" {
// Features supported
#define ESP_TRANSPORT_WS_STORE_RESPONSE_HEADERS 1
// this define will also be used for optimized websocket sends with the
// optimized version to prepend the required space for the websocket
// header
#define MAX_WEBSOCKET_HEADER_SIZE 16
typedef enum ws_transport_opcodes {
WS_TRANSPORT_OPCODES_CONT = 0x00,
WS_TRANSPORT_OPCODES_TEXT = 0x01,
@@ -174,6 +179,37 @@ esp_err_t esp_transport_ws_set_config(esp_transport_handle_t t, const esp_transp
*/
int esp_transport_ws_send_raw(esp_transport_handle_t t, ws_transport_opcodes_t opcode, const char *b, int len, int timeout_ms);
/**
* @brief Sends websocket raw message with custom opcode and payload in a optimized way
*
* This method is similar to esp_transport_ws_send_raw(), but
* it assumes, that the first MAX_WEBSOCKET_HEADER_SIZE bytes
* of the buffer should not be sent and should rather be used
* for the required websocket header itself. This is done to
* have a single TCP packet for header and payload and to avoid
* copying and allocating additional resources. The first
* MAX_WEBSOCKET_HEADER_SIZE bytes should not be initialized in
* any specific way, and the return value (length) will also
* include the MAX_WEBSOCKET_HEADER_SIZE byte extra buffer.
*
* Note that generic esp_transport_write for ws handle sends
* binary massages by default if size is > 0 and
* ping message if message size is set to 0.
* This API is provided to support explicit messages with arbitrary opcode,
* should it be PING, PONG or TEXT message with arbitrary data.
*
* @param[in] t Websocket transport handle
* @param[in] opcode ws operation code
* @param[in] buffer The buffer
* @param[in] len The length
* @param[in] timeout_ms The timeout milliseconds (-1 indicates block forever)
*
* @return
* - Number of bytes was written
* - (-1) if there are any errors, should check errno
*/
int esp_transport_ws_send_raw_optimized(esp_transport_handle_t t, ws_transport_opcodes_t opcode, const char *b, int len, int timeout_ms);
/**
* @brief Returns websocket fin flag for last received data
*

View File

@@ -249,7 +249,7 @@ static int tcp_write(esp_transport_handle_t t, const char *buffer, int len, int
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->sockfd, timeout_ms);
return poll;
}
int ret = send(ssl->sockfd, (const unsigned char *) buffer, len, 0);
int ret = send(ssl->sockfd, (const unsigned char *) buffer, len, MSG_MORE);
if (ret < 0) {
ESP_LOGE(TAG, "tcp_write error, errno=%s", strerror(errno));
esp_transport_capture_errno(t, errno);

View File

@@ -469,6 +469,92 @@ static int _ws_write(esp_transport_handle_t t, int opcode, int mask_flag, const
return ret;
}
// This method is similar to _ws_write() but it assumes, that the first 16 bytes of the buffer should not be sent and
// should rather be used for the required websocket header itself. This is done to have a single TCP packet for header
// and payload and to avoid copying and allocating additional resources. The first 16 bytes should not be initialized
// in any specific way, and the return value (length) will also include the 16 byte extra buffer.
static int _ws_write_optimized(esp_transport_handle_t t, int opcode, int mask_flag, const char *b, int len, int timeout_ms)
{
assert(len >= MAX_WEBSOCKET_HEADER_SIZE);
transport_ws_t *ws = esp_transport_get_context_data(t);
char *buffer = (char *)b;
char *ws_header;
// char *mask;
int header_len = 0; //, i;
int poll_write;
if ((poll_write = esp_transport_poll_write(ws->parent, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error transport_poll_write %i", poll_write);
return poll_write;
}
int len2 = len - MAX_WEBSOCKET_HEADER_SIZE;
if (len2 <= 125) {
ws_header = buffer+MAX_WEBSOCKET_HEADER_SIZE-2-4;
ws_header[header_len++] = opcode;
ws_header[header_len++] = (uint8_t)(len2 | mask_flag);
} else if (len2 < 65536) {
ws_header = buffer+MAX_WEBSOCKET_HEADER_SIZE-4-4;
ws_header[header_len++] = opcode;
ws_header[header_len++] = WS_SIZE16 | mask_flag;
ws_header[header_len++] = (uint8_t)(len2 >> 8);
ws_header[header_len++] = (uint8_t)(len2 & 0xFF);
} else {
ws_header = buffer+MAX_WEBSOCKET_HEADER_SIZE-10-4;
ws_header[header_len++] = opcode;
ws_header[header_len++] = WS_SIZE64 | mask_flag;
/* Support maximum 4 bytes length */
ws_header[header_len++] = 0; //(uint8_t)((len >> 56) & 0xFF);
ws_header[header_len++] = 0; //(uint8_t)((len >> 48) & 0xFF);
ws_header[header_len++] = 0; //(uint8_t)((len >> 40) & 0xFF);
ws_header[header_len++] = 0; //(uint8_t)((len >> 32) & 0xFF);
ws_header[header_len++] = (uint8_t)((len2 >> 24) & 0xFF);
ws_header[header_len++] = (uint8_t)((len2 >> 16) & 0xFF);
ws_header[header_len++] = (uint8_t)((len2 >> 8) & 0xFF);
ws_header[header_len++] = (uint8_t)((len2 >> 0) & 0xFF);
}
if (mask_flag) {
ws_header[header_len++] = 0;
ws_header[header_len++] = 0;
ws_header[header_len++] = 0;
ws_header[header_len++] = 0;
// mask = &ws_header[header_len];
// mask = 0;
// ssize_t rc;
// if ((rc = getrandom(ws_header + header_len, 4, 0)) < 0) {
// ESP_LOGD(TAG, "getrandom() returned %zd", rc);
// return -1;
// }
// header_len += 4;
// for (i = MAX_WEBSOCKET_HEADER_SIZE; i < len; ++i) {
// buffer[i] = (buffer[i] ^ mask[i % 4]);
// }
}
// if (esp_transport_write(ws->parent, ws_header, len - MAX_WEBSOCKET_HEADER_SIZE + header_len, timeout_ms) != header_len) {
// ESP_LOGE(TAG, "Error write header");
// return -1;
// }
// if (len == 0) {
// return 0;
// }
int ret = esp_transport_write(ws->parent, ws_header, len - MAX_WEBSOCKET_HEADER_SIZE + header_len, timeout_ms);
// ESP_LOGI(TAG, "len=%d header_len=%d total_size=%d sent=%d", len, header_len, len - MAX_WEBSOCKET_HEADER_SIZE + header_len, ret);
// in case of masked transport we have to revert back to the original data, as ws layer
// does not create its own copy of data to be sent
if (mask_flag) {
// mask = &ws_header[header_len - 4];
// for (i = 0; i < len; ++i) {
// buffer[i] = (buffer[i] ^ mask[i % 4]);
// }
}
return ret + (ws_header - buffer);
}
int esp_transport_ws_send_raw(esp_transport_handle_t t, ws_transport_opcodes_t opcode, const char *b, int len, int timeout_ms)
{
uint8_t op_code = ws_get_bin_opcode(opcode);
@@ -480,6 +566,17 @@ int esp_transport_ws_send_raw(esp_transport_handle_t t, ws_transport_opcodes_t o
return _ws_write(t, op_code, WS_MASK, b, len, timeout_ms);
}
int esp_transport_ws_send_raw_optimized(esp_transport_handle_t t, ws_transport_opcodes_t opcode, const char *b, int len, int timeout_ms)
{
uint8_t op_code = ws_get_bin_opcode(opcode);
if (t == NULL) {
ESP_LOGE(TAG, "Transport must be a valid ws handle");
return ESP_ERR_INVALID_ARG;
}
ESP_LOGD(TAG, "Sending raw ws message with opcode %d", op_code);
return _ws_write_optimized(t, op_code, WS_MASK, b, len, timeout_ms);
}
static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeout_ms)
{
if (len == 0) {