This commit is contained in:
pictures2333 2025-12-31 14:51:35 +08:00
parent 354dd9c38d
commit 0f80116be2
13 changed files with 571 additions and 430 deletions

View file

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

View file

@ -1,5 +1,6 @@
#include "stdlib.h" #include "stdlib.h"
#include "esp_log.h"
#include "Arduino.h" #include "Arduino.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include <mutex> #include <mutex>
@ -8,11 +9,9 @@
#include "ESP32epdx.h" #include "ESP32epdx.h"
#include "EPD.h" #include "EPD.h"
#include "mesh_netif.h" #include "mesh_netif.h"
#include "esp_mesh.h" #include "tcphelper.h"
#include "main.h" #include "main.h"
#include "sha256.h"
std::mutex epd_mtx; std::mutex epd_mtx;
/* /*
@ -22,25 +21,7 @@ EPD: RES = 22 ; DC = 23 ; CS = 1 ; BUSY = 0
uint8_t *image_buf = nullptr; uint8_t *image_buf = nullptr;
#if CONFIG_MESH_ROOT == 0
extern "C" void req_release(request_t *req) {
free(req->command);
req->command = 0;
free(req->data);
req->data = 0;
free(req);
return;
}
extern "C" int command_update_image(uint64_t index, char *buf, size_t len) { extern "C" int command_update_image(uint64_t index, char *buf, size_t len) {
// check
if (!buf) {
return -2;
}
// main
if (!epd_mtx.try_lock()) { if (!epd_mtx.try_lock()) {
return -3; // locked return -3; // locked
} }
@ -62,11 +43,6 @@ extern "C" int command_update_image(uint64_t index, char *buf, size_t len) {
} }
extern "C" int command_push_image() { extern "C" int command_push_image() {
#if DEBUG == 1
printf("sha256 of image_buf: ");
show_sha256((char *)image_buf, CONFIG_IMAGE_BUF_SIZE);
#endif
if (epd_mtx.try_lock()) { if (epd_mtx.try_lock()) {
EPD_HW_Init_Fast(); EPD_HW_Init_Fast();
EPD_Display((unsigned char *)(image_buf)); EPD_Display((unsigned char *)(image_buf));
@ -79,149 +55,47 @@ extern "C" int command_push_image() {
} }
} }
extern "C" int mesh_client_callback(char *buf, size_t len) { extern "C" int tcp_client_callback(char *buf, size_t len) {
for (size_t i = 0; i < len; i++) {
printf("%02x ", buf[i]);
}
printf("\n");
request_t *req = client_parse_data(buf, len); request_t *req = client_parse_data(buf, len);
if (!req) { // error -> invalid data if (!req) { // error -> invalid data
return -2; return -2;
} }
int ret = 0;
// execute command // execute command
if (strcmp(req->command, "ping") == 0) if (strcmp(req->command, "ping") == 0)
{ {
goto mesh_client_callback_ret; return 0;
} }
else if (strcmp(req->command, "update_image") == 0) else if (strcmp(req->command, "update_image") == 0)
{ {
ret = command_update_image(req->index, req->data, req->data_len); return command_update_image(req->index, req->data, req->data_len);
goto mesh_client_callback_ret;
} }
else if (strcmp(req->command, "push_image") == 0) else if (strcmp(req->command, "push_image") == 0)
{ {
ret = command_push_image(); return command_push_image();
goto mesh_client_callback_ret;
} }
else else
{ {
ret = -2; return -2;
goto mesh_client_callback_ret;
} }
mesh_client_callback_ret:
req_release(req);
return ret;
} }
#else // root -> 送測試資料
#define PAYLOAD_SIZE 1024
#include "IMAGE.h"
void mesh_server_send_test_data() {
/*
mpack_writer_t *writer = (mpack_writer_t *)malloc(sizeof(mpack_writer_t));
char *payload = (char *)malloc(PAYLOAD_SIZE);
if (!writer || !payload) {
printf("failed to allocate memory\n");
return;
}
const unsigned char *image_start = &gImage_1[0];
const unsigned char *image_end = image_start + sizeof(gImage_1);
printf("sha256 of gImage_1: ");
show_sha256((char *)image_start, sizeof(gImage_1));
uint32_t counter = 0;
for (const unsigned char *image = image_start; image < image_end; image += 950) {
vTaskDelay(2000 / portTICK_PERIOD_MS);
memset(writer, 0, sizeof(mpack_writer_t));
memset(payload, 0, PAYLOAD_SIZE);
mpack_writer_init(writer, payload, PAYLOAD_SIZE);
mpack_start_map(writer, 3);
mpack_write_cstr(writer,"command");
mpack_write_cstr(writer,"update_image");
mpack_write_cstr(writer,"index");
printf("index -> %d\n", image - image_start);
mpack_write_u64(writer, image - image_start);
//mpack_write_cstr(writer,"data");
//size_t count = 950;
//if (image + 950 > image_end)
// count = image_end - image;
//mpack_start_bin(writer, count);
//mpack_write_bin(writer, (const char *)image, count);
//mpack_finish_bin(writer);
char testdata[64];
memset(testdata, 0, sizeof(testdata));
snprintf(testdata, sizeof(testdata), "Hello, World! -> %lu", counter++);
mpack_start_bin(writer, sizeof(testdata));
mpack_write_bin(writer, testdata, sizeof(testdata));
mpack_finish_bin(writer);
mpack_finish_map(writer);
if (mpack_writer_destroy(writer) != mpack_ok) {
printf("error!\n");
continue;
}
//fwrite("payload: ", 1, 9, stdout);
//fwrite(payload, 1, PAYLOAD_SIZE, stdout);
//fwrite("\n", 1, 1, stdout);
esp_err_t err = esp_mesh_boardcast_to_nodes((uint8_t *)payload, PAYLOAD_SIZE);
printf("mesh_server_send_test_data result -> %d\n", err);
}
vTaskDelay(1500 / portTICK_PERIOD_MS);
memset(writer, 0, sizeof(mpack_writer_t));
memset(payload, 0, PAYLOAD_SIZE);
mpack_writer_init(writer, payload, PAYLOAD_SIZE);
mpack_start_map(writer, 1);
mpack_write_cstr(writer,"command");
mpack_write_cstr(writer,"push_image");
mpack_finish_map(writer);
if (mpack_writer_destroy(writer) != mpack_ok) {
printf("error!\n");
} else {
esp_err_t err = esp_mesh_boardcast_to_nodes((uint8_t *)payload, PAYLOAD_SIZE);
printf("mesh_server_send_test_data result -> %d\n", err);
}
free(writer);
free(payload);
*/
char payload[64] = {0};
for (int i = 0; i < 6; i++) {
memset(payload, 0, sizeof(payload));
snprintf(payload, sizeof(payload), "Hello, World! -> %d", i);
esp_err_t err = esp_mesh_boardcast_to_nodes((uint8_t *)payload, sizeof(payload));
printf("[i=%d] result -> %d\n", i, err);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
return;
}
#endif
extern "C" void app_main() { extern "C" void app_main() {
initArduino(); initArduino();
#if CONFIG_TCP_ROOT == 0
// init image_buf // init image_buf
image_buf = (uint8_t *)malloc(CONFIG_IMAGE_BUF_SIZE); image_buf = (uint8_t *)malloc(CONFIG_IMAGE_BUF_SIZE);
if (!image_buf) { if (!image_buf) {
return; return;
} }
memset(image_buf, 0, CONFIG_IMAGE_BUF_SIZE); memset(image_buf, 0, CONFIG_IMAGE_BUF_SIZE);
#endif
// initialize NVS // initialize NVS
esp_err_t ret = nvs_flash_init(); esp_err_t ret = nvs_flash_init();
@ -234,26 +108,18 @@ extern "C" void app_main() {
// Initialize EPD // Initialize EPD
EPD_Pin_Init(6, 2, 7, 16, EPD_Pin_Init(6, 2, 7, 16,
22, 23, 1, 0); 22, 23, 1, 0);
// start mesh network
mesh_main(); mesh_main();
xTaskCreate(esp_mesh_p2p_rx_main, "MPRX", 3072, NULL, 5, NULL);
// tcp client
tcp_initialize();
// Arduino-like setup() // Arduino-like setup()
// Arduino-like loop() // Arduino-like loop()
int32_t counter = 6;
while (true) while (true)
{ {
#if CONFIG_MESH_ROOT == 1 vTaskDelay(500);
printf("counter -> %ld\n", counter);
if (counter == 0)
mesh_server_send_test_data();
if (counter >= 0)
counter--;
#endif
printf("Am I root? -> %d\n", esp_mesh_is_root());
vTaskDelay(5 * 1000 / portTICK_PERIOD_MS);
} }
// WARNING: if program reaches end of function app_main() the MCU will restart. // WARNING: if program reaches end of function app_main() the MCU will restart.

View file

@ -1,4 +1,6 @@
#pragma once #ifndef MAIN_H
#define MAIN_H
#include <stdint.h> #include <stdint.h>
/******************************************************* /*******************************************************
@ -13,16 +15,19 @@
static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x76 }; static const uint8_t MESH_ID[6] = { 0x77, 0x77, 0x77, 0x77, 0x77, 0x76 };
#define CONFIG_MESH_ROUTER_SSID "FBK_the_cutest_fox" #define CONFIG_MESH_ROUTER_SSID "FBK_the_cutest_fox"
#define CONFIG_MESH_ROUTER_PASSWD "zsfv3210" #define CONFIG_MESH_ROUTER_PASSWD "zsfv3210"
//#define CONFIG_MESH_ROUTER_SSID "FastCyberRoom" //#define CONFIG_MESH_ROUTER_SSID "testesp"
//#define CONFIG_MESH_ROUTER_PASSWD "dyes1107@" //#define CONFIG_MESH_ROUTER_PASSWD "RABCRABC"
#define CONFIG_MESH_AP_AUTHMODE WIFI_AUTH_WPA2_PSK #define CONFIG_MESH_AP_AUTHMODE WIFI_AUTH_WPA2_PSK
#define CONFIG_MESH_AP_PASSWD "RASRASRAS" #define CONFIG_MESH_AP_PASSWD "RASRASRAS"
#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 DEBUG 1 #define CONFIG_TCP_ROOT 0
#define CONFIG_MESH_ROOT 1 //#define CONFIG_TCP_SERVER_IP "172.16.0.1"
#define CONFIG_IMAGE_BUF_SLICE_SIZE 950 // map["data"] max size #define CONFIG_TCP_SERVER_IP "10.189.34.172"
#define CONFIG_TCP_SERVER_PORT "3030"
#define CONFIG_TCP_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 #define CONFIG_IMAGE_BUF_SIZE 5624
/******************************************************* /*******************************************************
@ -43,10 +48,16 @@ typedef struct request_t {
size_t data_len; size_t data_len;
} request_t; } request_t;
request_t *client_parse_data(char *buf, size_t len); #if CONFIG_TCP_ROOT == 1
int tcp_server_callback(const char *TAG, int sock);
#else
int tcp_client_callback(char *buf, size_t len);
#endif
int mesh_client_callback(char *buf, size_t len); request_t *client_parse_data(char *buf, size_t len);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif
#endif #endif

View file

@ -19,7 +19,7 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "main.h" #include "main.h"
//#include "tcphelper.h" #include "tcphelper.h"
/******************************************************* /*******************************************************
* Macros * Macros
@ -35,7 +35,7 @@
/******************************************************* /*******************************************************
* Constants * Constants
*******************************************************/ *******************************************************/
const char *MESH_TAG = "mesh_main"; static const char *MESH_TAG = "mesh_main";
/******************************************************* /*******************************************************
* Variable Definitions * Variable Definitions
@ -306,6 +306,13 @@ void ip_event_handler(void *arg, esp_event_base_t event_base,
ESP_ERROR_CHECK(esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns)); ESP_ERROR_CHECK(esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns));
mesh_netif_start_root_ap(esp_mesh_is_root(), dns.ip.u_addr.ip4.addr); mesh_netif_start_root_ap(esp_mesh_is_root(), dns.ip.u_addr.ip4.addr);
//#endif //#endif
// tcp client
#if CONFIG_TCP_ROOT == 1
start_tcp_server();
#else
start_tcp_client();
#endif
} }
@ -349,12 +356,8 @@ void mesh_main(void)
cfg.channel = CONFIG_MESH_CHANNEL; cfg.channel = CONFIG_MESH_CHANNEL;
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_MESH_ROOT == 0
memset((uint8_t *)&cfg.router.password, 0, 64);
#else
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));
#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));

View file

@ -1,186 +0,0 @@
/* Mesh Internal Communication Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <inttypes.h>
#include "esp_wifi.h"
#include "esp_mac.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mesh.h"
#include "esp_mesh_internal.h"
#include "nvs_flash.h"
#include "mesh_netif.h"
#include "main.h"
/*******************************************************
* Macros
*******************************************************/
/*******************************************************
* Constants
*******************************************************/
#define RX_SIZE (1500)
#define TX_SIZE (1460)
/*******************************************************
* Variable Definitions
*******************************************************/
static uint8_t tx_buf[TX_SIZE] = { 0, };
static uint8_t rx_buf[RX_SIZE] = { 0, };
static bool is_running = true;
static bool is_mesh_connected = false;
static mesh_addr_t mesh_parent_addr;
static int mesh_layer = -1;
static esp_netif_t *netif_sta = NULL;
//mesh_light_ctl_t light_on = {
// .cmd = MESH_CONTROL_CMD,
// .on = 1,
// .token_id = MESH_TOKEN_ID,
// .token_value = MESH_TOKEN_VALUE,
//};
//
//mesh_light_ctl_t light_off = {
// .cmd = MESH_CONTROL_CMD,
// .on = 0,
// .token_id = MESH_TOKEN_ID,
// .token_value = MESH_TOKEN_VALUE,
//};
/*******************************************************
* Function Declarations
*******************************************************/
/*******************************************************
* Function Definitions
*******************************************************/
#if CONFIG_MESH_ROOT == 1
esp_err_t esp_mesh_boardcast_to_nodes(uint8_t *payload, uint16_t payload_len)
{
int i;
esp_err_t err;
mesh_addr_t route_table[CONFIG_MESH_ROUTE_TABLE_SIZE];
int route_table_size = 0;
mesh_data_t data;
data.data = payload;
data.size = payload_len;
data.proto = MESH_PROTO_BIN;
data.tos = MESH_TOS_P2P;
esp_mesh_get_routing_table((mesh_addr_t *) &route_table,
CONFIG_MESH_ROUTE_TABLE_SIZE * 6, &route_table_size);
printf("route table size -> %d\n", route_table_size);
for (i = 0; i < route_table_size; i++) {
err = esp_mesh_send(&route_table[i], &data, MESH_DATA_P2P, NULL, 0);
if (err) {
ESP_LOGE(MESH_TAG,
"[ROOT-2-UNICAST][L:%d]parent:"MACSTR" to "MACSTR", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]",
mesh_layer, MAC2STR(mesh_parent_addr.addr),
MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(),
err, data.proto, data.tos);
return err;
}
}
return ESP_OK;
}
#else
esp_err_t esp_mesh_send_to_root(uint8_t *payload, uint16_t payload_len)
{
esp_err_t err;
mesh_data_t data;
data.data = payload;
data.size = payload_len;
data.proto = MESH_PROTO_BIN;
data.tos = MESH_TOS_P2P;
err = esp_mesh_send(NULL, &data, MESH_DATA_P2P, NULL, 0);
if (err) {
//ESP_LOGE(MESH_TAG,
// "[ROOT-2-UNICAST][L:%d]parent:"MACSTR" to "MACSTR", heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]",
// mesh_layer, MAC2STR(mesh_parent_addr.addr),
// MAC2STR(route_table[i].addr), esp_get_minimum_free_heap_size(),
// err, data.proto, data.tos);
ESP_LOGE(MESH_TAG, "Error while sending message to root, heap:%" PRId32 "[err:0x%x, proto:%d, tos:%d]",
esp_get_minimum_free_heap_size(), err,
data.proto, data.tos);
return err;
}
return ESP_OK;
}
#endif
void esp_mesh_p2p_rx_main(void *arg)
{
esp_err_t err;
mesh_addr_t from;
mesh_data_t data;
int flag = 0;
data.data = rx_buf;
data.size = RX_SIZE;
is_running = true;
while (is_running) {
data.size = RX_SIZE;
memset(rx_buf, 0, sizeof(rx_buf));
err = esp_mesh_recv(&from, &data, portMAX_DELAY, &flag, NULL, 0);
if (err != ESP_OK || !data.size) {
ESP_LOGE(MESH_TAG, "err:0x%x, size:%d", err, data.size);
continue;
}
//if (data.size > sizeof(packet_t)) {
// ESP_LOGE(MESH_TAG, "err:data.size > sizeof(packet_t), size:%d", data.size);
// continue;
//}
// extract data and process
//packet_t *packet = calloc(1, sizeof(packet_t));
//if (!packet) {
// ESP_LOGE(MESH_TAG, "failed to allocate memory");
// continue;
//}
//memcpy(packet, data.data, data.size);
#if CONFIG_MESH_ROOT == 1
printf("[root] received:%s\n", data.data);
#else
printf("recvived aaa\n");
printf("[root] received:%s\n", data.data);
char result_str[128] = {0};
int result = mesh_client_callback((char *)data.data, data.size);
switch (result) {
case 0:
strcpy(result_str, "ok\n");
break;
case -2:
strcpy(result_str, "invalid request\n");
break;
case -3:
strcpy(result_str, "locked\n");
break;
default:
strcpy(result_str, "unknown error\n");
break;
}
printf("returned -> %s\n", result_str);
esp_mesh_send_to_root((uint8_t *)result_str, strlen(result_str)+1);
#endif
//free(packet);
//packet = NULL;
// log
ESP_LOGW(MESH_TAG,
"[#RX][L:%d] parent:"MACSTR", receive from "MACSTR", size:%d, heap:%" PRId32 ", flag:%d[err:0x%x, proto:%d, tos:%d]",
mesh_layer,
MAC2STR(mesh_parent_addr.addr), MAC2STR(from.addr),
data.size, esp_get_minimum_free_heap_size(), flag, err, data.proto,
data.tos);
}
vTaskDelete(NULL);
}

View file

@ -13,10 +13,6 @@
#include "esp_mesh.h" #include "esp_mesh.h"
#include "esp_mac.h" #include "esp_mac.h"
#include "main.h"
extern const char *MESH_TAG;
/******************************************************* /*******************************************************
* Macros * Macros
*******************************************************/ *******************************************************/
@ -94,20 +90,6 @@ uint8_t* mesh_netif_get_station_mac(void);
// mesh main function // mesh main function
void mesh_main(void); void mesh_main(void);
// mesh_msg.c
void esp_mesh_p2p_rx_main(void *arg);
#if CONFIG_MESH_ROOT == 1
esp_err_t esp_mesh_boardcast_to_nodes(uint8_t *payload, uint16_t payload_len);
#else
#endif
typedef struct packet_t {
uint32_t packet_id;
uint8_t data[1024];
} packet_t;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -1,3 +1 @@
must enable "use external log wrapper" must enable "use external log wrapper"
我是寫 client 的,所以我這裡的「模擬 master」採用直接 unicast 的方式

View file

@ -1,24 +1,27 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include "mpack/src/mpack/mpack.h" #include "mpack.h"
#include "main.h" #include "main.h"
#if CONFIG_TCP_ROOT == 0
request_t *client_parse_data(char *buf, size_t len) { request_t *client_parse_data(char *buf, size_t len) {
mpack_reader_t reader; mpack_reader_t reader;
// initialize // initialize
mpack_reader_init_data(&reader, buf, len); mpack_reader_init_data(&reader, buf, len);
if (mpack_reader_error(&reader) != mpack_ok) { if (mpack_reader_error(&reader) != mpack_ok) {
goto parse_data_finish; goto client_parse_data_finish;
} }
size_t count = mpack_expect_map_max(&reader, 100); size_t count = mpack_expect_map_max(&reader, 100);
if (mpack_reader_error(&reader) != mpack_ok) { if (mpack_reader_error(&reader) != mpack_ok) {
goto parse_data_finish; goto client_parse_data_finish;
} }
// variables // variables
@ -32,31 +35,40 @@ request_t *client_parse_data(char *buf, size_t len) {
char key[32] = {0}; char key[32] = {0};
mpack_expect_cstr(&reader, key, sizeof(key)); mpack_expect_cstr(&reader, key, sizeof(key));
if (mpack_reader_error(&reader) != mpack_ok) { if (mpack_reader_error(&reader) != mpack_ok) {
goto parse_data_finish; goto client_parse_data_finish;
} }
printf("key -> %s\n", key);
if (strcmp(key, "command") == 0) { if (strcmp(key, "command") == 0) {
command = mpack_expect_cstr_alloc(&reader, 32); command = mpack_expect_cstr_alloc(&reader, 32);
} else if (strcmp(key, "index") == 0) { } else if (strcmp(key, "index") == 0) {
index = mpack_expect_u64(&reader); index = mpack_expect_u64(&reader);
} else if (strcmp(key, "data") == 0) { } else if (strcmp(key, "data") == 0) {
mpack_expect_bin(&reader); //mpack_expect_bin(&reader);
data = mpack_expect_bin_alloc(&reader, CONFIG_IMAGE_BUF_SLICE_SIZE, &data_len); data = mpack_expect_bin_alloc(&reader, CONFIG_IMAGE_BUF_SLICE_SIZE, &data_len);
} else { }
else {
mpack_discard(&reader); mpack_discard(&reader);
} }
if (mpack_reader_error(&reader) != mpack_ok) {
puts("broken");
}
} }
parse_data_finish: client_parse_data_finish:
if (mpack_reader_destroy(&reader) != mpack_ok) if (mpack_reader_destroy(&reader) != mpack_ok) {
return NULL; return NULL;
}
if (!command) if (!command) {
return NULL; return NULL;
}
request_t *req = malloc(sizeof(request_t)); request_t *req = (request_t *)malloc(sizeof(request_t));
if (!req) if (!req) {
return NULL; return NULL;
}
memset(req, 0, sizeof(request_t)); memset(req, 0, sizeof(request_t));
req->command = command; req->command = command;
@ -65,4 +77,5 @@ parse_data_finish:
req->data_len = data_len; req->data_len = data_len;
return req; return req;
} }
#endif

View file

@ -1,24 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <mbedtls/md.h>
void show_sha256(char *buf, size_t len) {
uint8_t output[32];
memset(output, 0, sizeof(output));
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 0);
mbedtls_md_starts(&ctx);
mbedtls_md_update(&ctx, (const unsigned char *)buf, len);
mbedtls_md_finish(&ctx, output);
mbedtls_md_free(&ctx);
for (int i = 0; i < sizeof(output); i++) {
printf("%02x", output[i]);
}
printf("\n");
return;
}

View file

@ -1,14 +0,0 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void show_sha256(char *buf, size_t len);
#ifdef __cplusplus
}
#endif

443
main/tcphelper.c Normal file
View file

@ -0,0 +1,443 @@
/* BSD non-blocking socket example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sys/socket.h"
#include "netdb.h"
#include "errno.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "main.h"
#include "mesh_netif.h"
/**
* @brief Indicates that the file descriptor represents an invalid (uninitialized or closed) socket
*
* Used in the TCP server structure `sock[]` which holds list of active clients we serve.
*/
#define INVALID_SOCK (-1)
/**
* @brief Time in ms to yield to all tasks when a non-blocking socket would block
*
* Non-blocking socket operations are typically executed in a separate task validating
* the socket status. Whenever the socket returns `EAGAIN` (idle status, i.e. would block)
* we have to yield to all tasks to prevent lower priority tasks from starving.
*/
#define YIELD_TO_ALL_MS 50
/**
* @brief Utility to log socket errors
*
* @param[in] tag Logging tag
* @param[in] sock Socket number
* @param[in] err Socket errno
* @param[in] message Message to print
*/
static void log_socket_error(const char *tag, const int sock, const int err, const char *message)
{
ESP_LOGE(tag, "[sock=%d]: %s\n"
"error=%d: %s", sock, message, err, strerror(err));
}
/**
* @brief Tries to receive data from specified sockets in a non-blocking way,
* i.e. returns immediately if no data.
*
* @param[in] tag Logging tag
* @param[in] sock Socket for reception
* @param[out] data Data pointer to write the received data
* @param[in] max_len Maximum size of the allocated space for receiving data
* @return
* >0 : Size of received data
* =0 : No data available
* -1 : Error occurred during socket read operation
* -2 : Socket is not connected, to distinguish between an actual socket error and active disconnection
*/
int try_receive(const char *tag, const int sock, char * data, size_t max_len)
{
int len = recv(sock, data, max_len, 0);
if (len < 0) {
if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
return 0; // Not an error
}
if (errno == ENOTCONN) {
ESP_LOGW(tag, "[sock=%d]: Connection closed", sock);
return -2; // Socket has been disconnected
}
log_socket_error(tag, sock, errno, "Error occurred during receiving");
return -1;
}
return len;
}
/**
* @brief Sends the specified data to the socket. This function blocks until all bytes got sent.
*
* @param[in] tag Logging tag
* @param[in] sock Socket to write data
* @param[in] data Data to be written
* @param[in] len Length of the data
* @return
* >0 : Size the written data
* -1 : Error occurred during socket write operation
*/
int socket_send(const char *tag, const int sock, const char * data, const size_t len)
{
int to_write = len;
while (to_write > 0) {
int written = send(sock, data + (len - to_write), to_write, 0);
if (written < 0 && errno != EINPROGRESS && errno != EAGAIN && errno != EWOULDBLOCK) {
log_socket_error(tag, sock, errno, "Error occurred during sending");
return -1;
}
to_write -= written;
}
return len;
}
// variables
SemaphoreHandle_t lock = NULL;
TaskHandle_t *task_handle = NULL;
void tcp_initialize() {
lock = xSemaphoreCreateMutex();
return;
}
#if CONFIG_TCP_ROOT == 1
static const char *TAG = "nonblocking-socket-server";
/**
* @brief Returns the string representation of client's address (accepted on this server)
*/
static inline char* get_clients_address(struct sockaddr_storage *source_addr)
{
static char address_str[128];
char *res = NULL;
// Convert ip address to string
if (source_addr->ss_family == PF_INET) {
res = inet_ntoa_r(((struct sockaddr_in *)source_addr)->sin_addr, address_str, sizeof(address_str) - 1);
}
#ifdef CONFIG_LWIP_IPV6
else if (source_addr->ss_family == PF_INET6) {
res = inet6_ntoa_r(((struct sockaddr_in6 *)source_addr)->sin6_addr, address_str, sizeof(address_str) - 1);
}
#endif
if (!res) {
address_str[0] = '\0'; // Returns empty string if conversion didn't succeed
}
return address_str;
}
static void tcp_server_task(void *pvParameters)
{
static char rx_buffer[128];
struct addrinfo hints = { .ai_socktype = SOCK_STREAM };
struct addrinfo *address_info;
int listen_sock = INVALID_SOCK;
const size_t max_socks = CONFIG_LWIP_MAX_SOCKETS - 1;
static int sock[CONFIG_LWIP_MAX_SOCKETS - 1];
// Prepare a list of file descriptors to hold client's sockets, mark all of them as invalid, i.e. available
for (int i=0; i<max_socks; ++i) {
sock[i] = INVALID_SOCK;
}
// Translating the hostname or a string representation of an IP to address_info
int res = getaddrinfo("0.0.0.0", CONFIG_TCP_SERVER_PORT, &hints, &address_info);
if (res != 0 || address_info == NULL) {
ESP_LOGE(TAG, "couldn't get hostname for `%s` "
"getaddrinfo() returns %d, addrinfo=%p", "0.0.0.0", res, address_info);
goto error;
}
// Creating a listener socket
listen_sock = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
if (listen_sock < 0) {
log_socket_error(TAG, listen_sock, errno, "Unable to create socket");
goto error;
}
ESP_LOGI(TAG, "Listener socket created");
// Marking the socket as non-blocking
int flags = fcntl(listen_sock, F_GETFL);
if (fcntl(listen_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
log_socket_error(TAG, listen_sock, errno, "Unable to set socket non blocking");
goto error;
}
ESP_LOGI(TAG, "Socket marked as non blocking");
// Binding socket to the given address
int err = bind(listen_sock, address_info->ai_addr, address_info->ai_addrlen);
if (err != 0) {
log_socket_error(TAG, listen_sock, errno, "Socket unable to bind");
goto error;
}
ESP_LOGI(TAG, "Socket bound on %s:%s", "0.0.0.0", CONFIG_TCP_SERVER_PORT);
// Set queue (backlog) of pending connections to one (can be more)
err = listen(listen_sock, 1);
if (err != 0) {
log_socket_error(TAG, listen_sock, errno, "Error occurred during listen");
goto error;
}
ESP_LOGI(TAG, "Socket listening");
// Main loop for accepting new connections and serving all connected clients
while (1) {
struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
socklen_t addr_len = sizeof(source_addr);
// Find a free socket
int new_sock_index = 0;
for (new_sock_index=0; new_sock_index<max_socks; ++new_sock_index) {
if (sock[new_sock_index] == INVALID_SOCK) {
break;
}
}
// We accept a new connection only if we have a free socket
if (new_sock_index < max_socks) {
// Try to accept a new connections
sock[new_sock_index] = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
if (sock[new_sock_index] < 0) {
if (errno == EWOULDBLOCK) { // The listener socket did not accepts any connection
// continue to serve open connections and try to accept again upon the next iteration
ESP_LOGV(TAG, "No pending connections...");
} else {
log_socket_error(TAG, listen_sock, errno, "Error when accepting connection");
goto error;
}
} else {
// We have a new client connected -> print it's address
ESP_LOGI(TAG, "[sock=%d]: Connection accepted from IP:%s", sock[new_sock_index], get_clients_address(&source_addr));
// ...and set the client's socket non-blocking
flags = fcntl(sock[new_sock_index], F_GETFL);
if (fcntl(sock[new_sock_index], F_SETFL, flags | O_NONBLOCK) == -1) {
log_socket_error(TAG, sock[new_sock_index], errno, "Unable to set socket non blocking");
goto error;
}
ESP_LOGI(TAG, "[sock=%d]: Socket marked as non blocking", sock[new_sock_index]);
}
}
// We serve all the connected clients in this loop
for (int i=0; i<max_socks; ++i) {
if (sock[i] != INVALID_SOCK) {
// send
int result = tcp_server_callback(TAG, sock[i]);
if (result != 0) {
ESP_LOGE(TAG, "[sock=%d]: tcp_server_callback returned %d -> closing the socket", sock[i], result);
close(sock[i]);
sock[i] = INVALID_SOCK;
}
} // one client's socket
} // for all sockets
// Yield to other tasks
vTaskDelay(pdMS_TO_TICKS(YIELD_TO_ALL_MS));
}
error:
if (listen_sock != INVALID_SOCK) {
close(listen_sock);
}
for (int i=0; i<max_socks; ++i) {
if (sock[i] != INVALID_SOCK) {
close(sock[i]);
}
}
free(address_info);
vTaskDelete(NULL);
}
void start_tcp_server(void)
{
if (xSemaphoreTake(lock, 1000 / portTICK_PERIOD_MS) == false)
{
return;
}
// stop old task
if (task_handle) {
ESP_LOGI(TAG, "Detected old task, deleting...");
vTaskDelete(*task_handle);
free(task_handle);
task_handle = NULL;
}
// new task
task_handle = malloc(sizeof(TaskHandle_t));
memset(task_handle, 0, sizeof(TaskHandle_t));
xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, task_handle);
xSemaphoreGive(lock);
return;
}
#else
static const char *TAG = "nonblocking-socket-client";
// tcp client
static void tcp_client_task(void *pvParameters)
{
static char rx_buffer[CONFIG_TCP_RXBUFFER_SIZE];
int sock = INVALID_SOCK;
struct addrinfo hints = { .ai_socktype = SOCK_STREAM };
struct addrinfo *address_info;
int res = getaddrinfo(CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT, &hints, &address_info);
if (res != 0 || address_info == NULL) {
ESP_LOGE(TAG, "couldn't get hostname for `%s` "
"getaddrinfo() returns %d, addrinfo=%p", CONFIG_TCP_SERVER_IP, res, address_info);
goto error;
}
// Creating client's socket
sock = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
if (sock < 0) {
log_socket_error(TAG, sock, errno, "Unable to create socket");
goto error;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT);
// Marking the socket as non-blocking
int flags = fcntl(sock, F_GETFL);
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
log_socket_error(TAG, sock, errno, "Unable to set socket non blocking");
}
if (connect(sock, address_info->ai_addr, address_info->ai_addrlen) != 0) {
if (errno == EINPROGRESS) {
ESP_LOGD(TAG, "connection in progress");
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
// Connection in progress -> have to wait until the connecting socket is marked as writable, i.e. connection completes
res = select(sock+1, NULL, &fdset, NULL, NULL);
if (res < 0) {
log_socket_error(TAG, sock, errno, "Error during connection: select for socket to be writable");
goto error;
} else if (res == 0) {
log_socket_error(TAG, sock, errno, "Connection timeout: select for socket to be writable");
goto error;
} else {
int sockerr;
socklen_t len = (socklen_t)sizeof(int);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
log_socket_error(TAG, sock, errno, "Error when getting socket error using getsockopt()");
goto error;
}
if (sockerr) {
log_socket_error(TAG, sock, sockerr, "Connection error");
goto error;
}
}
} else {
log_socket_error(TAG, sock, errno, "Socket is unable to connect");
goto error;
}
}
ESP_LOGI(TAG, "Connected to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT);
// Keep receiving message
do {
// receive
int len = 0;
memset(rx_buffer, 0, sizeof(rx_buffer));
do {
len = try_receive(TAG, sock, rx_buffer, sizeof(rx_buffer));
if (len < 0) {
ESP_LOGE(TAG, "Error occurred during try_receive");
goto error;
}
vTaskDelay(pdMS_TO_TICKS(YIELD_TO_ALL_MS));
} while (len == 0);
ESP_LOGI(TAG, "Received message (len=%d)", len);
// execute command
char tx_buffer[128] = {0};
int result = tcp_client_callback(rx_buffer, len);
switch (result) {
case 0:
strcpy(tx_buffer, "ok\n");
break;
case -2:
strcpy(tx_buffer, "invalid request\n");
break;
case -3:
strcpy(tx_buffer, "locked\n");
break;
default:
strcpy(tx_buffer, "unknown error\n");
break;
}
// send result
len = socket_send(TAG, sock, tx_buffer, strlen(tx_buffer));
if (len < 0) {
ESP_LOGE(TAG, "Error occurred during socket_send");
goto error;
}
ESP_LOGI(TAG, "Written: %.*s", len, tx_buffer);
} while (true);
error:
if (sock != INVALID_SOCK) {
close(sock);
}
free(address_info);
free(task_handle);
task_handle = NULL;
vTaskDelete(NULL);
}
void start_tcp_client(void) {
if (xSemaphoreTake(lock, 1000 / portTICK_PERIOD_MS) == false)
{
return;
}
// stop old task
if (task_handle) {
ESP_LOGI(TAG, "Detected old task, deleting...");
vTaskDelete(*task_handle);
free(task_handle);
task_handle = NULL;
}
// new task
task_handle = malloc(sizeof(TaskHandle_t));
memset(task_handle, 0, sizeof(TaskHandle_t));
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, task_handle);
xSemaphoreGive(lock);
return;
}
#endif

23
main/tcphelper.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
// functions
int socket_send(const char *tag, const int sock, const char * data, const size_t len);
int try_receive(const char *tag, const int sock, char * data, size_t max_len);
void tcp_initialize(void);
#if CONFIG_TCP_ROOT == 1
void start_tcp_server(void);
#else
void start_tcp_client(void);
#endif
#ifdef __cplusplus
}
#endif

28
tcp_client_asyncio.py Normal file
View file

@ -0,0 +1,28 @@
import asyncio
import signal
async def handle_client(reader, writer):
try:
while True:
#data = await reader.readline()
#if not data:
# break
#
#msg = data.decode().strip()
#writer.write(f"echo: {msg}\n".encode())
await writer.drain()
except Exception as e:
print("error:", e)
finally:
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(
handle_client, host="0.0.0.0", port=3030
)
async with server:
await server.serve_forever()
asyncio.run(main())