0
0
Fork 0

Compare commits

...

10 Commits

Author SHA1 Message Date
kerms 9b031581d6 change uart and jtag gpio pin 2024-06-22 16:39:34 +08:00
kerms 5bac7ae67b change system api ID to 0 2024-06-22 14:57:34 +08:00
windowsair fb32c9bdff fix(dap): Fix DAP_SPI_WriteBits issue
In the previous implementation, we assumed that we were running on Keil,
so for tools such as OpenOCD, they would not be able to establish a
connection using the SPI rate.

(cherry picked from commit ef71750678aaddbb4d55eb2b428c44b3af122556)
2024-06-22 14:53:03 +08:00
windowsair 0d8d7a014f fix(dap): Only setup SWD port when using SPI speed
Connection problems may occur at SPI speeds when DAP_Connect and
DAP_SWJ_Clock are called in different orders.

Let's setup SWD at SPI rates to avoid potential timing issues.

(cherry picked from commit a89be4248eb7676109183183b0360dd57e02f039)
2024-06-22 14:52:26 +08:00
kerms 2426e56191 fix(soft reset) when reset, manual write to AIRCR/SYSRESETREQ 2024-06-22 14:52:10 +08:00
kerms a48936a90a reformat: code cleanup and reformat some API_JSON returns 2024-06-22 14:52:02 +08:00
kerms 3386a56024 feat(wt_system api): get fm_ver and software reboot 2024-06-22 14:46:20 +08:00
kerms b5a4b38c8d fix(ws) memory leak due to json.in and ws not closed correctly 2024-06-22 14:32:56 +08:00
kerms 209f62866b fix(ws) concurrent access to websocket 2024-06-22 14:28:48 +08:00
kerms 8fba1208f3 reformat(static_buffer) to memory_pool and feat:global resource management 2024-06-22 14:12:31 +08:00
41 changed files with 890 additions and 358 deletions

5
.gitignore vendored
View File

@ -7,6 +7,5 @@ sdkconfig
.idea/ .idea/
dependencies.lock dependencies.lock
package-lock.json package-lock.json
**/priv_note.md managed_components/
_priv_tools/ /version.txt
project_components/wifi_manager/wifi_configuration.h

View File

@ -66,13 +66,13 @@ There is built-in ipv4 only mDNS server. You can access the device using `dap.lo
| JTAG | | | JTAG | |
|--------------------|---------| |--------------------|--------|
| TCK | GPIO6 | | TCK | GPIO6 |
| TMS | GPIO7 | | TMS | GPIO7 |
| TDI | GPIO9 | | TDI | GPIO5 |
| TDO | GPIO8 | | TDO | GPIO3 |
| nTRST \(optional\) | GPIO4 | | nTRST \(optional\) | GPIO4 |
| nRESET | GPIO5 | | nRESET | GPIO10 |
| TVCC | 3V3 | | TVCC | 3V3 |
| GND | GND | | GND | GND |
@ -280,6 +280,39 @@ Recv data <- TCP <- Uart Rx <- external devices
When the TCP connection is established, bridge will try to resolve the text sent for the first packet. When the text is a valid baud rate, bridge will switch to it. When the TCP connection is established, bridge will try to resolve the text sent for the first packet. When the text is a valid baud rate, bridge will switch to it.
For example, sending the ASCII text `115200` will switch the baud rate to 115200. For example, sending the ASCII text `115200` will switch the baud rate to 115200.
<details>
<summary>ESP32C3</summary>
| | PIN |
|-----|--------|
| RX | GPIO20 |
| TX | GPIO21 |
</details>
<details>
<summary>ESP32</summary>
| | PIN |
|-----|--------|
| RX | GPIO22 |
| TX | GPIO23 |
</details>
<details>
<summary>ESP32S3</summary>
| | PIN |
|-----|--------|
| RX | GPIO18 |
| TX | GPIO17 |
</details>
------ ------
## Credit ## Credit

View File

@ -370,10 +370,10 @@ __STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString (char *str) {
#define PIN_SWDIO _ // SPI MISO #define PIN_SWDIO _ // SPI MISO
#define PIN_SWDIO_MOSI 7 // SPI MOSI #define PIN_SWDIO_MOSI 7 // SPI MOSI
#define PIN_SWCLK 6 #define PIN_SWCLK 6
#define PIN_TDO 8 // device TDO -> Host Data Input #define PIN_TDO 3 // device TDO -> Host Data Input
#define PIN_TDI 9 #define PIN_TDI 5
#define PIN_nTRST 4 // optional #define PIN_nTRST 4 // optional
#define PIN_nRESET 5 #define PIN_nRESET 10
#define PIN_LED_CONNECTED _ // won't be used #define PIN_LED_CONNECTED _ // won't be used
#define PIN_LED_RUNNING _ // won't be used #define PIN_LED_RUNNING _ // won't be used

View File

@ -236,6 +236,7 @@ static uint32_t DAP_Connect(const uint8_t *request, uint8_t *response) {
#if (DAP_SWD != 0) #if (DAP_SWD != 0)
case DAP_PORT_SWD: case DAP_PORT_SWD:
DAP_Data.debug_port = DAP_PORT_SWD; DAP_Data.debug_port = DAP_PORT_SWD;
if (SWD_TransferSpeed != kTransfer_SPI)
PORT_SWD_SETUP(); PORT_SWD_SETUP();
break; break;
#endif #endif
@ -273,6 +274,17 @@ static uint32_t DAP_Disconnect(uint8_t *response) {
// return: number of bytes in response // return: number of bytes in response
static uint32_t DAP_ResetTarget(uint8_t *response) { static uint32_t DAP_ResetTarget(uint8_t *response) {
if (DAP_Data.debug_port == DAP_PORT_SWD) {
/* Workaround for software reset */
uint32_t AIRCR_REG_ADDR = 0xE000ED0C;
/* TODO: read AIRCR, retrieve AIRCR_PRIGROUP bits and OR to the write */
uint32_t AIRCR_RESET_VAL = (0x05FA << 16 | 1 << 2); /* Vector key | SYSRESETREQ bit */
SWD_Transfer(0x05,&AIRCR_REG_ADDR);
dap_os_delay(2);
SWD_Transfer(0x0d,&AIRCR_RESET_VAL);
}
*(response+1) = RESET_TARGET(); *(response+1) = RESET_TARGET();
*(response+0) = DAP_OK; *(response+0) = DAP_OK;
return (2U); return (2U);

View File

@ -6,14 +6,16 @@
* 2021-2-11 Support SWD sequence * 2021-2-11 Support SWD sequence
* 2021-3-10 Support 3-wire SPI * 2021-3-10 Support 3-wire SPI
* 2022-9-15 Support ESP32C3 * 2022-9-15 Support ESP32C3
* @version 0.4 * 2024-6-9 Fix DAP_SPI_WriteBits issue
* @date 2022-9-15 * @version 0.5
* @date 2024-6-9
* *
* @copyright MIT License * @copyright MIT License
* *
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include "main/dap_configuration.h" #include "main/dap_configuration.h"
@ -87,6 +89,9 @@ __STATIC_FORCEINLINE int div_round_up(int A, int B)
*/ */
void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf) void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf)
{ {
uint32_t data[16];
int nbytes, i;
DAP_SPI.user.usr_command = 0; DAP_SPI.user.usr_command = 0;
DAP_SPI.user.usr_addr = 0; DAP_SPI.user.usr_addr = 0;
@ -94,39 +99,12 @@ void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf)
DAP_SPI.user.usr_mosi = 1; DAP_SPI.user.usr_mosi = 1;
DAP_SPI.user.usr_miso = 0; DAP_SPI.user.usr_miso = 0;
SET_MOSI_BIT_LEN(count - 1); SET_MOSI_BIT_LEN(count - 1);
// copy data to reg
switch (count)
{
case 8:
DAP_SPI.data_buf[0] = (buf[0] << 0) | (0U << 8) | (0U << 16) | (0U << 24);
break;
case 16:
DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (0x000U << 16) | (0x000U << 24);
break;
case 33: // 32bits data & 1 bit parity
DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
DAP_SPI.data_buf[1] = (buf[4] << 0) | (0x000U << 8) | (0x000U << 16) | (0x000U << 24);
break;
case 51: // for line reset
DAP_SPI.data_buf[0] = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
DAP_SPI.data_buf[1] = (buf[4] << 0) | (buf[5] << 8) | (buf[2] << 16) | (0x000U << 24);
break;
default:
{
uint32_t data_buf[2];
uint8_t *pData = (uint8_t *)data_buf;
int i;
for (i = 0; i < div_round_up(count, 8); i++) nbytes = div_round_up(count, 8);
{ memcpy(data, buf, nbytes);
pData[i] = buf[i];
}
// last byte use mask:
pData[i-1] = pData[i-1] & ((2U >> (count % 8)) - 1U);
DAP_SPI.data_buf[0] = data_buf[0]; for (i = 0; i < nbytes; i++) {
DAP_SPI.data_buf[1] = data_buf[1]; DAP_SPI.data_buf[i] = data[i];
}
} }
START_AND_WAIT_SPI_TRANSMISSION_DONE(); START_AND_WAIT_SPI_TRANSMISSION_DONE();

View File

@ -0,0 +1,9 @@
file(GLOB SOURCES
*.c
)
idf_component_register(
SRCS ${SOURCES}
INCLUDE_DIRS "."
REQUIRES utils wt_common
)

View File

@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "global_module.h"
#include <stddef.h>
#include <esp_log.h>
#define TAG __FILE_NAME__
#define GLOBAL_MODULE_MAX 10
static global_module_t module_arr[GLOBAL_MODULE_MAX] = {0};
static uint8_t module_count = 0;
int global_module_reg(const global_module_t *g_mod)
{
if (g_mod->module_id > GLOBAL_MODULE_MAX) {
ESP_LOGE(TAG, "g_id > max");
return 1;
}
if (module_arr[g_mod->module_id].init != NULL) {
ESP_LOGE(TAG, "g_id.init not NULL");
return 1;
}
ESP_LOGI(TAG, "g_id: %d", g_mod->module_id);
module_arr[g_mod->module_id].module_id = g_mod->module_id;
module_arr[g_mod->module_id].init = g_mod->init;
module_count++;
return 0;
}
int global_module_init()
{
for (int i = 0; i < GLOBAL_MODULE_MAX; ++i) {
if (module_arr[i].init) {
module_arr[i].init();
}
}
return 0;
}

View File

@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef GLOBAL_MODULE_H_GUARD
#define GLOBAL_MODULE_H_GUARD
#include <stdint.h>
typedef int (*global_module_init_func)(void);
typedef struct global_module_t {
global_module_init_func init;
uint8_t module_id;
} global_module_t;
int global_module_reg(const global_module_t *g_mod);
int global_module_init();
#define GLOBAL_MODULE_REGISTER(NAME, GLOBAL_MODULE_CFG) \
__attribute__((used, constructor)) void cons_G_MOD_ ## NAME(); \
void cons_G_MOD_ ## NAME() { global_module_reg(GLOBAL_MODULE_CFG); }
#endif //GLOBAL_MODULE_H_GUARD

View File

@ -4,17 +4,19 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include "static_buffer.h" #include "memory_pool.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/queue.h> #include <freertos/queue.h>
#define BUFFER_NR 4 #define BUFFER_NR 8
#define BUFFER_SZ 2048 #define BUFFER_SZ 2048
static uint8_t buf[BUFFER_NR][BUFFER_SZ]; static uint8_t buf[BUFFER_NR][BUFFER_SZ];
/* TODO: use CAS */
static QueueHandle_t buf_queue = NULL; static QueueHandle_t buf_queue = NULL;
int static_buffer_init() int memory_pool_init()
{ {
if (buf_queue != NULL) if (buf_queue != NULL)
return 0; return 0;
@ -33,22 +35,25 @@ int static_buffer_init()
return 0; return 0;
} }
void *static_buffer_get(uint32_t tick_wait) void *memory_pool_get(uint32_t tick_wait)
{ {
void *ptr = NULL; void *ptr = NULL;
xQueueReceive(buf_queue, &ptr, tick_wait); xQueueReceive(buf_queue, &ptr, tick_wait);
assert(ptr);
return ptr; return ptr;
} }
void static_buffer_put(void *ptr) void memory_pool_put(void *ptr)
{ {
//printf("put buf %d\n", uxQueueMessagesWaiting(buf_queue)); #ifdef WT_DEBUG_MODE
printf("put buf %d\n", uxQueueMessagesWaiting(buf_queue));
#endif
if (unlikely(xQueueSend(buf_queue, &ptr, 0) != pdTRUE)) { if (unlikely(xQueueSend(buf_queue, &ptr, 0) != pdTRUE)) {
assert(0); assert(0);
} }
} }
uint32_t static_buffer_get_buf_size() inline uint32_t memory_pool_get_buf_size()
{ {
return BUFFER_SZ; return BUFFER_SZ;
} }

View File

@ -9,13 +9,13 @@
#include <stdint.h> #include <stdint.h>
int static_buffer_init(); int memory_pool_init();
void *static_buffer_get(uint32_t tick_wait); void *memory_pool_get(uint32_t tick_wait);
void static_buffer_put(void *ptr); void memory_pool_put(void *ptr);
uint32_t static_buffer_get_buf_size(); uint32_t memory_pool_get_buf_size();
#endif //STATIC_BUFFER_H_GUARD #endif //STATIC_BUFFER_H_GUARD

View File

@ -41,6 +41,25 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#include "uart_tcp_bridge.h" #include "uart_tcp_bridge.h"
#if defined CONFIG_IDF_TARGET_ESP32S3
#define UART_PORT UART_NUM_1
#define UART_HW (&UART1)
#define PORT_RX_PIN 18
#define PORT_TX_PIN 17
#elif defined CONFIG_IDF_TARGET_ESP32C3
#define UART_PORT UART_NUM_0
#define UART_HW (&UART0)
#define PORT_RX_PIN 20
#define PORT_TX_PIN 21
#elif defined CONFIG_IDF_TARGET_ESP32
#define UART_PORT UART_NUM_2
#define UART_HW (&UART2)
#define PORT_RX_PIN 16
#define PORT_TX_PIN 17
#else
#error "Unknown target"
#endif
#ifdef CONFIG_IDF_TARGET_ESP8266 #ifdef CONFIG_IDF_TARGET_ESP8266
#define UART_BRIDGE_TX UART_NUM_0 #define UART_BRIDGE_TX UART_NUM_0
#define UART_BRIDGE_RX UART_NUM_1 #define UART_BRIDGE_RX UART_NUM_1
@ -52,8 +71,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#elif defined CONFIG_IDF_TARGET_ESP32C3 #elif defined CONFIG_IDF_TARGET_ESP32C3
#define UART_BRIDGE_TX UART_NUM_1 #define UART_BRIDGE_TX UART_NUM_1
#define UART_BRIDGE_RX UART_NUM_1 #define UART_BRIDGE_RX UART_NUM_1
#define UART_BRIDGE_TX_PIN 19 #define UART_BRIDGE_TX_PIN 21
#define UART_BRIDGE_RX_PIN 18 // PIN18 has 50000ns glitch during the power-up #define UART_BRIDGE_RX_PIN 20
#elif defined CONFIG_IDF_TARGET_ESP32S3 #elif defined CONFIG_IDF_TARGET_ESP32S3
#define UART_BRIDGE_TX UART_NUM_1 #define UART_BRIDGE_TX UART_NUM_1
#define UART_BRIDGE_RX UART_NUM_1 #define UART_BRIDGE_RX UART_NUM_1

View File

@ -10,25 +10,28 @@
#include "wt_storage.h" #include "wt_storage.h"
#include "wifi_manager.h" #include "wifi_manager.h"
#include "web_server.h" #include "web_server.h"
#include "static_buffer.h" #include "memory_pool.h"
#include "request_runner.h" #include "request_runner.h"
#include "uart_tcp_bridge.h" #include "uart_tcp_bridge.h"
#include "global_module.h"
#include <assert.h> #include <assert.h>
void app_main() void app_main()
{ {
assert(static_buffer_init() == 0); assert(memory_pool_init() == 0); // static buffer
assert(request_runner_init() == 0); assert(request_runner_init() == 0);
wt_storage_init(); wt_storage_init();
ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
wt_mdns_init();
wifi_manager_init(); wifi_manager_init();
DAP_Setup(); DAP_Setup();
start_webserver();
wt_mdns_init(); global_module_init();
start_webserver();
xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 14, NULL); xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 14, NULL);

View File

@ -3,8 +3,8 @@
# 2nd stage boot ,data,0x1000, # 2nd stage boot ,data,0x1000,
# partition table,data,0xF000,4K(0x1000), # partition table,data,0xF000,4K(0x1000),
begin ,0x40,0x00 , ,0k , begin ,0x40,0x00 , ,0k ,
nvs ,data,nvs ,0x10000,16K , nvs ,data,nvs ,0x10000 ,16K ,
phy_init ,data,phy , ,4K , phy_init,data,phy , ,4K ,
none0 ,0x40,0x00 , ,0k , none0 ,0x40,0x00 , ,0k ,
ota_0 ,app ,ota_0 ,0x20000,0x1B0000, ota_0 ,app ,ota_0,0x20000 ,0x1B0000,
wt_nvs ,data,nvs , ,64K , wt_nvs ,data,nvs , ,64K ,

1 # Name , Type , SubType , Offset , Size , Flags
3 # 2nd stage boot ,data,0x1000,
4 # partition table,data,0xF000,4K(0x1000),
5 begin ,0x40,0x00 , ,0k , begin ,0x40,0x00 , ,0k ,
6 nvs ,data,nvs ,0x10000,16K , nvs ,data,nvs ,0x10000 ,16K ,
7 phy_init ,data,phy , ,4K , phy_init,data,phy , ,4K ,
8 none0 ,0x40,0x00 , ,0k , none0 ,0x40,0x00 , ,0k ,
9 ota_0 ,app ,ota_0 ,0x20000,0x1B0000, ota_0 ,app ,ota_0,0x20000 ,0x1B0000,
10 wt_nvs ,data,nvs , ,64K , wt_nvs ,data,nvs , ,64K ,

View File

@ -1,9 +1,10 @@
file(GLOB SOURCES * file(GLOB SOURCES *.c
) )
idf_component_register( idf_component_register(
SRCS ${SOURCES} SRCS ${SOURCES}
INCLUDE_DIRS "." INCLUDE_DIRS "."
REQUIRES json request_runner REQUIRES json request_runner wt_common
PRIV_REQUIRES memory_pool
) )

View File

@ -8,6 +8,13 @@
typedef struct api_json_req_t { typedef struct api_json_req_t {
cJSON *in; cJSON *in;
cJSON *out; cJSON *out;
union {
struct {
uint8_t big_buffer: 1;
uint8_t reserved: 7;
};
uint8_t out_flag;
};
} api_json_req_t; } api_json_req_t;
typedef struct api_json_module_req_t { typedef struct api_json_module_req_t {
@ -25,12 +32,16 @@ typedef enum api_json_req_status_e {
API_JSON_OK = 0, API_JSON_OK = 0,
API_JSON_ASYNC = 1, API_JSON_ASYNC = 1,
API_JSON_BAD_REQUEST = 2, API_JSON_BAD_REQUEST = 2,
API_JSON_INTERNAL_ERR = 3,
API_JSON_UNSUPPORTED_CMD = 4,
API_JSON_PROPERTY_ERR = 5,
API_JSON_BUSY = 6,
} api_json_req_status_e; } api_json_req_status_e;
typedef int (*api_json_on_req)(uint16_t cmd, api_json_req_t *req, api_json_module_async_t *rsp); typedef int (*api_json_on_req)(uint16_t cmd, api_json_req_t *req, api_json_module_async_t *rsp);
typedef struct api_json_module_cfg_t { typedef struct api_json_module_cfg_t {
api_json_on_req on_req; api_json_on_req on_req; /* input request callback */
uint8_t module_id; uint8_t module_id;
} api_json_module_cfg_t; } api_json_module_cfg_t;
@ -40,11 +51,8 @@ void api_json_module_dump();
int api_json_module_add(api_json_init_func); int api_json_module_add(api_json_init_func);
/** #define API_JSON_MODULE_REGISTER(INIT) \
* @brief Register a module that will be init with PRI(priority) order. __attribute__((used, constructor)) void cons_ ## INIT(); \
*/
#define API_JSON_MODULE_REGISTER(PRI, INIT) \
__attribute__((used, constructor(PRI))) void cons_ ## INIT(); \
void cons_ ## INIT() { api_json_module_add(INIT); } void cons_ ## INIT() { api_json_module_add(INIT); }
int api_json_module_call(uint8_t id, uint16_t cmd, api_json_req_t *in, api_json_module_async_t *out); int api_json_module_call(uint8_t id, uint16_t cmd, api_json_req_t *in, api_json_module_async_t *out);

View File

@ -26,7 +26,7 @@ _Noreturn void req_long_task(void *arg)
if (unlikely(xQueueReceive(long_run_queue, &req, portMAX_DELAY) != pdTRUE)) { if (unlikely(xQueueReceive(long_run_queue, &req, portMAX_DELAY) != pdTRUE)) {
continue; continue;
} }
req->status = req->module.helper_cb(req->module.arg); req->status = req->module.cb(req->module.arg);
/* if send out queue is busy, set status and let the cb to cancel send out /* if send out queue is busy, set status and let the cb to cancel send out
* */ * */

View File

@ -15,7 +15,7 @@ typedef struct req_send_out_cb_t {
} req_send_out_cb_t; } req_send_out_cb_t;
typedef struct req_module_cb_t { typedef struct req_module_cb_t {
int (*helper_cb)(void *arg); int (*cb)(void *arg);
void *arg; void *arg;
} req_module_cb_t; } req_module_cb_t;

View File

@ -10,7 +10,7 @@ idf_component_register(
SRCS ${SOURCES} SRCS ${SOURCES}
INCLUDE_DIRS "." INCLUDE_DIRS "."
REQUIRES esp_http_server REQUIRES esp_http_server
PRIV_REQUIRES request_runner api_router json static_buffer utils html PRIV_REQUIRES request_runner api_router json memory_pool utils html
) )
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON) idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@ -1,7 +1,7 @@
#include "web_uri_module.h" #include "web_uri_module.h"
#include "api_json_router.h" #include "api_json_router.h"
#include "request_runner.h" #include "request_runner.h"
#include "static_buffer.h" #include "memory_pool.h"
#include <esp_http_server.h> #include <esp_http_server.h>
#include <esp_log.h> #include <esp_log.h>
@ -32,13 +32,13 @@ static esp_err_t api_post_handler(httpd_req_t *req)
char *buf; char *buf;
uint32_t remaining = req->content_len; uint32_t remaining = req->content_len;
buf_len = static_buffer_get_buf_size() - sizeof(post_request_t); buf_len = memory_pool_get_buf_size() - sizeof(post_request_t);
if (unlikely(buf_len < remaining)) { if (unlikely(buf_len < remaining)) {
ESP_LOGE(TAG, "req size %lu > buf_len %lu", remaining, buf_len); ESP_LOGE(TAG, "req size %lu > buf_len %lu", remaining, buf_len);
return ESP_FAIL; return ESP_FAIL;
} }
post_req = static_buffer_get(pdMS_TO_TICKS(20)); post_req = memory_pool_get(pdMS_TO_TICKS(20));
if (unlikely(post_req == NULL)) { if (unlikely(post_req == NULL)) {
ESP_LOGE(TAG, "static buf busy"); ESP_LOGE(TAG, "static buf busy");
return ESP_FAIL; return ESP_FAIL;
@ -97,7 +97,7 @@ end:
ESP_LOGE(TAG, "resp_send err: %s", esp_err_to_name(err)); ESP_LOGE(TAG, "resp_send err: %s", esp_err_to_name(err));
} }
put_buf: put_buf:
static_buffer_put(post_req); memory_pool_put(post_req);
return err; return err;
} }
@ -107,7 +107,7 @@ int uri_api_send_out(httpd_req_t *req, post_request_t *post_req, int err)
uint32_t buf_len; uint32_t buf_len;
buf = post_req->buf; buf = post_req->buf;
buf_len = static_buffer_get_buf_size() - sizeof(post_request_t); buf_len = memory_pool_get_buf_size() - sizeof(post_request_t);
cJSON_Delete(post_req->json.in); cJSON_Delete(post_req->json.in);
if (post_req->json.out) { if (post_req->json.out) {
ESP_LOGI(TAG, "json out ok"); ESP_LOGI(TAG, "json out ok");
@ -136,7 +136,7 @@ void async_send_out_cb(void *arg, int module_status)
/* clean resources */ /* clean resources */
httpd_req_async_handler_complete(req->req_out); httpd_req_async_handler_complete(req->req_out);
static_buffer_put(req); memory_pool_put(req);
}; };
/** /**

View File

@ -20,9 +20,6 @@ httpd_resp_send(req, (const char *)filename##_start, file_size);
static esp_err_t html_base_get_handler(httpd_req_t *req) static esp_err_t html_base_get_handler(httpd_req_t *req)
{ {
char *buf;
size_t buf_len;
/* this "hash" actually use the first 4 chars as an int32_t "hash" */ /* this "hash" actually use the first 4 chars as an int32_t "hash" */
const int *URI_HASH = (const int *)req->uri; const int *URI_HASH = (const int *)req->uri;

View File

@ -6,7 +6,7 @@
#include "web_uri_module.h" #include "web_uri_module.h"
#include "api_json_router.h" #include "api_json_router.h"
#include "static_buffer.h" #include "memory_pool.h"
#include <esp_http_server.h> #include <esp_http_server.h>
#include <esp_log.h> #include <esp_log.h>
@ -16,12 +16,27 @@
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/queue.h> #include <freertos/queue.h>
#include <lwipopts.h>
#include <lwip/netdb.h>
#define TAG __FILE_NAME__ #define TAG __FILE_NAME__
#define MSG_BUSY_ERROR "{\"error\":\"Resource busy\"}"
#define MSG_JSON_ERROR "{\"error\":\"JSON parse error\"}"
#define MSG_SEND_JSON_ERROR "{\"error\":\"JSON generation error\"}" // Error message templates
#define MSG_INTERNAL_ERROR "{\"error\":\"\"}" #define ERROR_MSG_TEMPLATE(err_msg, err_code) "{\"error\":\"" err_msg "\", \"code\":" #err_code "}"
// Error messages
#define MSG_BAD_REQUEST_ERROR ERROR_MSG_TEMPLATE("Bad json request", 2)
#define MSG_JSON_ERROR ERROR_MSG_TEMPLATE("JSON parse error", 3)
#define MSG_SEND_JSON_ERROR ERROR_MSG_TEMPLATE("JSON generation error", 3)
#define MSG_INTERNAL_ERROR ERROR_MSG_TEMPLATE("Internal error", 3)
#define MSG_UNSUPPORTED_CMD ERROR_MSG_TEMPLATE("Unsupported cmd", 4)
#define MSG_PROPERTY_ERROR ERROR_MSG_TEMPLATE("Property error", 5)
#define MSG_BUSY_ERROR ERROR_MSG_TEMPLATE("Resource busy", 6)
#define GET_FD_IDX(fd) ((fd) - LWIP_SOCKET_OFFSET)
#define WS_MODULE_ID 3
typedef struct ws_msg_t { typedef struct ws_msg_t {
api_json_req_t json; api_json_req_t json;
@ -33,28 +48,39 @@ typedef struct ws_msg_t {
uint8_t payload[0]; /* size = static_buf_size - offsetof(this, delim) */ uint8_t payload[0]; /* size = static_buf_size - offsetof(this, delim) */
} ws_msg_t; } ws_msg_t;
#define PAYLOAD_LEN static_buffer_get_buf_size() - sizeof(ws_msg_t) #define PAYLOAD_LEN memory_pool_get_buf_size() - sizeof(ws_msg_t)
struct ws_ctx_t { struct ws_ctx_t {
struct ws_client_info_t { struct ws_client_info_t {
httpd_handle_t hd; httpd_handle_t hd;
int fd; /* range 58 ~ 58+max_socket */ int fd; /* range 64 - max_socket ~ 64 */
} clients[CONFIG_LWIP_MAX_SOCKETS+1]; } clients[CONFIG_LWIP_MAX_SOCKETS];
TaskHandle_t task_heartbeat; TaskHandle_t task_heartbeat;
/* valid <client_count> fd are stored at beginning of the array
* use GET_FD_IDX to get the index in clients */
uint8_t valid_fd[CONFIG_LWIP_MAX_SOCKETS];
int8_t client_count; int8_t client_count;
struct {
SemaphoreHandle_t mutex;
StaticSemaphore_t xMutexBuffer;
} lock[CONFIG_LWIP_MAX_SOCKETS];
} ws_ctx; } ws_ctx;
static int ws_on_text_data(httpd_req_t *req, ws_msg_t *ws_msg); static int ws_on_text_data(httpd_req_t *req, ws_msg_t *ws_msg);
static int ws_on_binary_data(httpd_req_t *req, ws_msg_t *ws_msg); static int ws_on_binary_data(httpd_req_t *req, ws_msg_t *ws_msg);
static int ws_on_socket_open(httpd_req_t *req); static int ws_on_socket_open(httpd_req_t *req);
static int ws_on_close(httpd_req_t *req, ws_msg_t *msg); static int ws_on_close(httpd_req_t *req, httpd_ws_frame_t *ws_pkt, void *msg);
/* send with lock per fd */
static inline int ws_send_frame_safe(httpd_handle_t hd, int fd, httpd_ws_frame_t *frame);
static void ws_async_resp(void *arg); static void ws_async_resp(void *arg);
static void async_send_out_cb(void *arg, int module_status); static void async_send_out_cb(void *arg, int module_status);
static void json_to_text(ws_msg_t *msg); static void json_to_text(ws_msg_t *msg);
/* Heartbeat related */ /* Heartbeat related */
static inline void ws_add_fd(httpd_handle_t hd, int fd); static inline int8_t ws_add_fd(httpd_handle_t hd, int fd);
static inline void ws_rm_fd(int fd); static inline void ws_rm_fd(int fd);
_Noreturn static void heartbeat_task(void *arg); _Noreturn static void heartbeat_task(void *arg);
@ -66,23 +92,24 @@ static esp_err_t ws_req_handler(httpd_req_t *req)
if (unlikely(req->method == HTTP_GET)) { if (unlikely(req->method == HTTP_GET)) {
return ws_on_socket_open(req); return ws_on_socket_open(req);
} }
#ifdef WT_DEBUG_MODE
ESP_LOGI(TAG, "ws_handler: httpd_handle_t=%p, sockfd=%d, client_info:%d, client_count: %d", req->handle, ESP_LOGI(TAG, "ws_handler: httpd_handle_t=%p, sockfd=%d, client_info:%d, client_count: %d", req->handle,
httpd_req_to_sockfd(req), httpd_ws_get_fd_info(req->handle, httpd_req_to_sockfd(req)), httpd_req_to_sockfd(req), httpd_ws_get_fd_info(req->handle, httpd_req_to_sockfd(req)),
ws_ctx.client_count); ws_ctx.client_count);
#endif
int err = ESP_OK; int err = ESP_OK;
httpd_ws_frame_t *ws_pkt; httpd_ws_frame_t *ws_pkt;
ws_msg_t *ws_msg; ws_msg_t *ws_msg;
ws_msg = static_buffer_get(pdMS_TO_TICKS(10)); ws_msg = memory_pool_get(pdMS_TO_TICKS(10));
if (unlikely(ws_msg == NULL)) { if (unlikely(ws_msg == NULL)) {
httpd_ws_frame_t resp_pkt; httpd_ws_frame_t resp_pkt;
resp_pkt.type = HTTPD_WS_TYPE_TEXT; resp_pkt.type = HTTPD_WS_TYPE_TEXT;
resp_pkt.len = strlen(MSG_BUSY_ERROR); resp_pkt.len = strlen(MSG_BUSY_ERROR);
resp_pkt.payload = (uint8_t *)MSG_BUSY_ERROR; resp_pkt.payload = (uint8_t *)MSG_BUSY_ERROR;
resp_pkt.final = 1; resp_pkt.final = 1;
httpd_ws_send_frame_async(req->handle, httpd_req_to_sockfd(req), &resp_pkt); ws_send_frame_safe(req->handle, httpd_req_to_sockfd(req), &resp_pkt);
goto end; goto end;
} }
ws_pkt = &ws_msg->ws_pkt; ws_pkt = &ws_msg->ws_pkt;
@ -92,41 +119,47 @@ static esp_err_t ws_req_handler(httpd_req_t *req)
err = httpd_ws_recv_frame(req, ws_pkt, 0); err = httpd_ws_recv_frame(req, ws_pkt, 0);
if (unlikely(err != ESP_OK)) { if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "ws recv len error"); ESP_LOGE(TAG, "ws recv len error");
return ws_on_close(req, ws_msg); return ws_on_close(req, ws_pkt, ws_msg);
} }
#ifdef WT_DEBUG_MODE
ESP_LOGI(TAG, "frame len: %d, type: %d", ws_pkt->len, ws_pkt->type); ESP_LOGI(TAG, "frame len: %d, type: %d", ws_pkt->len, ws_pkt->type);
#endif
if (unlikely(ws_pkt->len > PAYLOAD_LEN)) { if (unlikely(ws_pkt->len > PAYLOAD_LEN)) {
ESP_LOGE(TAG, "frame len is too big"); ESP_LOGE(TAG, "frame len is too big");
return ws_on_close(req, ws_msg); return ws_on_close(req, ws_pkt, ws_msg);
} }
ws_pkt->payload = ws_msg->payload;
switch (ws_pkt->type) { switch (ws_pkt->type) {
case HTTPD_WS_TYPE_CONTINUE: case HTTPD_WS_TYPE_CONTINUE:
ESP_LOGE(TAG, "WS Continue not handled");
goto end; goto end;
case HTTPD_WS_TYPE_TEXT: case HTTPD_WS_TYPE_TEXT:
ws_pkt->payload = ws_msg->payload;
/* read incoming data */ /* read incoming data */
err = httpd_ws_recv_frame(req, ws_pkt, ws_pkt->len); err = httpd_ws_recv_frame(req, ws_pkt, ws_pkt->len);
if (unlikely(err != ESP_OK)) { if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "ws recv data error"); ESP_LOGE(TAG, "ws recv data error");
return ws_on_close(req, ws_msg); return ws_on_close(req, ws_pkt, ws_msg);
} }
return ws_on_text_data(req, ws_msg); return ws_on_text_data(req, ws_msg);
case HTTPD_WS_TYPE_BINARY: case HTTPD_WS_TYPE_BINARY:
ws_pkt->payload = ws_msg->payload;
/* read incoming data */
err = httpd_ws_recv_frame(req, ws_pkt, ws_pkt->len);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "ws recv data error");
return ws_on_close(req, ws_msg);
}
return ws_on_binary_data(req, ws_msg); return ws_on_binary_data(req, ws_msg);
case HTTPD_WS_TYPE_CLOSE: case HTTPD_WS_TYPE_CLOSE:
return ws_on_close(req, ws_msg); if ((err = httpd_ws_recv_frame(req, ws_pkt, 126)) != ESP_OK) {
ESP_LOGE(TAG, "Cannot receive the full CLOSE frame");
}
return ws_on_close(req, ws_pkt, ws_msg);
case HTTPD_WS_TYPE_PING: case HTTPD_WS_TYPE_PING:
/* Now turn the frame to PONG */ /* Now turn the frame to PONG */
if ((err = httpd_ws_recv_frame(req, ws_pkt, 126)) != ESP_OK) {
ESP_LOGE(TAG, "Cannot receive the full PONG frame");
return ws_on_close(req, ws_pkt, ws_msg);
}
ws_pkt->type = HTTPD_WS_TYPE_PONG; ws_pkt->type = HTTPD_WS_TYPE_PONG;
err = httpd_ws_send_frame(req, ws_pkt); err = ws_send_frame_safe(req->handle, httpd_req_to_sockfd(req), ws_pkt);
if (err) {
ESP_LOGE(TAG, "Cannot send PONG frame %s", esp_err_to_name(err));
return ws_on_close(req, ws_pkt, ws_msg);
}
goto end; goto end;
case HTTPD_WS_TYPE_PONG: case HTTPD_WS_TYPE_PONG:
err = ESP_OK; err = ESP_OK;
@ -136,10 +169,262 @@ static esp_err_t ws_req_handler(httpd_req_t *req)
goto end; goto end;
} }
end: end:
static_buffer_put(ws_msg); memory_pool_put(ws_msg);
return err; return err;
} }
void ws_set_err_msg(httpd_ws_frame_t *p_frame, api_json_req_status_e ret);
int ws_on_text_data(httpd_req_t *req, ws_msg_t *ws_msg)
{
int err = ESP_OK;
int ret;
httpd_ws_frame_t *ws_pkt;
ws_pkt = &ws_msg->ws_pkt;
ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
ESP_LOGI(TAG, "%.*s", ws_pkt->len, ws_pkt->payload);
ESP_LOGI(TAG, "====================================");
ESP_LOGI(TAG, "heap min: %lu, cur: %lu", esp_get_minimum_free_heap_size(), esp_get_free_heap_size());
/* Decode */
ws_msg->json.in = cJSON_ParseWithLength((char *)ws_pkt->payload, ws_pkt->len);
if (unlikely(ws_msg->json.in == NULL)) {
ws_pkt->payload = (uint8_t *)MSG_JSON_ERROR;
ws_pkt->len = strlen(MSG_JSON_ERROR);
goto put_buf;
}
ws_msg->json.out = NULL;
ws_msg->json.out_flag = 0;
ret = api_json_route(&ws_msg->json, &ws_msg->async);
if (ret == API_JSON_ASYNC) {
ws_msg->hd = req->handle;
ws_msg->fd = httpd_req_to_sockfd(req);
ws_msg->async.req_task.send_out.cb = async_send_out_cb;
ws_msg->async.req_task.send_out.arg = ws_msg;
if (req_queue_push_long_run(&ws_msg->async.req_task, pdMS_TO_TICKS(20))) {
/* queued failed */
goto end;
}
/* ret, buf will be release latter in async send out */
return ESP_OK;
} else if (ret != API_JSON_OK) {
ws_set_err_msg(ws_pkt, ret);
goto end;
} else if (ws_msg->json.out == NULL) {
/* API exec ok */
goto end;
}
/* api function returns something, send it to http client */
json_to_text(ws_msg);
end:
cJSON_Delete(ws_msg->json.in);
put_buf:
ws_send_frame_safe(req->handle, httpd_req_to_sockfd(req), ws_pkt);
memory_pool_put(ws_msg);
return err;
}
void ws_set_err_msg(httpd_ws_frame_t *p_frame, api_json_req_status_e ret)
{
p_frame->final = 1;
switch (ret) {
case API_JSON_BAD_REQUEST:
p_frame->len = strlen(MSG_BAD_REQUEST_ERROR);
p_frame->payload = (uint8_t *)MSG_BAD_REQUEST_ERROR;
break;
case API_JSON_BUSY:
p_frame->len = strlen(MSG_BUSY_ERROR);
p_frame->payload = (uint8_t *)MSG_BUSY_ERROR;
break;
case API_JSON_UNSUPPORTED_CMD:
p_frame->len = strlen(MSG_UNSUPPORTED_CMD);
p_frame->payload = (uint8_t *)MSG_UNSUPPORTED_CMD;
break;
case API_JSON_PROPERTY_ERR:
p_frame->len = strlen(MSG_PROPERTY_ERROR);
p_frame->payload = (uint8_t *)MSG_PROPERTY_ERROR;
break;
default:
p_frame->len = strlen(MSG_INTERNAL_ERROR);
p_frame->payload = (uint8_t *)MSG_INTERNAL_ERROR;
return;
}
}
_Static_assert(sizeof(httpd_ws_frame_t) <= 16, "bin_data_internal padding not sufficient for httpd_ws_frame_t");
int ws_on_binary_data(httpd_req_t *req, ws_msg_t *ws_msg)
{
(void) req;
memory_pool_put(ws_msg);
return 0;
}
int ws_on_socket_open(httpd_req_t *req)
{
int sock_fd = httpd_req_to_sockfd(req);
ESP_LOGI(TAG, "ws open: %d", sock_fd);
return ws_add_fd(req->handle, sock_fd);
}
/**
* @param msg must only used as generic ptr, truncated by ws_on_bin()
* @return
*/
static int ws_on_close(httpd_req_t *req, httpd_ws_frame_t *ws_pkt, void *msg)
{
/* Read the rest of the CLOSE frame and response */
/* Please refer to RFC6455 Section 5.5.1 for more details */
ws_pkt->len = 0;
ws_pkt->type = HTTPD_WS_TYPE_CLOSE;
ESP_LOGI(TAG, "ws %d closed", httpd_req_to_sockfd(req));
ws_rm_fd(httpd_req_to_sockfd(req));
int err = httpd_ws_send_frame_async(req, httpd_req_to_sockfd(req), ws_pkt);
if (err) {
ESP_LOGE(TAG, "on close %s", esp_err_to_name(err));
}
httpd_sess_trigger_close(req->handle, httpd_req_to_sockfd(req));
memory_pool_put(msg);
return err;
}
static void ws_async_resp(void *arg)
{
ws_msg_t *req = arg;
httpd_handle_t hd = req->hd;
int fd = req->fd;
int err;
ESP_LOGI(TAG, "ws async fd : %d", fd);
err = ws_send_frame_safe(hd, fd, &req->ws_pkt);
if (unlikely(err)) {
ESP_LOGE(TAG, "%s", esp_err_to_name(err));
}
memory_pool_put(req);
}
void async_send_out_cb(void *arg, int module_status)
{
ws_msg_t *req = arg;
cJSON_Delete(req->json.in);
ESP_LOGI(TAG, "send out %d", module_status);
if (module_status != API_JSON_OK) {
req->ws_pkt.payload = req->payload;
ws_set_err_msg(&req->ws_pkt, module_status);
int err = ws_send_frame_safe(req->hd, req->fd, &req->ws_pkt);
if (err) {
ESP_LOGE(TAG, "send out %s", esp_err_to_name(err));
}
goto end;
}
int err;
json_to_text(req);
err = httpd_queue_work(req->hd, ws_async_resp, req);
if (likely(err == ESP_OK)) {
/* msg queued, let callee release the buffer */
return;
}
ESP_LOGE(TAG, "errno: %d, fd %p: %s", errno, req->hd, esp_err_to_name(err));
end:
/* clean resources */
memory_pool_put(req);
}
void json_to_text(ws_msg_t *ws_msg)
{
int err;
httpd_ws_frame_t *ws_pkt = &ws_msg->ws_pkt;
/* api function returns something, send it to http client */
err = !cJSON_PrintPreallocated(ws_msg->json.out, (char *)ws_pkt->payload, PAYLOAD_LEN - 5, 0);
cJSON_Delete(ws_msg->json.out);
if (unlikely(err)) {
ws_pkt->len = strlen(MSG_SEND_JSON_ERROR);
ws_pkt->payload = (uint8_t *)MSG_SEND_JSON_ERROR;
ws_pkt->final = 1;
}
ws_pkt->len = strlen((char *)ws_pkt->payload);
}
/* Clients array manipulation function
* */
static inline int8_t ws_add_fd(httpd_handle_t hd, int fd)
{
if (ws_ctx.client_count >= CONFIG_LWIP_MAX_SOCKETS) {
return 1;
}
uint8_t idx = GET_FD_IDX(fd);
ws_ctx.clients[idx].fd = fd;
ws_ctx.clients[idx].hd = hd;
ws_ctx.valid_fd[ws_ctx.client_count] = fd;
ws_ctx.client_count++;
return 0;
}
/**
* @brief replace the fd and hd to be removed by the last item
* all front items are valid
*/
static inline void ws_rm_fd(int fd)
{
for (int i = 0; i < ws_ctx.client_count; ++i) {
if (ws_ctx.valid_fd[i] != fd) {
continue;
}
ws_ctx.valid_fd[i] = ws_ctx.valid_fd[ws_ctx.client_count - 1];
ws_ctx.client_count--;
return;
}
}
static inline int ws_send_frame_safe(httpd_handle_t hd, int fd, httpd_ws_frame_t *frame)
{
int err;
xSemaphoreTake(ws_ctx.lock[GET_FD_IDX(fd)].mutex, portMAX_DELAY);
err = httpd_ws_send_frame_async(hd, fd, frame);
xSemaphoreGive(ws_ctx.lock[GET_FD_IDX(fd)].mutex);
return err;
}
static inline void ws_broadcast_heartbeat()
{
static httpd_ws_frame_t ws_pkt = {
.len = 0,
.payload = NULL,
.type = HTTPD_WS_TYPE_TEXT,
};
int err;
for (int i = 0; i < ws_ctx.client_count; ++i) {
uint8_t idx = GET_FD_IDX(ws_ctx.valid_fd[i]);
err = ws_send_frame_safe(ws_ctx.clients[idx].hd, ws_ctx.clients[idx].fd, &ws_pkt);
if (err) {
ws_rm_fd(ws_ctx.clients[idx].fd);
httpd_sess_trigger_close(ws_ctx.clients[idx].hd, ws_ctx.clients[idx].fd);
ESP_LOGE(TAG, "hb send err: %s", esp_err_to_name(err));
}
}
}
_Noreturn
void heartbeat_task(void *arg)
{
(void)arg;
while (1) {
vTaskDelay(pdMS_TO_TICKS(1500));
ws_broadcast_heartbeat();
}
};
/** /**
* REGISTER MODULE * REGISTER MODULE
@ -155,13 +440,20 @@ static const httpd_uri_t uri_api = {
.handle_ws_control_frames = true, .handle_ws_control_frames = true,
}; };
static int WS_REQ_INIT(const httpd_uri_t **uri_conf) { static int WS_REQ_INIT(const httpd_uri_t **uri_conf)
{
*uri_conf = &uri_api; *uri_conf = &uri_api;
xTaskCreate(heartbeat_task, "hb task", 2048, NULL, 3, &ws_ctx.task_heartbeat); xTaskCreate(heartbeat_task, "hb task", 2048, NULL, 3, &ws_ctx.task_heartbeat);
ws_ctx.client_count = 0;
for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; ++i) {
ws_ctx.lock[i].mutex = xSemaphoreCreateMutexStatic(&ws_ctx.lock[i].xMutexBuffer);
}
return 0; return 0;
} }
static int WS_REQ_EXIT(const httpd_uri_t **uri_conf) { static int WS_REQ_EXIT(const httpd_uri_t **uri_conf)
{
*uri_conf = &uri_api; *uri_conf = &uri_api;
vTaskDelete(ws_ctx.task_heartbeat); vTaskDelete(ws_ctx.task_heartbeat);
ws_ctx.task_heartbeat = NULL; ws_ctx.task_heartbeat = NULL;
@ -169,209 +461,3 @@ static int WS_REQ_EXIT(const httpd_uri_t **uri_conf) {
} }
WEB_URI_MODULE_REGISTER(101, WS_REQ_INIT, WS_REQ_EXIT) WEB_URI_MODULE_REGISTER(101, WS_REQ_INIT, WS_REQ_EXIT)
int ws_on_text_data(httpd_req_t *req, ws_msg_t *ws_msg)
{
int err = ESP_OK;
int ret;
httpd_ws_frame_t *ws_pkt;
ws_pkt = &ws_msg->ws_pkt;
ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
ESP_LOGI(TAG, "%.*s", ws_pkt->len, ws_pkt->payload);
ESP_LOGI(TAG, "====================================");
ESP_LOGI(TAG, "heap min: %lu, cur: %lu", esp_get_minimum_free_heap_size(), esp_get_free_heap_size());
/* Decode */
ws_msg->json.in = cJSON_ParseWithLength((char *) ws_pkt->payload, ws_pkt->len);
if (unlikely(ws_msg->json.in == NULL)) {
ws_pkt->payload = (uint8_t *) MSG_JSON_ERROR;
ws_pkt->len = strlen(MSG_JSON_ERROR);
goto put_buf;
}
ws_msg->json.out = NULL;
ret = api_json_route(&ws_msg->json, &ws_msg->async);
if (ret == API_JSON_ASYNC) {
ws_msg->hd = req->handle;
ws_msg->fd = httpd_req_to_sockfd(req);
ws_msg->async.req_task.send_out.cb = async_send_out_cb;
ws_msg->async.req_task.send_out.arg = ws_msg;
if (req_queue_push_long_run(&ws_msg->async.req_task, pdMS_TO_TICKS(20))) {
/* queued failed */
goto end;
}
/* ret, buf will be release latter in async send out */
return ESP_OK;
} else if (ret != API_JSON_OK) {
ws_pkt->len = strlen(MSG_BUSY_ERROR);
ws_pkt->payload = (uint8_t *)MSG_BUSY_ERROR;
ws_pkt->final = 1;
err = httpd_ws_send_frame_async(req->handle, httpd_req_to_sockfd(req), ws_pkt);
goto end;
} else if (ws_msg->json.out == NULL) {
goto end;
}
/* api function returns something, send it to http client */
json_to_text(ws_msg);
end:
cJSON_Delete(ws_msg->json.in);
put_buf:
httpd_ws_send_frame_async(req->handle, httpd_req_to_sockfd(req), ws_pkt);
static_buffer_put(ws_msg);
return err;
}
int ws_on_binary_data(httpd_req_t *req, ws_msg_t *ws_msg)
{
(void) req;
static_buffer_put(ws_msg);
return 0;
}
int ws_on_socket_open(httpd_req_t *req)
{
int sock_fd = httpd_req_to_sockfd(req);
ws_add_fd(req->handle, sock_fd);
ESP_LOGI(TAG, "ws open: %d", sock_fd);
return ESP_OK;
}
static int ws_on_close(httpd_req_t *req, ws_msg_t *msg)
{
/* Read the rest of the CLOSE frame and response */
/* Please refer to RFC6455 Section 5.5.1 for more details */
msg->ws_pkt.len = 0;
msg->ws_pkt.type = HTTPD_WS_TYPE_CLOSE;
ESP_LOGI(TAG, "ws %d closed", httpd_req_to_sockfd(req));
ws_rm_fd(httpd_req_to_sockfd(req));
int err = httpd_ws_send_frame(req, &msg->ws_pkt);
if (err) {
ESP_LOGE(TAG, "on close %s", esp_err_to_name(err));
}
httpd_sess_trigger_close(req->handle, httpd_req_to_sockfd(req));
static_buffer_put(msg);
return err;
}
static void ws_async_resp(void *arg)
{
ws_msg_t *req = arg;
httpd_handle_t hd = req->hd;
int fd = req->fd;
int err;
ESP_LOGI(TAG, "ws async fd : %d", fd);
err = httpd_ws_send_frame_async(hd, fd, &req->ws_pkt);
if (err) {
ESP_LOGE(TAG, "%s", esp_err_to_name(err));
}
static_buffer_put(req);
}
void async_send_out_cb(void *arg, int module_status)
{
ws_msg_t *req = arg;
if (module_status != API_JSON_OK) {
goto end;
}
int err;
json_to_text(req);
err = httpd_queue_work(req->hd, ws_async_resp, req);
if (likely(err == ESP_OK)) {
return;
}
ESP_LOGE(TAG, "errno: %d, fd %p: %s", errno, req->hd, esp_err_to_name(err));
end:
/* clean resources */
static_buffer_put(req);
}
void json_to_text(ws_msg_t *ws_msg)
{
int err;
httpd_ws_frame_t *ws_pkt = &ws_msg->ws_pkt;
/* api function returns something, send it to http client */
err = !cJSON_PrintPreallocated(ws_msg->json.out, (char *) ws_msg->payload, PAYLOAD_LEN - 5, 0);
cJSON_Delete(ws_msg->json.out);
if (unlikely(err)) {
ws_pkt->len = strlen(MSG_SEND_JSON_ERROR);
ws_pkt->payload = (uint8_t *) MSG_SEND_JSON_ERROR;
ws_pkt->final = 1;
}
ws_pkt->len = strlen((char *) ws_pkt->payload);
}
/* Clients array manipulation function
* */
static inline void ws_add_fd(httpd_handle_t hd, int fd)
{
if (ws_ctx.client_count > CONFIG_LWIP_MAX_SOCKETS) {
return;
}
ws_ctx.clients[ws_ctx.client_count].fd = fd;
ws_ctx.clients[ws_ctx.client_count].hd = hd;
ws_ctx.client_count++;
}
/**
* @brief replace the fd and hd to be removed by the last item
* all front items are valid
*/
static inline void ws_rm_fd(int fd)
{
for (int i = 0; i < ws_ctx.client_count; ++i) {
if (ws_ctx.clients[i].fd == fd) {
ws_ctx.clients[i].fd = ws_ctx.clients[ws_ctx.client_count-1].fd;
ws_ctx.clients[i].hd = ws_ctx.clients[ws_ctx.client_count-1].hd;
ws_ctx.client_count--;
return;
}
}
}
static void send_heartbeat(void *arg)
{
static httpd_ws_frame_t ws_pkt = {
.len = 0,
.payload = NULL,
.type = HTTPD_WS_TYPE_TEXT,
};
struct ws_client_info_t *client_info = arg;
int err;
err = httpd_ws_send_frame_async(client_info->hd, client_info->fd, &ws_pkt);
if (err) {
ws_rm_fd(client_info->fd);
httpd_sess_trigger_close(client_info->hd, client_info->fd);
ESP_LOGE(TAG, "hb send err: %s", esp_err_to_name(err));
}
}
static inline void ws_broadcast_heartbeat()
{
int err;
for (int i = 0; i < ws_ctx.client_count; ++i) {
err = httpd_queue_work(ws_ctx.clients[i].hd, send_heartbeat, &ws_ctx.clients[i]);
if (err) {
ESP_LOGE(TAG, "hb queue work err: %s", esp_err_to_name(err));
}
}
}
_Noreturn
void heartbeat_task(void *arg)
{
(void) arg;
while (1) {
vTaskDelay(pdMS_TO_TICKS(2000));
ws_broadcast_heartbeat();
}
};

View File

@ -11,10 +11,15 @@ typedef struct uri_module_t {
uint8_t priority; uint8_t priority;
} uri_module_t; } uri_module_t;
/**
* @param priority smaller number will be called first
* @return 0: SUCCESS, 1: max module count reached
*/
int uri_module_add(uint8_t priority, uri_module_func init, uri_module_func exit); int uri_module_add(uint8_t priority, uri_module_func init, uri_module_func exit);
/** /**
* @brief Register a uri module that will be init with PRI(priority) order. * @brief Register a uri module that will be init with PRI(priority) order.
* smaller priority will be called first.
*/ */
#define WEB_URI_MODULE_REGISTER(PRI, INIT, EXIT) \ #define WEB_URI_MODULE_REGISTER(PRI, INIT, EXIT) \
__attribute__((used, constructor(PRI))) void cons_ ## INIT(); \ __attribute__((used, constructor(PRI))) void cons_ ## INIT(); \

View File

@ -11,7 +11,7 @@ file(GLOB SOURCES
idf_component_register( idf_component_register(
SRCS ${SOURCES} SRCS ${SOURCES}
INCLUDE_DIRS "." INCLUDE_DIRS "."
PRIV_REQUIRES mdns esp_wifi esp_event api_router wt_storage PRIV_REQUIRES mdns esp_wifi esp_event api_router wt_storage driver
) )
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON) idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@ -3,7 +3,7 @@
#include <lwip/ip4_addr.h> #include <lwip/ip4_addr.h>
#define WIFI_API_MODULE_ID 1 #define WIFI_MODULE_ID 1
typedef enum wifi_api_json_cmd_t { typedef enum wifi_api_json_cmd_t {
UNKNOWN = 0, UNKNOWN = 0,

View File

@ -1,5 +1,3 @@
#include "wifi_api_json.h"
#include "api_json_module.h" #include "api_json_module.h"
#include "wifi_api.h" #include "wifi_api.h"
#include "wifi_json_utils.h" #include "wifi_json_utils.h"
@ -19,7 +17,7 @@ static int wifi_api_json_disconnect(api_json_req_t *req);
static int wifi_api_json_ap_get_info(api_json_req_t *req); static int wifi_api_json_ap_get_info(api_json_req_t *req);
/* the upper caller call cb() with void *, this let us use custom function arg */
static int async_helper_cb(void *arg) static int async_helper_cb(void *arg)
{ {
api_json_module_req_t *req = arg; api_json_module_req_t *req = arg;
@ -30,7 +28,7 @@ static inline int set_async(api_json_req_t *req, api_json_module_async_t *async,
{ {
async->module.func = func; async->module.func = func;
async->module.arg = req; async->module.arg = req;
async->req_task.module.helper_cb = async_helper_cb; async->req_task.module.cb = async_helper_cb;
async->req_task.module.arg = &async->module; async->req_task.module.arg = &async->module;
return API_JSON_ASYNC; return API_JSON_ASYNC;
} }
@ -52,11 +50,10 @@ static int on_json_req(uint16_t cmd, api_json_req_t *req, api_json_module_async_
return wifi_api_json_disconnect(req); return wifi_api_json_disconnect(req);
case WIFI_API_JSON_AP_GET_INFO: case WIFI_API_JSON_AP_GET_INFO:
return wifi_api_json_ap_get_info(req); return wifi_api_json_ap_get_info(req);
break;
} }
ESP_LOGI(TAG, "cmd %d not executed\n", cmd); ESP_LOGI(TAG, "cmd %d not executed\n", cmd);
return API_JSON_BAD_REQUEST; return API_JSON_UNSUPPORTED_CMD;
} }
static int wifi_api_json_sta_get_ap_info(api_json_req_t *req) static int wifi_api_json_sta_get_ap_info(api_json_req_t *req)
@ -127,10 +124,8 @@ int wifi_api_json_disconnect(api_json_req_t *req)
static int wifi_api_json_init(api_json_module_cfg_t *cfg) static int wifi_api_json_init(api_json_module_cfg_t *cfg)
{ {
cfg->on_req = on_json_req; cfg->on_req = on_json_req;
cfg->module_id = WIFI_API_MODULE_ID; cfg->module_id = WIFI_MODULE_ID;
return 0; return 0;
} }
API_JSON_MODULE_REGISTER(0x90, wifi_api_json_init) API_JSON_MODULE_REGISTER(wifi_api_json_init)

View File

@ -1,4 +0,0 @@
#ifndef WIFI_API_JSON_H_GUARD
#define WIFI_API_JSON_H_GUARD
#endif //WIFI_API_JSON_H_GUARD

View File

@ -6,7 +6,7 @@
static void wifi_api_json_set_header(cJSON *root, uint16_t cmd) static void wifi_api_json_set_header(cJSON *root, uint16_t cmd)
{ {
cJSON_AddNumberToObject(root, "cmd", cmd); cJSON_AddNumberToObject(root, "cmd", cmd);
cJSON_AddNumberToObject(root, "module", WIFI_API_MODULE_ID); cJSON_AddNumberToObject(root, "module", WIFI_MODULE_ID);
} }
cJSON *wifi_api_json_serialize_ap_info(wifi_api_ap_info_t *ap_info, wifi_api_json_cmd_t cmd) cJSON *wifi_api_json_serialize_ap_info(wifi_api_ap_info_t *ap_info, wifi_api_json_cmd_t cmd)

View File

@ -4,7 +4,7 @@
#include <stdio.h> #include <stdio.h>
#define NVS_NAMESPACE "wt_wifi" #define WIFI_NVS_NAMESPACE "wt_wifi"
int wifi_data_get_last_conn_cred(wifi_credential_t *ap_credential) int wifi_data_get_last_conn_cred(wifi_credential_t *ap_credential)
{ {
@ -12,7 +12,7 @@ int wifi_data_get_last_conn_cred(wifi_credential_t *ap_credential)
nvs_handle_t handle; nvs_handle_t handle;
int err; int err;
err = wt_nvs_open(NVS_NAMESPACE, &handle); err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle);
if (err) { if (err) {
return WT_NVS_ERR; return WT_NVS_ERR;
} }
@ -41,7 +41,7 @@ int wifi_save_ap_credential(wifi_credential_t *ap_credential)
int err; int err;
nvs_handle_t handle; nvs_handle_t handle;
err = wt_nvs_open(NVS_NAMESPACE, &handle); err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle);
if (err) { if (err) {
return err; return err;
} }

View File

@ -0,0 +1,8 @@
file(GLOB SOURCES *.c
)
idf_component_register(
SRCS ${SOURCES}
INCLUDE_DIRS "."
)

View File

@ -0,0 +1,91 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef WT_DATA_DEF_H_GUARD
#define WT_DATA_DEF_H_GUARD
#include <stdint.h>
#define DECLARE_HANDLE(name) struct name##__ { int unused[0]; }; \
typedef struct name##__ *name
typedef enum wt_data_type_t {
WT_DATA_RESERVED = 0x00,
/* primitive type */
WT_DATA_EVENT = 0x02,
WT_DATA_ROUTE_HDR = 0x03,
WT_DATA_RAW_BROADCAST = 0x04,
/* data_type */
/* broadcast data */
WT_DATA_CMD_BROADCAST = 0x11,
/* targeted data */
WT_DATA_RAW = 0x20,
WT_DATA_CMD = 0x21,
WT_DATA_RESPONSE = 0x22,
/* standard protocols */
WT_DATA_PROTOBUF = 0x40,
WT_DATA_JSON = 0x41,
WT_DATA_MQTT = 0x42,
} __attribute__((packed)) wt_data_type_t;
_Static_assert(sizeof(wt_data_type_t) == 1, "wt_data_type_t must be 1 byte");
typedef struct wt_bin_data_hdr_t {
wt_data_type_t data_type; /* type of the payload */
union {
/* when targeted message -> bin data handle */
struct {
uint8_t module_id; /* src when broadcast, else target module */
uint8_t sub_id; /* src when broadcast, else target sub_id */
};
/* not used, only for make the union == 3B */
struct {
uint8_t dummy1;
uint8_t dummy2;
uint8_t dummy3;
} dummy;
};
} wt_bin_data_hdr_t;
_Static_assert(sizeof(wt_bin_data_hdr_t) == 4, "wt_data_4B_hdr_t must be 4 byte");
typedef struct wt_bin_data_t {
wt_bin_data_hdr_t hdr;
uint8_t payload[0];
} wt_bin_data_t;
typedef struct wt_bin_data_internal_t {
struct {
uint64_t Dummy1;
uint64_t Dummy2;
} ws_frame_slot; /* 16 byte padding for httpd_ws_frame */
struct { /* */
uint16_t data_len;
uint8_t src_module;
uint8_t src_sub_module;
};
struct { /* */
uint8_t send_count;
uint8_t reserved1;
uint16_t reserved2;
};
wt_bin_data_t data;
} wt_bin_data_internal_t;
typedef union wt_port_info {
uint8_t name[32]; /* for ease identification */
struct { /* for socket */
uint32_t foreign_ip;
uint16_t local_port;
uint16_t foreign_port;
};
struct { /* for peripheral port number */
uint8_t periph_num;
};
} wt_port_info_t;
#endif //WT_DATA_DEF_H_GUARD

View File

@ -14,6 +14,22 @@ void wt_mdns_init()
/* TODO: read instance description from NVS */ /* TODO: read instance description from NVS */
ESP_ERROR_CHECK(mdns_instance_name_set(MDSN_INSTANCE_DESC)); ESP_ERROR_CHECK(mdns_instance_name_set(MDSN_INSTANCE_DESC));
//structure with TXT records
mdns_txt_item_t serviceTxtData[] = {
#if defined CONFIG_IDF_TARGET_ESP32S3
{"board", "esp32S3"},
#elif defined CONFIG_IDF_TARGET_ESP32C3
{"board", "esp32c3"},
#elif defined CONFIG_IDF_TARGET_ESP32
{"board", "esp32"},
#endif
};
//initialize service
ESP_ERROR_CHECK(mdns_service_add("WebServer", "_http", "_tcp", 80,
serviceTxtData, sizeof(serviceTxtData)/sizeof(serviceTxtData[0])));
ESP_ERROR_CHECK(mdns_service_subtype_add_for_host("WebServer", "_http", "_tcp", NULL, "_server") );
} }
int wt_mdns_set_hostname(const char *hostname) int wt_mdns_set_hostname(const char *hostname)

View File

@ -2,7 +2,7 @@
#define WT_MDNS_CONFIG_H_GUARD #define WT_MDNS_CONFIG_H_GUARD
#define MDSN_DEFAULT_HOSTNAME "dap" // + serial number (4 char) #define MDSN_DEFAULT_HOSTNAME "dap" // + serial number (4 char)
#define MDSN_INSTANCE_DESC "无线STM32调试器 by 允斯工作室" #define MDSN_INSTANCE_DESC "ESP32 无线透传"
void wt_mdns_init(); void wt_mdns_init();

View File

@ -0,0 +1,26 @@
file(GLOB SOURCES *.c
)
idf_component_register(
SRCS ${SOURCES}
INCLUDE_DIRS "."
PRIV_REQUIRES
global_resource esp_app_format api_router
)
# Execute the Git command to get the formatted commit date
execute_process(
COMMAND git show -s --format=%cd --date=format:'%Y-%m-%d'
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE FM_DATE
RESULT_VARIABLE result
ERROR_VARIABLE git_error
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT "${result}" STREQUAL "0")
message(WARNING "Git command failed with: ${git_error}")
endif()
target_compile_definitions(${COMPONENT_LIB} PRIVATE FW_UPD_DATE="${FM_DATE}")
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "wt_system.h"
#include "wt_system_api.h"
#include <esp_app_desc.h>
#include <string.h>
#include <esp_system.h>
#include <freertos/FreeRTOS.h>
#include <esp_log.h>
#define TAG "WT_SYS"
void wt_system_get_fm_info(wt_fm_info_t *fm_info)
{
const esp_app_desc_t *app_desc = esp_app_get_description();
strcpy(fm_info->fm_ver, app_desc->version);
memcpy(fm_info->upd_date, FW_UPD_DATE, sizeof(fm_info->upd_date) - 1);
fm_info->upd_date[sizeof(fm_info->upd_date) - 1] = '\0';
}
static void reboot_task(void *arg)
{
ESP_LOGW(TAG, "reboot in 2 seconds");
vTaskDelay(pdMS_TO_TICKS(2000));
esp_restart();
}
void wt_system_reboot()
{
xTaskCreatePinnedToCore(reboot_task, "reboot", 4096, NULL, 3, NULL, 0);
}
static int wt_system_init(void)
{
return 0;
}
static const global_module_t module = {
.init = wt_system_init,
.module_id = SYSTEM_MODULE_ID
};
GLOBAL_MODULE_REGISTER(WT_SYSTEM, &module);

View File

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef WT_SYSTEM_H_GUARD
#define WT_SYSTEM_H_GUARD
#include "global_module.h"
typedef struct wt_fm_info_t {
char fm_ver[32];
char upd_date[11];
} wt_fm_info_t;
void wt_system_get_fm_info(wt_fm_info_t *fm_info);
/**
* Trigger delayed reboot in 2 seconds
*/
void wt_system_reboot();
#endif //WT_SYSTEM_H_GUARD

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef WT_SYSTEM_API_H_GUARD
#define WT_SYSTEM_API_H_GUARD
#define SYSTEM_MODULE_ID 0
typedef enum wt_system_cmd_t {
WT_SYS_GET_FM_INFO = 1,
WT_SYS_REBOOT = 2,
} wt_system_cmd_t;
#endif //WT_SYSTEM_API_H_GUARD

View File

@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "wt_system_api.h"
#include "wt_system.h"
#include "api_json_module.h"
#include "wt_system_json_utils.h"
static int sys_api_json_get_fm_info(api_json_req_t *req)
{
wt_fm_info_t info;
wt_system_get_fm_info(&info);
req->out = wt_sys_json_ser_fm_info(&info);
return API_JSON_OK;
}
static int on_json_req(uint16_t cmd, api_json_req_t *req, api_json_module_async_t *async)
{
wt_system_cmd_t ota_cmd = cmd;
switch (ota_cmd) {
default:
break;
case WT_SYS_GET_FM_INFO:
return sys_api_json_get_fm_info(req);
case WT_SYS_REBOOT:
wt_system_reboot();
return API_JSON_OK;
}
return API_JSON_UNSUPPORTED_CMD;
}
/* ****
* register module
* */
static int wt_sys_json_init(api_json_module_cfg_t *cfg)
{
cfg->on_req = on_json_req;
cfg->module_id = SYSTEM_MODULE_ID;
return 0;
}
API_JSON_MODULE_REGISTER(wt_sys_json_init)

View File

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "wt_system_json_utils.h"
static void wt_sys_json_add_header(cJSON *root, wt_system_cmd_t cmd)
{
cJSON_AddNumberToObject(root, "cmd", cmd);
cJSON_AddNumberToObject(root, "module", SYSTEM_MODULE_ID);
}
cJSON *wt_sys_json_ser_fm_info(wt_fm_info_t *info)
{
cJSON *root = cJSON_CreateObject();
wt_sys_json_add_header(root, WT_SYS_GET_FM_INFO);
cJSON_AddStringToObject(root, "fm_ver", info->fm_ver);
cJSON_AddStringToObject(root, "upd_date", info->upd_date);
return root;
}

View File

@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2024 kerms <kerms@niazo.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef WT_SYSTEM_JSON_UTILS_H_GUARD
#define WT_SYSTEM_JSON_UTILS_H_GUARD
#include "wt_system_api.h"
#include "wt_system.h"
#include <cJSON.h>
cJSON *wt_sys_json_ser_fm_info(wt_fm_info_t *info);
#endif //WT_SYSTEM_JSON_UTILS_H_GUARD

View File

@ -45,7 +45,8 @@ CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y
CONFIG_BOOTLOADER_WDT_ENABLE=y CONFIG_BOOTLOADER_WDT_ENABLE=y
# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set # CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
CONFIG_BOOTLOADER_WDT_TIME_MS=9000 CONFIG_BOOTLOADER_WDT_TIME_MS=9000
# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
# CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK is not set
# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set # CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set # CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set
# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set # CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set
@ -319,11 +320,7 @@ CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
# #
# Ethernet # Ethernet
# #
CONFIG_ETH_ENABLED=y # CONFIG_ETH_USE_SPI_ETHERNET is not set
CONFIG_ETH_USE_SPI_ETHERNET=y
# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
# CONFIG_ETH_SPI_ETHERNET_W5500 is not set
# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set
# CONFIG_ETH_USE_OPENETH is not set # CONFIG_ETH_USE_OPENETH is not set
# CONFIG_ETH_TRANSMIT_MUTEX is not set # CONFIG_ETH_TRANSMIT_MUTEX is not set
# end of Ethernet # end of Ethernet
@ -608,7 +605,7 @@ CONFIG_ESP_WIFI_NVS_ENABLED=y
CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752 CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752
CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32 CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32
CONFIG_ESP_WIFI_IRAM_OPT=y CONFIG_ESP_WIFI_IRAM_OPT=y
# CONFIG_ESP_WIFI_EXTRA_IRAM_OPT is not set CONFIG_ESP_WIFI_EXTRA_IRAM_OPT=y
CONFIG_ESP_WIFI_RX_IRAM_OPT=y CONFIG_ESP_WIFI_RX_IRAM_OPT=y
CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y
# CONFIG_ESP_WIFI_FTM_ENABLE is not set # CONFIG_ESP_WIFI_FTM_ENABLE is not set