Compare commits
10 Commits
3a5968f0fa
...
9b031581d6
Author | SHA1 | Date |
---|---|---|
|
9b031581d6 | |
|
5bac7ae67b | |
|
fb32c9bdff | |
|
0d8d7a014f | |
|
2426e56191 | |
|
a48936a90a | |
|
3386a56024 | |
|
b5a4b38c8d | |
|
209f62866b | |
|
8fba1208f3 |
|
@ -7,6 +7,5 @@ sdkconfig
|
|||
.idea/
|
||||
dependencies.lock
|
||||
package-lock.json
|
||||
**/priv_note.md
|
||||
_priv_tools/
|
||||
project_components/wifi_manager/wifi_configuration.h
|
||||
managed_components/
|
||||
/version.txt
|
53
README.md
53
README.md
|
@ -65,16 +65,16 @@ There is built-in ipv4 only mDNS server. You can access the device using `dap.lo
|
|||
--------------
|
||||
|
||||
|
||||
| JTAG | |
|
||||
|--------------------|---------|
|
||||
| TCK | GPIO6 |
|
||||
| TMS | GPIO7 |
|
||||
| TDI | GPIO9 |
|
||||
| TDO | GPIO8 |
|
||||
| nTRST \(optional\) | GPIO4 |
|
||||
| nRESET | GPIO5 |
|
||||
| TVCC | 3V3 |
|
||||
| GND | GND |
|
||||
| JTAG | |
|
||||
|--------------------|--------|
|
||||
| TCK | GPIO6 |
|
||||
| TMS | GPIO7 |
|
||||
| TDI | GPIO5 |
|
||||
| TDO | GPIO3 |
|
||||
| nTRST \(optional\) | GPIO4 |
|
||||
| nRESET | GPIO10 |
|
||||
| TVCC | 3V3 |
|
||||
| GND | GND |
|
||||
|
||||
|
||||
</details>
|
||||
|
@ -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.
|
||||
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
|
||||
|
|
|
@ -370,10 +370,10 @@ __STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString (char *str) {
|
|||
#define PIN_SWDIO _ // SPI MISO
|
||||
#define PIN_SWDIO_MOSI 7 // SPI MOSI
|
||||
#define PIN_SWCLK 6
|
||||
#define PIN_TDO 8 // device TDO -> Host Data Input
|
||||
#define PIN_TDI 9
|
||||
#define PIN_TDO 3 // device TDO -> Host Data Input
|
||||
#define PIN_TDI 5
|
||||
#define PIN_nTRST 4 // optional
|
||||
#define PIN_nRESET 5
|
||||
#define PIN_nRESET 10
|
||||
|
||||
#define PIN_LED_CONNECTED _ // won't be used
|
||||
#define PIN_LED_RUNNING _ // won't be used
|
||||
|
|
|
@ -236,7 +236,8 @@ static uint32_t DAP_Connect(const uint8_t *request, uint8_t *response) {
|
|||
#if (DAP_SWD != 0)
|
||||
case DAP_PORT_SWD:
|
||||
DAP_Data.debug_port = DAP_PORT_SWD;
|
||||
PORT_SWD_SETUP();
|
||||
if (SWD_TransferSpeed != kTransfer_SPI)
|
||||
PORT_SWD_SETUP();
|
||||
break;
|
||||
#endif
|
||||
#if (DAP_JTAG != 0)
|
||||
|
@ -273,6 +274,17 @@ static uint32_t DAP_Disconnect(uint8_t *response) {
|
|||
// return: number of bytes in 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+0) = DAP_OK;
|
||||
return (2U);
|
||||
|
|
|
@ -6,14 +6,16 @@
|
|||
* 2021-2-11 Support SWD sequence
|
||||
* 2021-3-10 Support 3-wire SPI
|
||||
* 2022-9-15 Support ESP32C3
|
||||
* @version 0.4
|
||||
* @date 2022-9-15
|
||||
* 2024-6-9 Fix DAP_SPI_WriteBits issue
|
||||
* @version 0.5
|
||||
* @date 2024-6-9
|
||||
*
|
||||
* @copyright MIT License
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.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)
|
||||
{
|
||||
uint32_t data[16];
|
||||
int nbytes, i;
|
||||
|
||||
DAP_SPI.user.usr_command = 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_miso = 0;
|
||||
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++)
|
||||
{
|
||||
pData[i] = buf[i];
|
||||
}
|
||||
// last byte use mask:
|
||||
pData[i-1] = pData[i-1] & ((2U >> (count % 8)) - 1U);
|
||||
nbytes = div_round_up(count, 8);
|
||||
memcpy(data, buf, nbytes);
|
||||
|
||||
DAP_SPI.data_buf[0] = data_buf[0];
|
||||
DAP_SPI.data_buf[1] = data_buf[1];
|
||||
}
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
DAP_SPI.data_buf[i] = data[i];
|
||||
}
|
||||
|
||||
START_AND_WAIT_SPI_TRANSMISSION_DONE();
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
file(GLOB SOURCES
|
||||
*.c
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES utils wt_common
|
||||
)
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -4,17 +4,19 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "static_buffer.h"
|
||||
#include "memory_pool.h"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
#define BUFFER_NR 4
|
||||
#define BUFFER_NR 8
|
||||
#define BUFFER_SZ 2048
|
||||
|
||||
static uint8_t buf[BUFFER_NR][BUFFER_SZ];
|
||||
|
||||
/* TODO: use CAS */
|
||||
static QueueHandle_t buf_queue = NULL;
|
||||
|
||||
int static_buffer_init()
|
||||
int memory_pool_init()
|
||||
{
|
||||
if (buf_queue != NULL)
|
||||
return 0;
|
||||
|
@ -33,22 +35,25 @@ int static_buffer_init()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *static_buffer_get(uint32_t tick_wait)
|
||||
void *memory_pool_get(uint32_t tick_wait)
|
||||
{
|
||||
void *ptr = NULL;
|
||||
xQueueReceive(buf_queue, &ptr, tick_wait);
|
||||
assert(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)) {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t static_buffer_get_buf_size()
|
||||
inline uint32_t memory_pool_get_buf_size()
|
||||
{
|
||||
return BUFFER_SZ;
|
||||
}
|
|
@ -9,13 +9,13 @@
|
|||
|
||||
#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
|
|
@ -41,6 +41,25 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|||
|
||||
#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
|
||||
#define UART_BRIDGE_TX UART_NUM_0
|
||||
#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
|
||||
#define UART_BRIDGE_TX UART_NUM_1
|
||||
#define UART_BRIDGE_RX UART_NUM_1
|
||||
#define UART_BRIDGE_TX_PIN 19
|
||||
#define UART_BRIDGE_RX_PIN 18 // PIN18 has 50000ns glitch during the power-up
|
||||
#define UART_BRIDGE_TX_PIN 21
|
||||
#define UART_BRIDGE_RX_PIN 20
|
||||
#elif defined CONFIG_IDF_TARGET_ESP32S3
|
||||
#define UART_BRIDGE_TX UART_NUM_1
|
||||
#define UART_BRIDGE_RX UART_NUM_1
|
||||
|
|
11
main/main.c
11
main/main.c
|
@ -10,25 +10,28 @@
|
|||
#include "wt_storage.h"
|
||||
#include "wifi_manager.h"
|
||||
#include "web_server.h"
|
||||
#include "static_buffer.h"
|
||||
#include "memory_pool.h"
|
||||
#include "request_runner.h"
|
||||
#include "uart_tcp_bridge.h"
|
||||
#include "global_module.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void app_main()
|
||||
{
|
||||
assert(static_buffer_init() == 0);
|
||||
assert(memory_pool_init() == 0); // static buffer
|
||||
assert(request_runner_init() == 0);
|
||||
wt_storage_init();
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
wt_mdns_init();
|
||||
|
||||
wifi_manager_init();
|
||||
DAP_Setup();
|
||||
start_webserver();
|
||||
|
||||
wt_mdns_init();
|
||||
global_module_init();
|
||||
|
||||
start_webserver();
|
||||
|
||||
xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 14, NULL);
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
# 1st stage ROM ,data, ,
|
||||
# 2nd stage boot ,data,0x1000,
|
||||
# partition table,data,0xF000,4K(0x1000),
|
||||
begin ,0x40,0x00 , ,0k ,
|
||||
nvs ,data,nvs ,0x10000,16K ,
|
||||
phy_init ,data,phy , ,4K ,
|
||||
none0 ,0x40,0x00 , ,0k ,
|
||||
ota_0 ,app ,ota_0 ,0x20000,0x1B0000,
|
||||
wt_nvs ,data,nvs , ,64K ,
|
||||
begin ,0x40,0x00 , ,0k ,
|
||||
nvs ,data,nvs ,0x10000 ,16K ,
|
||||
phy_init,data,phy , ,4K ,
|
||||
none0 ,0x40,0x00 , ,0k ,
|
||||
ota_0 ,app ,ota_0,0x20000 ,0x1B0000,
|
||||
wt_nvs ,data,nvs , ,64K ,
|
||||
|
|
|
|
@ -1,9 +1,10 @@
|
|||
file(GLOB SOURCES *
|
||||
file(GLOB SOURCES *.c
|
||||
)
|
||||
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES json request_runner
|
||||
REQUIRES json request_runner wt_common
|
||||
PRIV_REQUIRES memory_pool
|
||||
)
|
||||
|
|
|
@ -8,6 +8,13 @@
|
|||
typedef struct api_json_req_t {
|
||||
cJSON *in;
|
||||
cJSON *out;
|
||||
union {
|
||||
struct {
|
||||
uint8_t big_buffer: 1;
|
||||
uint8_t reserved: 7;
|
||||
};
|
||||
uint8_t out_flag;
|
||||
};
|
||||
} api_json_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_ASYNC = 1,
|
||||
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;
|
||||
|
||||
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 {
|
||||
api_json_on_req on_req;
|
||||
api_json_on_req on_req; /* input request callback */
|
||||
uint8_t module_id;
|
||||
} api_json_module_cfg_t;
|
||||
|
||||
|
@ -40,11 +51,8 @@ void api_json_module_dump();
|
|||
|
||||
int api_json_module_add(api_json_init_func);
|
||||
|
||||
/**
|
||||
* @brief Register a module that will be init with PRI(priority) order.
|
||||
*/
|
||||
#define API_JSON_MODULE_REGISTER(PRI, INIT) \
|
||||
__attribute__((used, constructor(PRI))) void cons_ ## INIT(); \
|
||||
#define API_JSON_MODULE_REGISTER(INIT) \
|
||||
__attribute__((used, constructor)) void cons_ ## 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);
|
||||
|
|
|
@ -26,7 +26,7 @@ _Noreturn void req_long_task(void *arg)
|
|||
if (unlikely(xQueueReceive(long_run_queue, &req, portMAX_DELAY) != pdTRUE)) {
|
||||
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
|
||||
* */
|
||||
|
|
|
@ -15,7 +15,7 @@ typedef struct req_send_out_cb_t {
|
|||
} req_send_out_cb_t;
|
||||
|
||||
typedef struct req_module_cb_t {
|
||||
int (*helper_cb)(void *arg);
|
||||
int (*cb)(void *arg);
|
||||
void *arg;
|
||||
} req_module_cb_t;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ idf_component_register(
|
|||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "."
|
||||
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)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "web_uri_module.h"
|
||||
#include "api_json_router.h"
|
||||
#include "request_runner.h"
|
||||
#include "static_buffer.h"
|
||||
#include "memory_pool.h"
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <esp_log.h>
|
||||
|
@ -32,13 +32,13 @@ static esp_err_t api_post_handler(httpd_req_t *req)
|
|||
char *buf;
|
||||
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)) {
|
||||
ESP_LOGE(TAG, "req size %lu > buf_len %lu", remaining, buf_len);
|
||||
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)) {
|
||||
ESP_LOGE(TAG, "static buf busy");
|
||||
return ESP_FAIL;
|
||||
|
@ -97,7 +97,7 @@ end:
|
|||
ESP_LOGE(TAG, "resp_send err: %s", esp_err_to_name(err));
|
||||
}
|
||||
put_buf:
|
||||
static_buffer_put(post_req);
|
||||
memory_pool_put(post_req);
|
||||
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;
|
||||
|
||||
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);
|
||||
if (post_req->json.out) {
|
||||
ESP_LOGI(TAG, "json out ok");
|
||||
|
@ -136,7 +136,7 @@ void async_send_out_cb(void *arg, int module_status)
|
|||
|
||||
/* clean resources */
|
||||
httpd_req_async_handler_complete(req->req_out);
|
||||
static_buffer_put(req);
|
||||
memory_pool_put(req);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
char *buf;
|
||||
size_t buf_len;
|
||||
|
||||
/* this "hash" actually use the first 4 chars as an int32_t "hash" */
|
||||
const int *URI_HASH = (const int *)req->uri;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "web_uri_module.h"
|
||||
#include "api_json_router.h"
|
||||
#include "static_buffer.h"
|
||||
#include "memory_pool.h"
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <esp_log.h>
|
||||
|
@ -16,12 +16,27 @@
|
|||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <lwipopts.h>
|
||||
#include <lwip/netdb.h>
|
||||
|
||||
#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\"}"
|
||||
#define MSG_INTERNAL_ERROR "{\"error\":\"\"}"
|
||||
|
||||
|
||||
// Error message templates
|
||||
#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 {
|
||||
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) */
|
||||
} 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_client_info_t {
|
||||
httpd_handle_t hd;
|
||||
int fd; /* range 58 ~ 58+max_socket */
|
||||
} clients[CONFIG_LWIP_MAX_SOCKETS+1];
|
||||
int fd; /* range 64 - max_socket ~ 64 */
|
||||
} clients[CONFIG_LWIP_MAX_SOCKETS];
|
||||
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;
|
||||
|
||||
struct {
|
||||
SemaphoreHandle_t mutex;
|
||||
StaticSemaphore_t xMutexBuffer;
|
||||
} lock[CONFIG_LWIP_MAX_SOCKETS];
|
||||
} ws_ctx;
|
||||
|
||||
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_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 async_send_out_cb(void *arg, int module_status);
|
||||
static void json_to_text(ws_msg_t *msg);
|
||||
|
||||
/* 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);
|
||||
|
||||
_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)) {
|
||||
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,
|
||||
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;
|
||||
httpd_ws_frame_t *ws_pkt;
|
||||
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)) {
|
||||
httpd_ws_frame_t resp_pkt;
|
||||
resp_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||
resp_pkt.len = strlen(MSG_BUSY_ERROR);
|
||||
resp_pkt.payload = (uint8_t *)MSG_BUSY_ERROR;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
if (unlikely(err != ESP_OK)) {
|
||||
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);
|
||||
#endif
|
||||
if (unlikely(ws_pkt->len > PAYLOAD_LEN)) {
|
||||
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) {
|
||||
case HTTPD_WS_TYPE_CONTINUE:
|
||||
ESP_LOGE(TAG, "WS Continue not handled");
|
||||
goto end;
|
||||
case HTTPD_WS_TYPE_TEXT:
|
||||
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_close(req, ws_pkt, ws_msg);
|
||||
}
|
||||
return ws_on_text_data(req, ws_msg);
|
||||
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);
|
||||
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:
|
||||
/* 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;
|
||||
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;
|
||||
case HTTPD_WS_TYPE_PONG:
|
||||
err = ESP_OK;
|
||||
|
@ -136,10 +169,262 @@ static esp_err_t ws_req_handler(httpd_req_t *req)
|
|||
goto end;
|
||||
}
|
||||
end:
|
||||
static_buffer_put(ws_msg);
|
||||
memory_pool_put(ws_msg);
|
||||
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
|
||||
|
@ -155,13 +440,20 @@ static const httpd_uri_t uri_api = {
|
|||
.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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
vTaskDelete(ws_ctx.task_heartbeat);
|
||||
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)
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -11,10 +11,15 @@ typedef struct uri_module_t {
|
|||
uint8_t priority;
|
||||
} 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);
|
||||
|
||||
/**
|
||||
* @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) \
|
||||
__attribute__((used, constructor(PRI))) void cons_ ## INIT(); \
|
||||
|
|
|
@ -11,7 +11,7 @@ file(GLOB SOURCES
|
|||
idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
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)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <lwip/ip4_addr.h>
|
||||
|
||||
#define WIFI_API_MODULE_ID 1
|
||||
#define WIFI_MODULE_ID 1
|
||||
|
||||
typedef enum wifi_api_json_cmd_t {
|
||||
UNKNOWN = 0,
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include "wifi_api_json.h"
|
||||
|
||||
#include "api_json_module.h"
|
||||
#include "wifi_api.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);
|
||||
|
||||
|
||||
/* the upper caller call cb() with void *, this let us use custom function arg */
|
||||
static int async_helper_cb(void *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.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;
|
||||
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);
|
||||
case WIFI_API_JSON_AP_GET_INFO:
|
||||
return wifi_api_json_ap_get_info(req);
|
||||
break;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
cfg->on_req = on_json_req;
|
||||
cfg->module_id = WIFI_API_MODULE_ID;
|
||||
cfg->module_id = WIFI_MODULE_ID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
API_JSON_MODULE_REGISTER(0x90, wifi_api_json_init)
|
||||
|
||||
|
||||
API_JSON_MODULE_REGISTER(wifi_api_json_init)
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef WIFI_API_JSON_H_GUARD
|
||||
#define WIFI_API_JSON_H_GUARD
|
||||
|
||||
#endif //WIFI_API_JSON_H_GUARD
|
|
@ -6,7 +6,7 @@
|
|||
static void wifi_api_json_set_header(cJSON *root, uint16_t 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)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ int wifi_data_get_last_conn_cred(wifi_credential_t *ap_credential)
|
|||
nvs_handle_t handle;
|
||||
int err;
|
||||
|
||||
err = wt_nvs_open(NVS_NAMESPACE, &handle);
|
||||
err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle);
|
||||
if (err) {
|
||||
return WT_NVS_ERR;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ int wifi_save_ap_credential(wifi_credential_t *ap_credential)
|
|||
int err;
|
||||
nvs_handle_t handle;
|
||||
|
||||
err = wt_nvs_open(NVS_NAMESPACE, &handle);
|
||||
err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
file(GLOB SOURCES *.c
|
||||
)
|
||||
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "."
|
||||
)
|
|
@ -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
|
|
@ -14,6 +14,22 @@ void wt_mdns_init()
|
|||
|
||||
/* TODO: read instance description from NVS */
|
||||
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)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define WT_MDNS_CONFIG_H_GUARD
|
||||
|
||||
#define MDSN_DEFAULT_HOSTNAME "dap" // + serial number (4 char)
|
||||
#define MDSN_INSTANCE_DESC "无线STM32调试器 by 允斯工作室"
|
||||
#define MDSN_INSTANCE_DESC "ESP32 无线透传"
|
||||
|
||||
void wt_mdns_init();
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -45,7 +45,8 @@ CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y
|
|||
CONFIG_BOOTLOADER_WDT_ENABLE=y
|
||||
# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
|
||||
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_ON_POWER_ON is not set
|
||||
# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set
|
||||
|
@ -319,11 +320,7 @@ CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
|
|||
#
|
||||
# Ethernet
|
||||
#
|
||||
CONFIG_ETH_ENABLED=y
|
||||
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_SPI_ETHERNET is not set
|
||||
# CONFIG_ETH_USE_OPENETH is not set
|
||||
# CONFIG_ETH_TRANSMIT_MUTEX is not set
|
||||
# end of Ethernet
|
||||
|
@ -608,7 +605,7 @@ CONFIG_ESP_WIFI_NVS_ENABLED=y
|
|||
CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752
|
||||
CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32
|
||||
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_ENABLE_WPA3_SAE=y
|
||||
# CONFIG_ESP_WIFI_FTM_ENABLE is not set
|
||||
|
|
Loading…
Reference in New Issue