Compare commits
No commits in common. "ea95b056cc2f49274648e70b39bb2838ba729315" and "354dd9c38d9c0298b36ef3fdcbccaedcda5caa61" have entirely different histories.
ea95b056cc
...
354dd9c38d
13 changed files with 437 additions and 660 deletions
|
|
@ -1,10 +1,12 @@
|
||||||
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"
|
||||||
"mpack/src/mpack/*.c"
|
"pubsubclient/src/*.cpp",
|
||||||
|
"mpack/src/mpack/*.c",
|
||||||
|
"sha256/*.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS "main.cpp" "EPD.cpp" "mesh_main.c" "mesh_netif.c" "tcphelper.c" "process.c" ${MY_LIB_SOURCES}
|
SRCS "processor.c" "main.cpp" "EPD.cpp" "mesh_main.c" "mesh_netif.c" "mesh_msg.c" ${MY_LIB_SOURCES}
|
||||||
INCLUDE_DIRS "" "ESP32epdx/src" "ESP32epdx/src/GUI" "mpack/src/mpack"
|
INCLUDE_DIRS "" "ESP32epdx/src" "ESP32epdx/src/GUI" "mpack/src/mpack" "sha256"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
173
main/main.cpp
173
main/main.cpp
|
|
@ -1,6 +1,5 @@
|
||||||
#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>
|
||||||
|
|
@ -9,9 +8,11 @@
|
||||||
#include "ESP32epdx.h"
|
#include "ESP32epdx.h"
|
||||||
#include "EPD.h"
|
#include "EPD.h"
|
||||||
#include "mesh_netif.h"
|
#include "mesh_netif.h"
|
||||||
#include "tcphelper.h"
|
#include "esp_mesh.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
#include "sha256.h"
|
||||||
|
|
||||||
std::mutex epd_mtx;
|
std::mutex epd_mtx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -21,7 +22,25 @@ 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
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +62,11 @@ 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));
|
||||||
|
|
@ -55,40 +79,149 @@ extern "C" int command_push_image() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int tcp_client_callback(request_t *req) {
|
extern "C" int mesh_client_callback(char *buf, size_t len) {
|
||||||
printf("cmd -> %s\n", req->command);
|
request_t *req = client_parse_data(buf, len);
|
||||||
printf("index -> %llu\n", req->index);
|
if (!req) { // error -> invalid data
|
||||||
printf("data_len -> %u\n", req->data_len);
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
// execute command
|
// execute command
|
||||||
if (strcmp(req->command, "ping") == 0)
|
if (strcmp(req->command, "ping") == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
goto mesh_client_callback_ret;
|
||||||
}
|
}
|
||||||
else if (strcmp(req->command, "update_image") == 0)
|
else if (strcmp(req->command, "update_image") == 0)
|
||||||
{
|
{
|
||||||
return command_update_image(req->index, req->data, req->data_len);
|
ret = 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)
|
||||||
{
|
{
|
||||||
return command_push_image();
|
ret = command_push_image();
|
||||||
|
goto mesh_client_callback_ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return -2;
|
ret = -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();
|
||||||
|
|
@ -102,17 +235,25 @@ extern "C" void app_main() {
|
||||||
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)
|
||||||
{
|
{
|
||||||
vTaskDelay(500);
|
#if CONFIG_MESH_ROOT == 1
|
||||||
|
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.
|
||||||
|
|
|
||||||
31
main/main.h
31
main/main.h
|
|
@ -1,6 +1,4 @@
|
||||||
#ifndef MAIN_H
|
#pragma once
|
||||||
#define MAIN_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*******************************************************
|
/*******************************************************
|
||||||
|
|
@ -13,21 +11,18 @@
|
||||||
|
|
||||||
// change these
|
// change these
|
||||||
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 "testesp"
|
//#define CONFIG_MESH_ROUTER_SSID "FastCyberRoom"
|
||||||
#define CONFIG_MESH_ROUTER_PASSWD "RABCRABC"
|
//#define CONFIG_MESH_ROUTER_PASSWD "dyes1107@"
|
||||||
#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 CONFIG_TCP_ROOT 0
|
#define DEBUG 1
|
||||||
#define CONFIG_TCP_SERVER_IP "172.16.0.1"
|
#define CONFIG_MESH_ROOT 1
|
||||||
//#define CONFIG_TCP_SERVER_IP "10.189.34.172"
|
#define CONFIG_IMAGE_BUF_SLICE_SIZE 950 // map["data"] max size
|
||||||
#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
|
||||||
|
|
||||||
/*******************************************************
|
/*******************************************************
|
||||||
|
|
@ -48,16 +43,10 @@ typedef struct request_t {
|
||||||
size_t data_len;
|
size_t data_len;
|
||||||
} request_t;
|
} request_t;
|
||||||
|
|
||||||
#if CONFIG_TCP_ROOT == 1
|
|
||||||
int tcp_server_callback(const char *TAG, int sock);
|
|
||||||
#else
|
|
||||||
int tcp_client_callback(request_t *req);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
request_t *client_parse_data(char *buf, size_t len);
|
request_t *client_parse_data(char *buf, size_t len);
|
||||||
|
|
||||||
|
int mesh_client_callback(char *buf, size_t len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -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
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
static const char *MESH_TAG = "mesh_main";
|
const char *MESH_TAG = "mesh_main";
|
||||||
|
|
||||||
/*******************************************************
|
/*******************************************************
|
||||||
* Variable Definitions
|
* Variable Definitions
|
||||||
|
|
@ -306,13 +306,6 @@ 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -356,8 +349,12 @@ 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));
|
||||||
|
|
|
||||||
186
main/mesh_msg.c
Normal file
186
main/mesh_msg.c
Normal file
|
|
@ -0,0 +1,186 @@
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,10 @@
|
||||||
#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
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
|
|
@ -90,6 +94,20 @@ 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
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
must enable "use external log wrapper"
|
must enable "use external log wrapper"
|
||||||
|
|
||||||
|
我是寫 client 的,所以我這裡的「模擬 master」採用直接 unicast 的方式
|
||||||
|
|
@ -1,27 +1,24 @@
|
||||||
#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.h"
|
#include "mpack/src/mpack/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 client_parse_data_finish;
|
goto 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 client_parse_data_finish;
|
goto parse_data_finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
|
|
@ -35,40 +32,31 @@ 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 client_parse_data_finish;
|
goto 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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client_parse_data_finish:
|
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 = (request_t *)malloc(sizeof(request_t));
|
request_t *req = 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;
|
||||||
|
|
@ -78,4 +66,3 @@ client_parse_data_finish:
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
24
main/sha256/sha256.c
Normal file
24
main/sha256/sha256.c
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
14
main/sha256/sha256.h
Normal file
14
main/sha256/sha256.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void show_sha256(char *buf, size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
485
main/tcphelper.c
485
main/tcphelper.c
|
|
@ -1,485 +0,0 @@
|
||||||
/* 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 "mpack.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";
|
|
||||||
|
|
||||||
size_t mp_fill(mpack_tree_t *reader, char *buffer, size_t count) {
|
|
||||||
int sock = (int)reader->context;
|
|
||||||
ESP_LOGI(TAG, "expect %lu bytes", count);
|
|
||||||
ssize_t r = recv(sock, buffer, count, 0);
|
|
||||||
ESP_LOGI(TAG, "received %ld bytes", r);
|
|
||||||
|
|
||||||
if (r <= 0) {
|
|
||||||
mpack_tree_flag_error(reader, mpack_error_io);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) == -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) {
|
|
||||||
ESP_LOGE(TAG, "Failed to connect server");
|
|
||||||
}
|
|
||||||
|
|
||||||
//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);
|
|
||||||
|
|
||||||
// mpack
|
|
||||||
mpack_tree_t tree;
|
|
||||||
mpack_tree_init_stream(&tree, mp_fill, (void *)sock, CONFIG_IMAGE_BUF_SIZE, 30);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
mpack_tree_parse(&tree);
|
|
||||||
if (mpack_tree_error(&tree) != mpack_ok) {
|
|
||||||
ESP_LOGE(TAG, "mperror: %d\n", mpack_tree_error(&tree));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse
|
|
||||||
mpack_node_t root = mpack_tree_root(&tree);
|
|
||||||
char *cmd = mpack_node_cstr_alloc(mpack_node_map_cstr(root, "command"), 30);
|
|
||||||
|
|
||||||
size_t index = 0;
|
|
||||||
size_t data_size = 0;
|
|
||||||
char *data = NULL;
|
|
||||||
if (strcmp(cmd, "update_image") == 0) {
|
|
||||||
index = mpack_node_u64(mpack_node_map_cstr(root, "index"));
|
|
||||||
|
|
||||||
data_size = mpack_node_data_len(mpack_node_map_cstr(root, "data"));
|
|
||||||
data = (char *)mpack_node_data(mpack_node_map_cstr(root, "data"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// callback
|
|
||||||
request_t req;
|
|
||||||
memset(&req, 0, sizeof(req));
|
|
||||||
req.command = cmd;
|
|
||||||
req.index = index;
|
|
||||||
req.data = data;
|
|
||||||
req.data_len = data_size;
|
|
||||||
|
|
||||||
int result = tcp_client_callback(&req);
|
|
||||||
char tx_buffer[128] = {0};
|
|
||||||
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
|
|
||||||
int send_len = socket_send(TAG, sock, tx_buffer, strlen(tx_buffer));
|
|
||||||
if (send_len < 0) {
|
|
||||||
ESP_LOGE(TAG, "Error occurred during socket_send");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
ESP_LOGI(TAG, "Written: %.*s", send_len, tx_buffer);
|
|
||||||
|
|
||||||
// end
|
|
||||||
free(cmd);
|
|
||||||
cmd=NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
from typing import Dict, Any
|
|
||||||
import socket
|
|
||||||
|
|
||||||
import msgpack
|
|
||||||
|
|
||||||
import tcp_client_image
|
|
||||||
|
|
||||||
|
|
||||||
HOST = "0.0.0.0"
|
|
||||||
PORT = 3030
|
|
||||||
|
|
||||||
def send_request(client_socket:socket.socket, data:Dict[str, Any]):
|
|
||||||
try:
|
|
||||||
message:bytes = msgpack.packb(data)
|
|
||||||
|
|
||||||
client_socket.sendall(message)
|
|
||||||
|
|
||||||
rx = client_socket.recv(1024)
|
|
||||||
if data:
|
|
||||||
print(f"Received message: {rx.decode('utf-8').strip()}")
|
|
||||||
else:
|
|
||||||
print("Connection closed")
|
|
||||||
return
|
|
||||||
except ConnectionResetError:
|
|
||||||
print("Connection reset")
|
|
||||||
|
|
||||||
def image(s:socket.socket):
|
|
||||||
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(s, data)
|
|
||||||
|
|
||||||
send_request(s, {"command":"push_image"})
|
|
||||||
|
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
||||||
s.bind((HOST, PORT))
|
|
||||||
s.listen(5)
|
|
||||||
print("listening...")
|
|
||||||
|
|
||||||
conn, addr = s.accept() # 阻塞
|
|
||||||
with conn:
|
|
||||||
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(conn)
|
|
||||||
elif choice == 2:
|
|
||||||
send_request(conn, {"command":"ping"})
|
|
||||||
elif choice == 3:
|
|
||||||
send_request(conn, {"command":"invalid_command"})
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
Loading…
Add table
Reference in a new issue