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/
|
.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
|
|
41
README.md
41
README.md
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
* 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;
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
|
11
main/main.c
11
main/main.c
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,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
|
||||||
)
|
)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
* */
|
* */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
@ -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(); \
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
/* 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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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_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
|
||||||
|
|
Loading…
Reference in New Issue