feat: mpack + continus stream
This commit is contained in:
parent
0f80116be2
commit
ea95b056cc
5 changed files with 202 additions and 120 deletions
|
|
@ -55,17 +55,10 @@ extern "C" int command_push_image() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int tcp_client_callback(char *buf, size_t len) {
|
extern "C" int tcp_client_callback(request_t *req) {
|
||||||
for (size_t i = 0; i < len; i++) {
|
printf("cmd -> %s\n", req->command);
|
||||||
printf("%02x ", buf[i]);
|
printf("index -> %llu\n", req->index);
|
||||||
}
|
printf("data_len -> %u\n", req->data_len);
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
request_t *req = client_parse_data(buf, len);
|
|
||||||
if (!req) { // error -> invalid data
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute command
|
// execute command
|
||||||
if (strcmp(req->command, "ping") == 0)
|
if (strcmp(req->command, "ping") == 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
14
main/main.h
14
main/main.h
|
|
@ -13,18 +13,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 "testesp"
|
||||||
//#define CONFIG_MESH_ROUTER_PASSWD "RABCRABC"
|
#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 CONFIG_TCP_ROOT 0
|
#define CONFIG_TCP_ROOT 0
|
||||||
//#define CONFIG_TCP_SERVER_IP "172.16.0.1"
|
#define CONFIG_TCP_SERVER_IP "172.16.0.1"
|
||||||
#define CONFIG_TCP_SERVER_IP "10.189.34.172"
|
//#define CONFIG_TCP_SERVER_IP "10.189.34.172"
|
||||||
#define CONFIG_TCP_SERVER_PORT "3030"
|
#define CONFIG_TCP_SERVER_PORT "3030"
|
||||||
#define CONFIG_TCP_RXBUFFER_SIZE 4096 // tcp raw data max size
|
#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_SLICE_SIZE 2048 // map["data"] max size
|
||||||
|
|
@ -51,7 +51,7 @@ typedef struct request_t {
|
||||||
#if CONFIG_TCP_ROOT == 1
|
#if CONFIG_TCP_ROOT == 1
|
||||||
int tcp_server_callback(const char *TAG, int sock);
|
int tcp_server_callback(const char *TAG, int sock);
|
||||||
#else
|
#else
|
||||||
int tcp_client_callback(char *buf, size_t len);
|
int tcp_client_callback(request_t *req);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
request_t *client_parse_data(char *buf, size_t len);
|
request_t *client_parse_data(char *buf, size_t len);
|
||||||
|
|
|
||||||
152
main/tcphelper.c
152
main/tcphelper.c
|
|
@ -18,6 +18,7 @@
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
|
|
||||||
|
#include "mpack.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh_netif.h"
|
#include "mesh_netif.h"
|
||||||
|
|
||||||
|
|
@ -298,6 +299,20 @@ void start_tcp_server(void)
|
||||||
#else
|
#else
|
||||||
static const char *TAG = "nonblocking-socket-client";
|
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
|
// tcp client
|
||||||
static void tcp_client_task(void *pvParameters)
|
static void tcp_client_task(void *pvParameters)
|
||||||
{
|
{
|
||||||
|
|
@ -323,64 +338,86 @@ static void tcp_client_task(void *pvParameters)
|
||||||
ESP_LOGI(TAG, "Socket created, connecting to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT);
|
ESP_LOGI(TAG, "Socket created, connecting to %s:%s", CONFIG_TCP_SERVER_IP, CONFIG_TCP_SERVER_PORT);
|
||||||
|
|
||||||
// Marking the socket as non-blocking
|
// Marking the socket as non-blocking
|
||||||
int flags = fcntl(sock, F_GETFL);
|
//int flags = fcntl(sock, F_GETFL);
|
||||||
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
|
//if (fcntl(sock, F_SETFL, flags) == -1) {
|
||||||
log_socket_error(TAG, sock, errno, "Unable to set socket non blocking");
|
// 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 (connect(sock, address_info->ai_addr, address_info->ai_addrlen) != 0) {
|
||||||
if (errno == EINPROGRESS) {
|
ESP_LOGE(TAG, "Failed to connect server");
|
||||||
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
|
//if (connect(sock, address_info->ai_addr, address_info->ai_addrlen) != 0) {
|
||||||
res = select(sock+1, NULL, &fdset, NULL, NULL);
|
// if (errno == EINPROGRESS) {
|
||||||
if (res < 0) {
|
// ESP_LOGD(TAG, "connection in progress");
|
||||||
log_socket_error(TAG, sock, errno, "Error during connection: select for socket to be writable");
|
// fd_set fdset;
|
||||||
goto error;
|
// FD_ZERO(&fdset);
|
||||||
} else if (res == 0) {
|
// FD_SET(sock, &fdset);
|
||||||
log_socket_error(TAG, sock, errno, "Connection timeout: select for socket to be writable");
|
//
|
||||||
goto error;
|
// // Connection in progress -> have to wait until the connecting socket is marked as writable, i.e. connection completes
|
||||||
} else {
|
// res = select(sock+1, NULL, &fdset, NULL, NULL);
|
||||||
int sockerr;
|
// if (res < 0) {
|
||||||
socklen_t len = (socklen_t)sizeof(int);
|
// log_socket_error(TAG, sock, errno, "Error during connection: select for socket to be writable");
|
||||||
|
// goto error;
|
||||||
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
|
// } else if (res == 0) {
|
||||||
log_socket_error(TAG, sock, errno, "Error when getting socket error using getsockopt()");
|
// log_socket_error(TAG, sock, errno, "Connection timeout: select for socket to be writable");
|
||||||
goto error;
|
// goto error;
|
||||||
}
|
// } else {
|
||||||
if (sockerr) {
|
// int sockerr;
|
||||||
log_socket_error(TAG, sock, sockerr, "Connection error");
|
// socklen_t len = (socklen_t)sizeof(int);
|
||||||
goto error;
|
//
|
||||||
}
|
// if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
|
||||||
}
|
// log_socket_error(TAG, sock, errno, "Error when getting socket error using getsockopt()");
|
||||||
} else {
|
// goto error;
|
||||||
log_socket_error(TAG, sock, errno, "Socket is unable to connect");
|
// }
|
||||||
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);
|
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
|
// 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};
|
char tx_buffer[128] = {0};
|
||||||
int result = tcp_client_callback(rx_buffer, len);
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0:
|
case 0:
|
||||||
strcpy(tx_buffer, "ok\n");
|
strcpy(tx_buffer, "ok\n");
|
||||||
|
|
@ -397,13 +434,18 @@ static void tcp_client_task(void *pvParameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send result
|
// send result
|
||||||
len = socket_send(TAG, sock, tx_buffer, strlen(tx_buffer));
|
int send_len = socket_send(TAG, sock, tx_buffer, strlen(tx_buffer));
|
||||||
if (len < 0) {
|
if (send_len < 0) {
|
||||||
ESP_LOGE(TAG, "Error occurred during socket_send");
|
ESP_LOGE(TAG, "Error occurred during socket_send");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Written: %.*s", len, tx_buffer);
|
ESP_LOGI(TAG, "Written: %.*s", send_len, tx_buffer);
|
||||||
} while (true);
|
|
||||||
|
// end
|
||||||
|
free(cmd);
|
||||||
|
cmd=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (sock != INVALID_SOCK) {
|
if (sock != INVALID_SOCK) {
|
||||||
|
|
|
||||||
75
tcp_client2.py
Normal file
75
tcp_client2.py
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
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
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
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())
|
|
||||||
Loading…
Add table
Reference in a new issue