feat(tcp_server): schema in message pack and more command

This commit is contained in:
pictures23333 2025-12-16 15:54:07 +08:00
parent 080a1d81e2
commit 1428ec2d11
7 changed files with 225 additions and 84 deletions

View file

@ -2,9 +2,10 @@ file(GLOB_RECURSE MY_LIB_SOURCES
"ESP32epdx/src/*.cpp" "ESP32epdx/src/*.cpp"
"ESP32epdx/src/GUI/*.cpp" "ESP32epdx/src/GUI/*.cpp"
"pubsubclient/src/*.cpp", "pubsubclient/src/*.cpp",
"mpack/src/mpack/*.c"
) )
idf_component_register( idf_component_register(
SRCS "main.cpp" "EPD.cpp" "mesh_main.c" "mesh_netif.c" "tcphelper.c" ${MY_LIB_SOURCES} SRCS "main.cpp" "EPD.cpp" "mesh_main.c" "mesh_netif.c" "tcphelper.c" ${MY_LIB_SOURCES}
INCLUDE_DIRS "" "ESP32epdx/src" "ESP32epdx/src/GUI" INCLUDE_DIRS "" "ESP32epdx/src" "ESP32epdx/src/GUI" "mpack/src/mpack"
) )

View file

@ -1,8 +1,10 @@
#include "Arduino.h" #include "stdlib.h"
#include "Arduino.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include <mutex> #include <mutex>
#include "mpack.h"
#include "ESP32epdx.h" #include "ESP32epdx.h"
#include "EPD.h" #include "EPD.h"
#include "mesh_netif.h" #include "mesh_netif.h"
@ -16,69 +18,165 @@ SPI: SCK = 6 ; MISO = 2 ; MOSI = 7 ; SS = 16
EPD: RES = 22 ; DC = 23 ; CS = 1 ; BUSY = 0 EPD: RES = 22 ; DC = 23 ; CS = 1 ; BUSY = 0
*/ */
#define IMAGE_BUF_SIZE 5624
uint8_t *image_buf = nullptr; uint8_t *image_buf = nullptr;
extern "C" int tcp_server_callback(char *buf, size_t len) { typedef struct request_t {
if (!strncmp(buf, "ping", 4)) { // ping // command : update_image, push_image, ping
return 0; char *command;
} else if (!strncmp(buf, "image", 5) && len == 5 + 5624) { // update image
if (epd_mtx.try_lock()) // arguments for update_image
{ uint64_t index;
// work char *data;
EPD_HW_Init_Fast(); size_t data_len;
EPD_Display((unsigned char *)(buf+5)); } request_t;
EPD_DeepSleep();
//vTaskDelay(pdMS_TO_TICKS(1000));
// unlock extern "C" request_t* parse_data(char *buf, size_t len) {
epd_mtx.unlock(); // variables
char *command = NULL;
uint64_t index = 0;
char *data = NULL;
size_t data_len = 0;
return 0; // init reader
} mpack_reader_t reader;
else mpack_reader_init_data(&reader, buf, len);
{
// locked size_t count = mpack_expect_map_max(&reader, 100);
return -2; if (mpack_reader_error(&reader) != mpack_ok) {
return NULL;
} }
} else { // invalid request
return -3; // read data
} for (size_t i = 0; i < count; i++) {
char *key = mpack_expect_cstr_alloc(&reader, 100);
if (strcmp(key, "command") == 0) {
command = mpack_expect_cstr_alloc(&reader, 32);
} else if (strcmp(key, "index") == 0) {
index = mpack_expect_u64(&reader);
} else if (strcmp(key, "data") == 0) {
data = mpack_expect_bin_alloc(&reader, CONFIG_IMAGE_BUF_SLICE_SIZE, &data_len);
} else {
mpack_discard(&reader);
}
free(key);
}
// finish
mpack_done_map(&reader);
if (mpack_reader_destroy(&reader) != mpack_ok) {
return NULL;
}
// return
request_t *result = (request_t *)malloc(sizeof(request_t));
if (!result) {
return NULL;
}
memset(result, 0, sizeof(request_t));
result->command = command;
result->index = index;
result->data = data;
result->data_len = data_len;
return result;
} }
extern "C" void app_main() extern "C" int command_update_image(uint64_t index, char *buf, size_t len) {
{ if (!epd_mtx.try_lock()) {
initArduino(); return -3; // locked
}
if (
index < 0 || index >= CONFIG_IMAGE_BUF_SIZE ||
len < 0 || len > CONFIG_IMAGE_BUF_SIZE ||
(index+len) < 0 || (index+len) > CONFIG_IMAGE_BUF_SIZE
)
{
epd_mtx.unlock();
return -2;
}
// init image_buf memcpy(image_buf + index, buf, len);
image_buf = (uint8_t *)malloc(IMAGE_BUF_SIZE);
memset(image_buf, 0, IMAGE_BUF_SIZE);
//Initialize NVS epd_mtx.unlock();
esp_err_t ret = nvs_flash_init(); return 0;
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { }
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Initialize EPD extern "C" int command_push_image() {
EPD_Pin_Init(6, 2, 7, 16, if (epd_mtx.try_lock()) {
22, 23, 1, 0); EPD_HW_Init_Fast();
EPD_Display((unsigned char *)(image_buf));
EPD_DeepSleep();
mesh_main(); epd_mtx.unlock();
return 0;
} else {
return -3;
}
}
// tcp server extern "C" int tcp_server_callback(char *buf, size_t len) {
start_tcp_server(); request_t *req = parse_data(buf, len);
if (!req) { // error -> invalid data
return -2;
}
// Arduino-like setup() // execute command
if (strcmp(req->command, "ping") == 0)
{
return 0;
}
else if (strcmp(req->command, "update_image") == 0)
{
return command_update_image(req->index, req->data, req->data_len);
}
else if (strcmp(req->command, "push_image") == 0)
{
return command_push_image();
}
else
{
return -2;
}
}
// Arduino-like loop() extern "C" void app_main() {
while (true) initArduino();
{
vTaskDelay(500);
}
// WARNING: if program reaches end of function app_main() the MCU will restart. // init image_buf
image_buf = (uint8_t *)malloc(CONFIG_IMAGE_BUF_SIZE);
if (!image_buf) {
return;
}
memset(image_buf, 0, CONFIG_IMAGE_BUF_SIZE);
// initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Initialize EPD
EPD_Pin_Init(6, 2, 7, 16,
22, 23, 1, 0);
mesh_main();
// tcp server
start_tcp_server();
// Arduino-like setup()
// Arduino-like loop()
while (true)
{
vTaskDelay(500);
}
// WARNING: if program reaches end of function app_main() the MCU will restart.
} }

View file

@ -22,9 +22,12 @@ static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x76 };
#define CONFIG_MESH_AP_CONNECTIONS 6 // number of nodes #define CONFIG_MESH_AP_CONNECTIONS 6 // number of nodes
#define CONFIG_MESH_NON_MESH_AP_CONNECTIONS 0 // number of non-node devices #define CONFIG_MESH_NON_MESH_AP_CONNECTIONS 0 // number of non-node devices
#define CONFIG_TCP_DEBUG 0
#define CONFIG_TCP_SERVER_BIND_ADDRESS "0.0.0.0" #define CONFIG_TCP_SERVER_BIND_ADDRESS "0.0.0.0"
#define CONFIG_TCP_SERVER_BIND_PORT "8888" #define CONFIG_TCP_SERVER_BIND_PORT "8888"
#define CONFIG_TCP_SERVER_RXBUFFER_SIZE 8192 #define CONFIG_TCP_SERVER_RXBUFFER_SIZE 4096 // tcp raw data max size
#define CONFIG_IMAGE_BUF_SLICE_SIZE 2048 // map["data"] max size
#define CONFIG_IMAGE_BUF_SIZE 5624
/******************************************************* /*******************************************************
* Function Declarations * Function Declarations

View file

@ -320,9 +320,12 @@ void mesh_main(void)
cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID); cfg.router.ssid_len = strlen(CONFIG_MESH_ROUTER_SSID);
memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len); memcpy((uint8_t *) &cfg.router.ssid, CONFIG_MESH_ROUTER_SSID, cfg.router.ssid_len);
#if CONFIG_TCP_DEBUG
memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD, memcpy((uint8_t *) &cfg.router.password, CONFIG_MESH_ROUTER_PASSWD,
strlen(CONFIG_MESH_ROUTER_PASSWD)); strlen(CONFIG_MESH_ROUTER_PASSWD));
//memset((uint8_t *) &cfg.router.password, 0, 64); #else
memset((uint8_t *) &cfg.router.password, 0, 64);
#endif
/* mesh softAP */ /* mesh softAP */
ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(CONFIG_MESH_AP_AUTHMODE)); ESP_ERROR_CHECK(esp_mesh_set_ap_authmode(CONFIG_MESH_AP_AUTHMODE));

1
main/mpack Submodule

@ -0,0 +1 @@
Subproject commit a94ff1129d41a470ad9425ce6f730b3d8e99983f

View file

@ -250,14 +250,11 @@ static void tcp_server_task(void *pvParameters)
case 0: case 0:
strcpy(tx_buffer, "ok\n"); strcpy(tx_buffer, "ok\n");
break; break;
case -1:
strcpy(tx_buffer, "invalid data\n");
break;
case -2: case -2:
strcpy(tx_buffer, "locked\n"); strcpy(tx_buffer, "invalid request\n");
break; break;
case -3: case -3:
strcpy(tx_buffer, "invalid request\n"); strcpy(tx_buffer, "locked\n");
break; break;
default: default:
strcpy(tx_buffer, "unknown error\n"); strcpy(tx_buffer, "unknown error\n");

View file

@ -1,38 +1,76 @@
from typing import Dict, Any
import socket import socket
import msgpack
import tcp_client_image import tcp_client_image
SERVER_ADDRESS = ('172.16.0.249', 8888) SERVER_ADDRESS = ('172.16.0.249', 8888)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) def send_request(data:Dict[str, Any]):
client_socket.connect(SERVER_ADDRESS) client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(SERVER_ADDRESS)
try:
message:bytes = msgpack.packb(data)
try:
while True:
message = ""
choice = int(input("image > "))
if choice == 1:
message = b"image" + bytes(tcp_client_image.image1)
elif choice == 2:
message = b"image" + bytes(tcp_client_image.image2)
elif choice == 3:
message = b"ping"
else:
message = b"something_invalid"
# 4. 傳送資料 (需要編碼成 bytes)
client_socket.sendall(message) client_socket.sendall(message)
# 5. 接收伺服器的回應 rx = client_socket.recv(1024)
# 接收最多 1024 bytes
data = client_socket.recv(1024)
if data: if data:
print(f"收到伺服器訊息: {data.decode('utf-8')}") print(f"Received message: {rx.decode('utf-8').strip()}")
else:
print("Connection closed")
return
except ConnectionResetError:
print("Connection reset")
finally:
client_socket.close()
print("Connection closed")
def image():
image = b""
try:
choice = int(input("image > "))
if choice == 1:
image = tcp_client_image.image1
elif choice == 2:
image = tcp_client_image.image2
else:
raise ValueError
except:
print("invalid choice")
return
chunk_size = 2048
for i in range(0, len(image), chunk_size):
data = {
"command": "update_image",
"index": i,
"data": bytes(image[i:i+chunk_size])
}
send_request(data)
send_request({"command":"push_image"})
def main():
while True:
print("Command:")
print("(1) update + push image")
print("(2) ping")
print("(3) invalid request")
print("(4) exit")
choice:int = int(input("> "))
data = {}
if choice == 1:
image()
elif choice == 2:
send_request({"command":"ping"})
elif choice == 3:
send_request({"command":"invalid_command"})
else: else:
print("伺服器已關閉連線。")
break break
except ConnectionResetError:
print("連線被伺服器重置。") if __name__ == "__main__":
finally: main()
client_socket.close()
print("客戶端連線已關閉。")