mirror of
https://git.mirrors.martin98.com/https://github.com/luc-github/ESP3D.git
synced 2025-08-02 06:40:41 +08:00
Fix compilation for Async
Update library for ESP32 async
This commit is contained in:
parent
40c5156be5
commit
df51e025ce
@ -12,8 +12,11 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/me-no-dev/AsyncTCP.git"
|
"url": "https://github.com/me-no-dev/AsyncTCP.git"
|
||||||
},
|
},
|
||||||
"version": "1.0.0",
|
"version": "1.0.3",
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
"frameworks": "arduino",
|
"frameworks": "arduino",
|
||||||
"platforms": ["espressif32", "espressif32_stage"]
|
"platforms": "espressif32",
|
||||||
|
"build": {
|
||||||
|
"libCompatMode": 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=AsyncTCP
|
name=AsyncTCP
|
||||||
version=1.0.0
|
version=1.0.3
|
||||||
author=Me-No-Dev
|
author=Me-No-Dev
|
||||||
maintainer=Me-No-Dev
|
maintainer=Me-No-Dev
|
||||||
sentence=Async TCP Library for ESP32
|
sentence=Async TCP Library for ESP32
|
||||||
|
@ -29,12 +29,18 @@ extern "C"{
|
|||||||
#include "lwip/dns.h"
|
#include "lwip/dns.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_FREERTOS_UNICORE
|
||||||
|
#define ASYNCTCP_RUNNING_CORE 0
|
||||||
|
#else
|
||||||
|
#define ASYNCTCP_RUNNING_CORE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TCP/IP Event Task
|
* TCP/IP Event Task
|
||||||
* */
|
* */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LWIP_TCP_SENT, LWIP_TCP_RECV, LWIP_TCP_ERROR, LWIP_TCP_POLL
|
LWIP_TCP_SENT, LWIP_TCP_RECV, LWIP_TCP_ERROR, LWIP_TCP_POLL, LWIP_TCP_CLEAR
|
||||||
} lwip_event_t;
|
} lwip_event_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -74,13 +80,77 @@ typedef struct {
|
|||||||
static xQueueHandle _async_queue;
|
static xQueueHandle _async_queue;
|
||||||
static TaskHandle_t _async_service_task_handle = NULL;
|
static TaskHandle_t _async_service_task_handle = NULL;
|
||||||
|
|
||||||
static void _handle_async_event(lwip_event_packet_t * e){
|
static inline bool _init_async_event_queue(){
|
||||||
|
if(!_async_queue){
|
||||||
|
_async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));
|
||||||
|
if(!_async_queue){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if(e->event == LWIP_TCP_RECV){
|
static inline bool _send_async_event(lwip_event_packet_t ** e){
|
||||||
|
return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _prepend_async_event(lwip_event_packet_t ** e){
|
||||||
|
return _async_queue && xQueueSendToFront(_async_queue, e, portMAX_DELAY) == pdPASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _get_async_event(lwip_event_packet_t ** e){
|
||||||
|
return _async_queue && xQueueReceive(_async_queue, e, portMAX_DELAY) == pdPASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _remove_events_with_arg(void * arg){
|
||||||
|
lwip_event_packet_t * first_packet = NULL;
|
||||||
|
lwip_event_packet_t * packet = NULL;
|
||||||
|
|
||||||
|
if(!_async_queue){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//figure out which is the first packet so we can keep the order
|
||||||
|
while(!first_packet){
|
||||||
|
if(xQueueReceive(_async_queue, &first_packet, 0) != pdPASS){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//discard packet if matching
|
||||||
|
if((int)first_packet->arg == (int)arg){
|
||||||
|
//ets_printf("X: 0x%08x\n", (uint32_t)first_packet->arg);
|
||||||
|
free(first_packet);
|
||||||
|
first_packet = NULL;
|
||||||
|
//return first packet to the back of the queue
|
||||||
|
} else if(xQueueSend(_async_queue, &first_packet, portMAX_DELAY) != pdPASS){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet){
|
||||||
|
if(xQueueReceive(_async_queue, &packet, 0) != pdPASS){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if((int)packet->arg == (int)arg){
|
||||||
|
//ets_printf("X: 0x%08x\n", (uint32_t)packet->arg);
|
||||||
|
free(packet);
|
||||||
|
packet = NULL;
|
||||||
|
} else if(xQueueSend(_async_queue, &packet, portMAX_DELAY) != pdPASS){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _handle_async_event(lwip_event_packet_t * e){
|
||||||
|
if(e->event == LWIP_TCP_CLEAR){
|
||||||
|
_remove_events_with_arg(e->arg);
|
||||||
|
} else if(e->event == LWIP_TCP_RECV){
|
||||||
|
//ets_printf("%c: 0x%08x 0x%08x\n", e->recv.pb?'R':'D', e->arg, e->recv.pcb);
|
||||||
AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err);
|
AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err);
|
||||||
} else if(e->event == LWIP_TCP_SENT){
|
} else if(e->event == LWIP_TCP_SENT){
|
||||||
|
//ets_printf("S: 0x%08x 0x%08x\n", e->arg, e->sent.pcb);
|
||||||
AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len);
|
AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len);
|
||||||
} else if(e->event == LWIP_TCP_POLL){
|
} else if(e->event == LWIP_TCP_POLL){
|
||||||
|
//ets_printf("P: 0x%08x 0x%08x\n", e->arg, e->poll.pcb);
|
||||||
AsyncClient::_s_poll(e->arg, e->poll.pcb);
|
AsyncClient::_s_poll(e->arg, e->poll.pcb);
|
||||||
} else if(e->event == LWIP_TCP_ERROR){
|
} else if(e->event == LWIP_TCP_ERROR){
|
||||||
AsyncClient::_s_error(e->arg, e->error.err);
|
AsyncClient::_s_error(e->arg, e->error.err);
|
||||||
@ -91,11 +161,8 @@ static void _handle_async_event(lwip_event_packet_t * e){
|
|||||||
static void _async_service_task(void *pvParameters){
|
static void _async_service_task(void *pvParameters){
|
||||||
lwip_event_packet_t * packet = NULL;
|
lwip_event_packet_t * packet = NULL;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if(xQueueReceive(_async_queue, &packet, 0) == pdTRUE){
|
if(_get_async_event(&packet)){
|
||||||
//dispatch packet
|
|
||||||
_handle_async_event(packet);
|
_handle_async_event(packet);
|
||||||
} else {
|
|
||||||
vTaskDelay(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
@ -110,14 +177,11 @@ static void _stop_async_task(){
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
static bool _start_async_task(){
|
static bool _start_async_task(){
|
||||||
if(!_async_queue){
|
if(!_init_async_event_queue()){
|
||||||
_async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *));
|
return false;
|
||||||
if(!_async_queue){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(!_async_service_task_handle){
|
if(!_async_service_task_handle){
|
||||||
xTaskCreatePinnedToCore(_async_service_task, "async_tcp", 8192, NULL, 3, &_async_service_task_handle, 1);
|
xTaskCreatePinnedToCore(_async_service_task, "async_tcp", 8192, NULL, 3, &_async_service_task_handle, ASYNCTCP_RUNNING_CORE);
|
||||||
if(!_async_service_task_handle){
|
if(!_async_service_task_handle){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -129,60 +193,58 @@ static bool _start_async_task(){
|
|||||||
* LwIP Callbacks
|
* LwIP Callbacks
|
||||||
* */
|
* */
|
||||||
|
|
||||||
static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) {
|
static int8_t _tcp_clear_events(void * arg) {
|
||||||
if(!_async_queue){
|
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
||||||
return ERR_OK;
|
e->event = LWIP_TCP_CLEAR;
|
||||||
|
e->arg = arg;
|
||||||
|
if (!_prepend_async_event(&e)) {
|
||||||
|
free((void*)(e));
|
||||||
}
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) {
|
||||||
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
||||||
e->event = LWIP_TCP_POLL;
|
e->event = LWIP_TCP_POLL;
|
||||||
e->arg = arg;
|
e->arg = arg;
|
||||||
e->poll.pcb = pcb;
|
e->poll.pcb = pcb;
|
||||||
if (xQueueSend(_async_queue, &e, portMAX_DELAY) != pdPASS) {
|
if (!_send_async_event(&e)) {
|
||||||
free((void*)(e));
|
free((void*)(e));
|
||||||
}
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) {
|
static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) {
|
||||||
if(!_async_queue){
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
||||||
e->event = LWIP_TCP_RECV;
|
e->event = LWIP_TCP_RECV;
|
||||||
e->arg = arg;
|
e->arg = arg;
|
||||||
e->recv.pcb = pcb;
|
e->recv.pcb = pcb;
|
||||||
e->recv.pb = pb;
|
e->recv.pb = pb;
|
||||||
e->recv.err = err;
|
e->recv.err = err;
|
||||||
if (xQueueSend(_async_queue, &e, portMAX_DELAY) != pdPASS) {
|
if (!_send_async_event(&e)) {
|
||||||
free((void*)(e));
|
free((void*)(e));
|
||||||
}
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) {
|
static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) {
|
||||||
if(!_async_queue){
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
||||||
e->event = LWIP_TCP_SENT;
|
e->event = LWIP_TCP_SENT;
|
||||||
e->arg = arg;
|
e->arg = arg;
|
||||||
e->sent.pcb = pcb;
|
e->sent.pcb = pcb;
|
||||||
e->sent.len = len;
|
e->sent.len = len;
|
||||||
if (xQueueSend(_async_queue, &e, portMAX_DELAY) != pdPASS) {
|
if (!_send_async_event(&e)) {
|
||||||
free((void*)(e));
|
free((void*)(e));
|
||||||
}
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tcp_error(void * arg, int8_t err) {
|
static void _tcp_error(void * arg, int8_t err) {
|
||||||
if(!_async_queue){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t));
|
||||||
e->event = LWIP_TCP_ERROR;
|
e->event = LWIP_TCP_ERROR;
|
||||||
e->arg = arg;
|
e->arg = arg;
|
||||||
e->error.err = err;
|
e->error.err = err;
|
||||||
if (xQueueSend(_async_queue, &e, portMAX_DELAY) != pdPASS) {
|
if (!_send_async_event(&e)) {
|
||||||
free((void*)(e));
|
free((void*)(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +256,7 @@ static void _tcp_error(void * arg, int8_t err) {
|
|||||||
#include "lwip/priv/tcpip_priv.h"
|
#include "lwip/priv/tcpip_priv.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct tcpip_api_call call;
|
struct tcpip_api_call_data call;
|
||||||
tcp_pcb * pcb;
|
tcp_pcb * pcb;
|
||||||
int8_t err;
|
int8_t err;
|
||||||
union {
|
union {
|
||||||
@ -217,20 +279,24 @@ typedef struct {
|
|||||||
};
|
};
|
||||||
} tcp_api_call_t;
|
} tcp_api_call_t;
|
||||||
|
|
||||||
static err_t _tcp_output_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = tcp_output(msg->pcb);
|
if(msg->pcb){
|
||||||
|
msg->err = tcp_output(msg->pcb);
|
||||||
|
} else {
|
||||||
|
msg->err = 0;
|
||||||
|
}
|
||||||
return msg->err;
|
return msg->err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t _tcp_output(tcp_pcb * pcb) {
|
static esp_err_t _tcp_output(tcp_pcb * pcb) {
|
||||||
tcp_api_call_t msg;
|
tcp_api_call_t msg;
|
||||||
msg.pcb = pcb;
|
msg.pcb = pcb;
|
||||||
tcpip_api_call(_tcp_output_api, (struct tcpip_api_call*)&msg);
|
tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.err;
|
return msg.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t _tcp_write_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_write_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags);
|
msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags);
|
||||||
return msg->err;
|
return msg->err;
|
||||||
@ -242,11 +308,11 @@ static esp_err_t _tcp_write(tcp_pcb * pcb, const char* data, size_t size, uint8_
|
|||||||
msg.write.data = data;
|
msg.write.data = data;
|
||||||
msg.write.size = size;
|
msg.write.size = size;
|
||||||
msg.write.apiflags = apiflags;
|
msg.write.apiflags = apiflags;
|
||||||
tcpip_api_call(_tcp_write_api, (struct tcpip_api_call*)&msg);
|
tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.err;
|
return msg.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t _tcp_recved_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_recved_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = 0;
|
msg->err = 0;
|
||||||
tcp_recved(msg->pcb, msg->received);
|
tcp_recved(msg->pcb, msg->received);
|
||||||
@ -257,11 +323,11 @@ static esp_err_t _tcp_recved(tcp_pcb * pcb, size_t len) {
|
|||||||
tcp_api_call_t msg;
|
tcp_api_call_t msg;
|
||||||
msg.pcb = pcb;
|
msg.pcb = pcb;
|
||||||
msg.received = len;
|
msg.received = len;
|
||||||
tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call*)&msg);
|
tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.err;
|
return msg.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t _tcp_connect_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_connect_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb);
|
msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb);
|
||||||
return msg->err;
|
return msg->err;
|
||||||
@ -273,11 +339,11 @@ static esp_err_t _tcp_connect(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port, tc
|
|||||||
msg.connect.addr = addr;
|
msg.connect.addr = addr;
|
||||||
msg.connect.port = port;
|
msg.connect.port = port;
|
||||||
msg.connect.cb = cb;
|
msg.connect.cb = cb;
|
||||||
tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call*)&msg);
|
tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.err;
|
return msg.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t _tcp_close_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_close_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = tcp_close(msg->pcb);
|
msg->err = tcp_close(msg->pcb);
|
||||||
return msg->err;
|
return msg->err;
|
||||||
@ -286,11 +352,12 @@ static err_t _tcp_close_api(struct tcpip_api_call *api_call_msg){
|
|||||||
static esp_err_t _tcp_close(tcp_pcb * pcb) {
|
static esp_err_t _tcp_close(tcp_pcb * pcb) {
|
||||||
tcp_api_call_t msg;
|
tcp_api_call_t msg;
|
||||||
msg.pcb = pcb;
|
msg.pcb = pcb;
|
||||||
tcpip_api_call(_tcp_close_api, (struct tcpip_api_call*)&msg);
|
//ets_printf("close 0x%08x\n", (uint32_t)pcb);
|
||||||
|
tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.err;
|
return msg.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t _tcp_abort_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_abort_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = 0;
|
msg->err = 0;
|
||||||
tcp_abort(msg->pcb);
|
tcp_abort(msg->pcb);
|
||||||
@ -300,11 +367,12 @@ static err_t _tcp_abort_api(struct tcpip_api_call *api_call_msg){
|
|||||||
static esp_err_t _tcp_abort(tcp_pcb * pcb) {
|
static esp_err_t _tcp_abort(tcp_pcb * pcb) {
|
||||||
tcp_api_call_t msg;
|
tcp_api_call_t msg;
|
||||||
msg.pcb = pcb;
|
msg.pcb = pcb;
|
||||||
tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call*)&msg);
|
//ets_printf("abort 0x%08x\n", (uint32_t)pcb);
|
||||||
|
tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.err;
|
return msg.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t _tcp_bind_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_bind_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port);
|
msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port);
|
||||||
return msg->err;
|
return msg->err;
|
||||||
@ -315,11 +383,11 @@ static esp_err_t _tcp_bind(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port) {
|
|||||||
msg.pcb = pcb;
|
msg.pcb = pcb;
|
||||||
msg.bind.addr = addr;
|
msg.bind.addr = addr;
|
||||||
msg.bind.port = port;
|
msg.bind.port = port;
|
||||||
tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call*)&msg);
|
tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.err;
|
return msg.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static err_t _tcp_listen_api(struct tcpip_api_call *api_call_msg){
|
static err_t _tcp_listen_api(struct tcpip_api_call_data *api_call_msg){
|
||||||
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg;
|
||||||
msg->err = 0;
|
msg->err = 0;
|
||||||
msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog);
|
msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog);
|
||||||
@ -330,7 +398,7 @@ static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) {
|
|||||||
tcp_api_call_t msg;
|
tcp_api_call_t msg;
|
||||||
msg.pcb = pcb;
|
msg.pcb = pcb;
|
||||||
msg.backlog = backlog?backlog:0xFF;
|
msg.backlog = backlog?backlog:0xFF;
|
||||||
tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call*)&msg);
|
tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg);
|
||||||
return msg.pcb;
|
return msg.pcb;
|
||||||
}
|
}
|
||||||
#define _tcp_listen(p) _tcp_listen_with_backlog(p, 0xFF);
|
#define _tcp_listen(p) _tcp_listen_with_backlog(p, 0xFF);
|
||||||
@ -352,6 +420,8 @@ AsyncClient::AsyncClient(tcp_pcb* pcb)
|
|||||||
, _error_cb_arg(0)
|
, _error_cb_arg(0)
|
||||||
, _recv_cb(0)
|
, _recv_cb(0)
|
||||||
, _recv_cb_arg(0)
|
, _recv_cb_arg(0)
|
||||||
|
, _pb_cb(0)
|
||||||
|
, _pb_cb_arg(0)
|
||||||
, _timeout_cb(0)
|
, _timeout_cb(0)
|
||||||
, _timeout_cb_arg(0)
|
, _timeout_cb_arg(0)
|
||||||
, _pcb_busy(false)
|
, _pcb_busy(false)
|
||||||
@ -366,6 +436,8 @@ AsyncClient::AsyncClient(tcp_pcb* pcb)
|
|||||||
, next(NULL)
|
, next(NULL)
|
||||||
, _in_lwip_thread(false)
|
, _in_lwip_thread(false)
|
||||||
{
|
{
|
||||||
|
//ets_printf("+: 0x%08x\n", (uint32_t)this);
|
||||||
|
|
||||||
_pcb = pcb;
|
_pcb = pcb;
|
||||||
if(_pcb){
|
if(_pcb){
|
||||||
_rx_last_packet = millis();
|
_rx_last_packet = millis();
|
||||||
@ -374,12 +446,15 @@ AsyncClient::AsyncClient(tcp_pcb* pcb)
|
|||||||
tcp_sent(_pcb, &_tcp_sent);
|
tcp_sent(_pcb, &_tcp_sent);
|
||||||
tcp_err(_pcb, &_tcp_error);
|
tcp_err(_pcb, &_tcp_error);
|
||||||
tcp_poll(_pcb, &_tcp_poll, 1);
|
tcp_poll(_pcb, &_tcp_poll, 1);
|
||||||
|
//ets_printf("accept 0x%08x\n", (uint32_t)_pcb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncClient::~AsyncClient(){
|
AsyncClient::~AsyncClient(){
|
||||||
if(_pcb)
|
if(_pcb)
|
||||||
_close();
|
_close();
|
||||||
|
|
||||||
|
//ets_printf("-: 0x%08x\n", (uint32_t)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncClient::connect(IPAddress ip, uint16_t port){
|
bool AsyncClient::connect(IPAddress ip, uint16_t port){
|
||||||
@ -445,6 +520,7 @@ int8_t AsyncClient::_connected(void* pcb, int8_t err){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_close(){
|
int8_t AsyncClient::_close(){
|
||||||
|
//ets_printf("X: 0x%08x\n", (uint32_t)this);
|
||||||
int8_t err = ERR_OK;
|
int8_t err = ERR_OK;
|
||||||
if(_pcb) {
|
if(_pcb) {
|
||||||
//log_i("");
|
//log_i("");
|
||||||
@ -453,6 +529,7 @@ int8_t AsyncClient::_close(){
|
|||||||
tcp_recv(_pcb, NULL);
|
tcp_recv(_pcb, NULL);
|
||||||
tcp_err(_pcb, NULL);
|
tcp_err(_pcb, NULL);
|
||||||
tcp_poll(_pcb, NULL, 0);
|
tcp_poll(_pcb, NULL, 0);
|
||||||
|
_tcp_clear_events(this);
|
||||||
if(_in_lwip_thread){
|
if(_in_lwip_thread){
|
||||||
err = tcp_close(_pcb);
|
err = tcp_close(_pcb);
|
||||||
} else {
|
} else {
|
||||||
@ -484,6 +561,7 @@ void AsyncClient::_error(int8_t err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) {
|
int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) {
|
||||||
|
_in_lwip_thread = false;
|
||||||
_rx_last_packet = millis();
|
_rx_last_packet = millis();
|
||||||
//log_i("%u", len);
|
//log_i("%u", len);
|
||||||
_pcb_busy = false;
|
_pcb_busy = false;
|
||||||
@ -493,6 +571,14 @@ int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) {
|
int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) {
|
||||||
|
if(!_pcb || pcb != _pcb){
|
||||||
|
log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb);
|
||||||
|
if(pb){
|
||||||
|
pbuf_free(pb);
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
_in_lwip_thread = false;
|
||||||
if(pb == NULL){
|
if(pb == NULL){
|
||||||
return _close();
|
return _close();
|
||||||
}
|
}
|
||||||
@ -504,20 +590,25 @@ int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) {
|
|||||||
//Serial.write((const uint8_t *)pb->payload, pb->len);
|
//Serial.write((const uint8_t *)pb->payload, pb->len);
|
||||||
_ack_pcb = true;
|
_ack_pcb = true;
|
||||||
pbuf *b = pb;
|
pbuf *b = pb;
|
||||||
if(_recv_cb)
|
|
||||||
_recv_cb(_recv_cb_arg, this, b->payload, b->len);
|
|
||||||
if(!_ack_pcb)
|
|
||||||
_rx_ack_len += b->len;
|
|
||||||
else
|
|
||||||
_tcp_recved(pcb, b->len);
|
|
||||||
pb = b->next;
|
pb = b->next;
|
||||||
b->next = NULL;
|
b->next = NULL;
|
||||||
pbuf_free(b);
|
if(_pb_cb){
|
||||||
|
_pb_cb(_pb_cb_arg, this, b);
|
||||||
|
} else {
|
||||||
|
if(_recv_cb)
|
||||||
|
_recv_cb(_recv_cb_arg, this, b->payload, b->len);
|
||||||
|
if(!_ack_pcb)
|
||||||
|
_rx_ack_len += b->len;
|
||||||
|
else
|
||||||
|
_tcp_recved(pcb, b->len);
|
||||||
|
pbuf_free(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_poll(tcp_pcb* pcb){
|
int8_t AsyncClient::_poll(tcp_pcb* pcb){
|
||||||
|
_in_lwip_thread = false;
|
||||||
// Close requested
|
// Close requested
|
||||||
if(_close_pcb){
|
if(_close_pcb){
|
||||||
_close_pcb = false;
|
_close_pcb = false;
|
||||||
@ -546,7 +637,7 @@ int8_t AsyncClient::_poll(tcp_pcb* pcb){
|
|||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncClient::_dns_found(ip_addr_t *ipaddr){
|
void AsyncClient::_dns_found(struct ip_addr *ipaddr){
|
||||||
_in_lwip_thread = true;
|
_in_lwip_thread = true;
|
||||||
if(ipaddr){
|
if(ipaddr){
|
||||||
connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port);
|
connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port);
|
||||||
@ -591,10 +682,12 @@ int8_t AsyncClient::abort(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncClient::close(bool now){
|
void AsyncClient::close(bool now){
|
||||||
if(_in_lwip_thread){
|
if(_pcb){
|
||||||
tcp_recved(_pcb, _rx_ack_len);
|
if(_in_lwip_thread){
|
||||||
} else {
|
tcp_recved(_pcb, _rx_ack_len);
|
||||||
_tcp_recved(_pcb, _rx_ack_len);
|
} else {
|
||||||
|
_tcp_recved(_pcb, _rx_ack_len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(now)
|
if(now)
|
||||||
_close();
|
_close();
|
||||||
@ -814,6 +907,14 @@ bool AsyncClient::canSend(){
|
|||||||
return space() > 0;
|
return space() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncClient::ackPacket(struct pbuf * pb){
|
||||||
|
if(!pb){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_tcp_recved(_pcb, pb->len);
|
||||||
|
pbuf_free(pb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Callback Setters
|
// Callback Setters
|
||||||
|
|
||||||
@ -842,6 +943,11 @@ void AsyncClient::onData(AcDataHandler cb, void* arg){
|
|||||||
_recv_cb_arg = arg;
|
_recv_cb_arg = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncClient::onPacket(AcPacketHandler cb, void* arg){
|
||||||
|
_pb_cb = cb;
|
||||||
|
_pb_cb_arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg){
|
void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg){
|
||||||
_timeout_cb = cb;
|
_timeout_cb = cb;
|
||||||
_timeout_cb_arg = arg;
|
_timeout_cb_arg = arg;
|
||||||
@ -853,31 +959,58 @@ void AsyncClient::onPoll(AcConnectHandler cb, void* arg){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AsyncClient::_s_dns_found(const char * name, ip_addr_t * ipaddr, void * arg){
|
void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){
|
||||||
reinterpret_cast<AsyncClient*>(arg)->_dns_found(ipaddr);
|
if(arg){
|
||||||
|
reinterpret_cast<AsyncClient*>(arg)->_dns_found(ipaddr);
|
||||||
|
} else {
|
||||||
|
log_e("Bad Arg: 0x%08x", arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_s_poll(void * arg, struct tcp_pcb * pcb) {
|
int8_t AsyncClient::_s_poll(void * arg, struct tcp_pcb * pcb) {
|
||||||
reinterpret_cast<AsyncClient*>(arg)->_poll(pcb);
|
if(arg && pcb){
|
||||||
|
reinterpret_cast<AsyncClient*>(arg)->_poll(pcb);
|
||||||
|
} else {
|
||||||
|
log_e("Bad Args: 0x%08x 0x%08x", arg, pcb);
|
||||||
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) {
|
int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) {
|
||||||
reinterpret_cast<AsyncClient*>(arg)->_recv(pcb, pb, err);
|
if(arg && pcb){
|
||||||
|
reinterpret_cast<AsyncClient*>(arg)->_recv(pcb, pb, err);
|
||||||
|
} else {
|
||||||
|
if(pb){
|
||||||
|
pbuf_free(pb);
|
||||||
|
}
|
||||||
|
log_e("Bad Args: 0x%08x 0x%08x", arg, pcb);
|
||||||
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) {
|
int8_t AsyncClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) {
|
||||||
reinterpret_cast<AsyncClient*>(arg)->_sent(pcb, len);
|
if(arg && pcb){
|
||||||
|
reinterpret_cast<AsyncClient*>(arg)->_sent(pcb, len);
|
||||||
|
} else {
|
||||||
|
log_e("Bad Args: 0x%08x 0x%08x", arg, pcb);
|
||||||
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncClient::_s_error(void * arg, int8_t err) {
|
void AsyncClient::_s_error(void * arg, int8_t err) {
|
||||||
reinterpret_cast<AsyncClient*>(arg)->_error(err);
|
if(arg){
|
||||||
|
reinterpret_cast<AsyncClient*>(arg)->_error(err);
|
||||||
|
} else {
|
||||||
|
log_e("Bad Arg: 0x%08x", arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){
|
int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){
|
||||||
reinterpret_cast<AsyncClient*>(arg)->_connected(pcb, err);
|
if(arg && pcb){
|
||||||
|
reinterpret_cast<AsyncClient*>(arg)->_connected(pcb, err);
|
||||||
|
} else {
|
||||||
|
log_e("Bad Args: 0x%08x 0x%08x", arg, pcb);
|
||||||
|
}
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1032,9 +1165,9 @@ void AsyncServer::end(){
|
|||||||
tcp_arg(_pcb, NULL);
|
tcp_arg(_pcb, NULL);
|
||||||
tcp_accept(_pcb, NULL);
|
tcp_accept(_pcb, NULL);
|
||||||
if(_in_lwip_thread){
|
if(_in_lwip_thread){
|
||||||
tcp_abort(_pcb);
|
tcp_close(_pcb);
|
||||||
} else {
|
} else {
|
||||||
_tcp_abort(_pcb);
|
_tcp_close(_pcb);
|
||||||
}
|
}
|
||||||
_pcb = NULL;
|
_pcb = NULL;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
#include "IPAddress.h"
|
#include "IPAddress.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
|
#include "lwip/pbuf.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncClient;
|
class AsyncClient;
|
||||||
@ -38,11 +39,11 @@ typedef std::function<void(void*, AsyncClient*)> AcConnectHandler;
|
|||||||
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)> AcAckHandler;
|
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)> AcAckHandler;
|
||||||
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler;
|
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler;
|
||||||
typedef std::function<void(void*, AsyncClient*, void *data, size_t len)> AcDataHandler;
|
typedef std::function<void(void*, AsyncClient*, void *data, size_t len)> AcDataHandler;
|
||||||
|
typedef std::function<void(void*, AsyncClient*, struct pbuf *pb)> AcPacketHandler;
|
||||||
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler;
|
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler;
|
||||||
|
|
||||||
struct tcp_pcb;
|
struct tcp_pcb;
|
||||||
struct pbuf;
|
struct ip_addr;
|
||||||
struct _ip_addr;
|
|
||||||
|
|
||||||
class AsyncClient {
|
class AsyncClient {
|
||||||
protected:
|
protected:
|
||||||
@ -58,6 +59,8 @@ class AsyncClient {
|
|||||||
void* _error_cb_arg;
|
void* _error_cb_arg;
|
||||||
AcDataHandler _recv_cb;
|
AcDataHandler _recv_cb;
|
||||||
void* _recv_cb_arg;
|
void* _recv_cb_arg;
|
||||||
|
AcPacketHandler _pb_cb;
|
||||||
|
void* _pb_cb_arg;
|
||||||
AcTimeoutHandler _timeout_cb;
|
AcTimeoutHandler _timeout_cb;
|
||||||
void* _timeout_cb_arg;
|
void* _timeout_cb_arg;
|
||||||
AcConnectHandler _poll_cb;
|
AcConnectHandler _poll_cb;
|
||||||
@ -78,7 +81,7 @@ class AsyncClient {
|
|||||||
void _error(int8_t err);
|
void _error(int8_t err);
|
||||||
int8_t _poll(tcp_pcb* pcb);
|
int8_t _poll(tcp_pcb* pcb);
|
||||||
int8_t _sent(tcp_pcb* pcb, uint16_t len);
|
int8_t _sent(tcp_pcb* pcb, uint16_t len);
|
||||||
void _dns_found(struct _ip_addr *ipaddr);
|
void _dns_found(struct ip_addr *ipaddr);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -105,13 +108,13 @@ class AsyncClient {
|
|||||||
|
|
||||||
bool canSend();//ack is not pending
|
bool canSend();//ack is not pending
|
||||||
size_t space();
|
size_t space();
|
||||||
size_t add(const char* data, size_t size, uint8_t apiflags=0);//add for sending
|
size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending
|
||||||
bool send();//send all data added with the method above
|
bool send();//send all data added with the method above
|
||||||
size_t ack(size_t len); //ack data that you have not acked using the method below
|
size_t ack(size_t len); //ack data that you have not acked using the method below
|
||||||
void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData
|
void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData
|
||||||
|
|
||||||
size_t write(const char* data);
|
size_t write(const char* data);
|
||||||
size_t write(const char* data, size_t size, uint8_t apiflags=0); //only when canSend() == true
|
size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true
|
||||||
|
|
||||||
uint8_t state();
|
uint8_t state();
|
||||||
bool connecting();
|
bool connecting();
|
||||||
@ -141,10 +144,13 @@ class AsyncClient {
|
|||||||
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected
|
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected
|
||||||
void onAck(AcAckHandler cb, void* arg = 0); //ack received
|
void onAck(AcAckHandler cb, void* arg = 0); //ack received
|
||||||
void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error
|
void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error
|
||||||
void onData(AcDataHandler cb, void* arg = 0); //data received
|
void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used)
|
||||||
|
void onPacket(AcPacketHandler cb, void* arg = 0); //data received
|
||||||
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout
|
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout
|
||||||
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected
|
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected
|
||||||
|
|
||||||
|
void ackPacket(struct pbuf * pb);
|
||||||
|
|
||||||
const char * errorToString(int8_t error);
|
const char * errorToString(int8_t error);
|
||||||
const char * stateToString();
|
const char * stateToString();
|
||||||
|
|
||||||
@ -155,7 +161,7 @@ class AsyncClient {
|
|||||||
static void _s_error(void *arg, int8_t err);
|
static void _s_error(void *arg, int8_t err);
|
||||||
static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len);
|
static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len);
|
||||||
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
|
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
|
||||||
static void _s_dns_found(const char *name, struct _ip_addr *ipaddr, void *arg);
|
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg);
|
||||||
|
|
||||||
bool _in_lwip_thread;
|
bool _in_lwip_thread;
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,8 @@ To use this library you might need to have the latest git versions of [ESP32](ht
|
|||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
- [ESPAsyncWebServer ](#espasyncwebserver-)
|
- [ESPAsyncWebServer ](#espasyncwebserver-)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Using PlatformIO](#using-platformio)
|
||||||
- [Why should you care](#why-should-you-care)
|
- [Why should you care](#why-should-you-care)
|
||||||
- [Important things to remember](#important-things-to-remember)
|
- [Important things to remember](#important-things-to-remember)
|
||||||
- [Principles of operation](#principles-of-operation)
|
- [Principles of operation](#principles-of-operation)
|
||||||
@ -28,6 +30,7 @@ To use this library you might need to have the latest git versions of [ESP32](ht
|
|||||||
- [GET, POST and FILE parameters](#get-post-and-file-parameters)
|
- [GET, POST and FILE parameters](#get-post-and-file-parameters)
|
||||||
- [FILE Upload handling](#file-upload-handling)
|
- [FILE Upload handling](#file-upload-handling)
|
||||||
- [Body data handling](#body-data-handling)
|
- [Body data handling](#body-data-handling)
|
||||||
|
- [JSON body handling with ArduinoJson](#json-body-handling-with-arduinojson)
|
||||||
- [Responses](#responses)
|
- [Responses](#responses)
|
||||||
- [Redirect to another URL](#redirect-to-another-url)
|
- [Redirect to another URL](#redirect-to-another-url)
|
||||||
- [Basic response with HTTP Code](#basic-response-with-http-code)
|
- [Basic response with HTTP Code](#basic-response-with-http-code)
|
||||||
@ -78,6 +81,33 @@ To use this library you might need to have the latest git versions of [ESP32](ht
|
|||||||
- [Setup global and class functions as request handlers](#setup-global-and-class-functions-as-request-handlers)
|
- [Setup global and class functions as request handlers](#setup-global-and-class-functions-as-request-handlers)
|
||||||
- [Methods for controlling websocket connections](#methods-for-controlling-websocket-connections)
|
- [Methods for controlling websocket connections](#methods-for-controlling-websocket-connections)
|
||||||
- [Adding default headers to all responses](#adding-default-headers)
|
- [Adding default headers to all responses](#adding-default-headers)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Using PlatformIO
|
||||||
|
|
||||||
|
[PlatformIO](http://platformio.org) is an open source ecosystem for IoT development with cross platform build system, library manager and full support for Espressif ESP8266/ESP32 development. It works on the popular host OS: Mac OS X, Windows, Linux 32/64, Linux ARM (like Raspberry Pi, BeagleBone, CubieBoard).
|
||||||
|
|
||||||
|
1. Install [PlatformIO IDE](http://platformio.org/platformio-ide)
|
||||||
|
2. Create new project using "PlatformIO Home > New Project"
|
||||||
|
3. Update dev/platform to staging version:
|
||||||
|
- [Instruction for Espressif 8266](http://docs.platformio.org/en/latest/platforms/espressif8266.html#using-arduino-framework-with-staging-version)
|
||||||
|
- [Instruction for Espressif 32](http://docs.platformio.org/en/latest/platforms/espressif32.html#using-arduino-framework-with-staging-version)
|
||||||
|
4. Add "ESP Async WebServer" to project using [Project Configuration File `platformio.ini`](http://docs.platformio.org/page/projectconf.html) and [lib_deps](http://docs.platformio.org/page/projectconf/section_env_library.html#lib-deps) option:
|
||||||
|
```ini
|
||||||
|
[env:myboard]
|
||||||
|
platform = espressif...
|
||||||
|
board = ...
|
||||||
|
framework = arduino
|
||||||
|
|
||||||
|
# using the latest stable version
|
||||||
|
lib_deps = ESP Async WebServer
|
||||||
|
|
||||||
|
# or using GIT Url (the latest development version)
|
||||||
|
lib_deps = https://github.com/me-no-dev/ESPAsyncWebServer.git
|
||||||
|
```
|
||||||
|
5. Happy coding with PlatformIO!
|
||||||
|
|
||||||
## Why should you care
|
## Why should you care
|
||||||
- Using asynchronous network means that you can handle more than one connection at the same time
|
- Using asynchronous network means that you can handle more than one connection at the same time
|
||||||
- You are called once the request is ready and parsed
|
- You are called once the request is ready and parsed
|
||||||
@ -284,6 +314,20 @@ void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
If needed, the `_tempObject` field on the request can be used to store a pointer to temporary data (e.g. from the body) associated with the request. If assigned, the pointer will automatically be freed along with the request.
|
||||||
|
|
||||||
|
### JSON body handling with ArduinoJson
|
||||||
|
Endpoints which consume JSON can use a special handler to get ready to use JSON data in the request callback:
|
||||||
|
```cpp
|
||||||
|
#include "AsyncJson.h"
|
||||||
|
#include "ArduinoJson.h"
|
||||||
|
|
||||||
|
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint", [](AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
|
JsonObject& jsonObj = json.as<JsonObject>();
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
server.addHandler(handler);
|
||||||
|
```
|
||||||
|
|
||||||
## Responses
|
## Responses
|
||||||
### Redirect to another URL
|
### Redirect to another URL
|
||||||
@ -688,7 +732,7 @@ This way of sending Json is great for when the result is below 4KB
|
|||||||
#include "ArduinoJson.h"
|
#include "ArduinoJson.h"
|
||||||
|
|
||||||
|
|
||||||
AsyncResponseStream *response = request->beginResponseStream("text/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
DynamicJsonBuffer jsonBuffer;
|
DynamicJsonBuffer jsonBuffer;
|
||||||
JsonObject &root = jsonBuffer.createObject();
|
JsonObject &root = jsonBuffer.createObject();
|
||||||
root["heap"] = ESP.getFreeHeap();
|
root["heap"] = ESP.getFreeHeap();
|
||||||
@ -942,7 +986,7 @@ ws.printfAll(arguments...);
|
|||||||
//printf_P to a client
|
//printf_P to a client
|
||||||
ws.printf_P((uint32_t)client_id, PSTR(format), arguments...);
|
ws.printf_P((uint32_t)client_id, PSTR(format), arguments...);
|
||||||
//printfAll_P to all clients
|
//printfAll_P to all clients
|
||||||
ws.printf_P(PSTR(format), arguments...);
|
ws.printfAll_P(PSTR(format), arguments...);
|
||||||
//send text to a client
|
//send text to a client
|
||||||
ws.text((uint32_t)client_id, (char*)text);
|
ws.text((uint32_t)client_id, (char*)text);
|
||||||
ws.text((uint32_t)client_id, (uint8_t*)text, (size_t)len);
|
ws.text((uint32_t)client_id, (uint8_t*)text, (size_t)len);
|
||||||
@ -1097,7 +1141,7 @@ server.on("/scan", HTTP_GET, [](AsyncWebServerRequest *request){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
json += "]";
|
json += "]";
|
||||||
request->send(200, "text/json", json);
|
request->send(200, "application/json", json);
|
||||||
json = String();
|
json = String();
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"name":"ESPAsyncWebServer",
|
|
||||||
"description":"Asynchronous HTTP and WebSocket Server Library for ESP8266",
|
|
||||||
"keywords":"http,async,websocket,webserver",
|
|
||||||
"authors":
|
|
||||||
{
|
|
||||||
"name": "Hristo Gochkov",
|
|
||||||
"maintainer": true
|
|
||||||
},
|
|
||||||
"repository":
|
|
||||||
{
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/me-no-dev/ESPAsyncWebServer.git"
|
|
||||||
},
|
|
||||||
"version": "1.1.0",
|
|
||||||
"license": "LGPL-3.0",
|
|
||||||
"frameworks": "arduino",
|
|
||||||
"platforms": ["espressif8266", "espressif8266_stage"],
|
|
||||||
"dependencies":
|
|
||||||
{
|
|
||||||
"name": "ESPAsyncTCP"
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,7 @@
|
|||||||
#include <ESPAsyncTCP.h>
|
#include <ESPAsyncTCP.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SPIFFSEditor.h>
|
#include <SPIFFSEditor.h>
|
||||||
#include <ESP8266SSDP.h>
|
|
||||||
// SKETCH BEGIN
|
// SKETCH BEGIN
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
AsyncWebSocket ws("/ws");
|
AsyncWebSocket ws("/ws");
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
//
|
||||||
|
// A simple server implementation showing how to:
|
||||||
|
// * serve static messages
|
||||||
|
// * read GET and POST parameters
|
||||||
|
// * handle missing pages / 404s
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <Hash.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
const char* ssid = "YOUR_SSID";
|
||||||
|
const char* password = "YOUR_PASSWORD";
|
||||||
|
|
||||||
|
const char* PARAM_MESSAGE = "message";
|
||||||
|
|
||||||
|
void notFound(AsyncWebServerRequest *request) {
|
||||||
|
request->send(404, "text/plain", "Not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||||
|
Serial.printf("WiFi Failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
Serial.print("Hostname: ");
|
||||||
|
Serial.println(WiFi.hostname());
|
||||||
|
|
||||||
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", "Hello, world");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a GET request to <IP>/get?message=<message>
|
||||||
|
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
||||||
|
String message;
|
||||||
|
if (request->hasParam(PARAM_MESSAGE)) {
|
||||||
|
message = request->getParam(PARAM_MESSAGE)->value();
|
||||||
|
} else {
|
||||||
|
message = "No message sent";
|
||||||
|
}
|
||||||
|
request->send(200, "text/plain", "Hello, GET: " + message);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send a POST request to <IP>/post with a form field message set to <message>
|
||||||
|
server.on("/post", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
String message;
|
||||||
|
if (request->hasParam(PARAM_MESSAGE, true)) {
|
||||||
|
message = request->getParam(PARAM_MESSAGE, true)->value();
|
||||||
|
} else {
|
||||||
|
message = "No message sent";
|
||||||
|
}
|
||||||
|
request->send(200, "text/plain", "Hello, POST: " + message);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.onNotFound(notFound);
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name":"AsyncWebServer",
|
"name":"ESP Async WebServer",
|
||||||
"description":"Asynchronous HTTP and WebSocket Server Library for ESP32",
|
"description":"Asynchronous HTTP and WebSocket Server Library for ESP8266 and ESP32",
|
||||||
"keywords":"http,async,websocket,webserver",
|
"keywords":"http,async,websocket,webserver",
|
||||||
"authors":
|
"authors":
|
||||||
{
|
{
|
||||||
@ -12,12 +12,18 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/me-no-dev/ESPAsyncWebServer.git"
|
"url": "https://github.com/me-no-dev/ESPAsyncWebServer.git"
|
||||||
},
|
},
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
"frameworks": "arduino",
|
"frameworks": "arduino",
|
||||||
"platforms": ["espressif32", "espressif32_stage"],
|
"platforms": ["espressif8266", "espressif32"],
|
||||||
"dependencies":
|
"dependencies": [
|
||||||
{
|
{
|
||||||
"name": "AsyncTCP"
|
"name": "ESPAsyncTCP",
|
||||||
}
|
"platforms": "espressif8266"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AsyncTCP",
|
||||||
|
"platforms": "espressif32"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
name=ESP Async WebServer
|
name=ESP Async WebServer
|
||||||
version=1.1.0
|
version=1.2.0
|
||||||
author=Me-No-Dev
|
author=Me-No-Dev
|
||||||
maintainer=Me-No-Dev
|
maintainer=Me-No-Dev
|
||||||
sentence=Async Web Server for ESP8266 and ESP31B
|
sentence=Async Web Server for ESP8266 and ESP31B
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// ESPasyncJson.h
|
// AsyncJson.h
|
||||||
/*
|
/*
|
||||||
Async Response to use with arduinoJson and asyncwebserver
|
Async Response to use with ArduinoJson and AsyncWebServer
|
||||||
Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon.
|
Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon.
|
||||||
|
|
||||||
example of callback in use
|
Example of callback in use
|
||||||
|
|
||||||
server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) {
|
server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) {
|
||||||
|
|
||||||
@ -17,11 +17,27 @@
|
|||||||
request->send(response);
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Async Request to use with ArduinoJson and AsyncWebServer
|
||||||
|
Written by Arsène von Wyss (avonwyss)
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint");
|
||||||
|
handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
|
JsonObject& jsonObj = json.as<JsonObject>();
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
server.addHandler(handler);
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#ifndef ASYNC_JSON_H_
|
#ifndef ASYNC_JSON_H_
|
||||||
#define ASYNC_JSON_H_
|
#define ASYNC_JSON_H_
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
constexpr char* JSON_MIMETYPE = "application/json";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Json Response
|
* Json Response
|
||||||
* */
|
* */
|
||||||
@ -57,7 +73,7 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
|
|||||||
public:
|
public:
|
||||||
AsyncJsonResponse(bool isArray=false): _isValid{false} {
|
AsyncJsonResponse(bool isArray=false): _isValid{false} {
|
||||||
_code = 200;
|
_code = 200;
|
||||||
_contentType = "text/json";
|
_contentType = JSON_MIMETYPE;
|
||||||
if(isArray)
|
if(isArray)
|
||||||
_root = _jsonBuffer.createArray();
|
_root = _jsonBuffer.createArray();
|
||||||
else
|
else
|
||||||
@ -80,4 +96,68 @@ class AsyncJsonResponse: public AsyncAbstractResponse {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::function<void(AsyncWebServerRequest *request, JsonVariant &json)> ArJsonRequestHandlerFunction;
|
||||||
|
|
||||||
|
class AsyncCallbackJsonWebHandler: public AsyncWebHandler {
|
||||||
|
private:
|
||||||
|
protected:
|
||||||
|
const String _uri;
|
||||||
|
WebRequestMethodComposite _method;
|
||||||
|
ArJsonRequestHandlerFunction _onRequest;
|
||||||
|
int _contentLength;
|
||||||
|
int _maxContentLength;
|
||||||
|
public:
|
||||||
|
AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {}
|
||||||
|
void setMethod(WebRequestMethodComposite method){ _method = method; }
|
||||||
|
void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; }
|
||||||
|
void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; }
|
||||||
|
|
||||||
|
virtual bool canHandle(AsyncWebServerRequest *request) override final{
|
||||||
|
if(!_onRequest)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!(_method & request->method()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!request->contentType().equalsIgnoreCase(JSON_MIMETYPE))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
request->addInterestingHeader("ANY");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handleRequest(AsyncWebServerRequest *request) override final {
|
||||||
|
if(_onRequest) {
|
||||||
|
if (request->_tempObject != NULL) {
|
||||||
|
DynamicJsonBuffer jsonBuffer;
|
||||||
|
JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject));
|
||||||
|
if (json.success()) {
|
||||||
|
_onRequest(request, json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request->send(_contentLength > _maxContentLength ? 413 : 400);
|
||||||
|
} else {
|
||||||
|
request->send(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final {
|
||||||
|
}
|
||||||
|
virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final {
|
||||||
|
if (_onRequest) {
|
||||||
|
_contentLength = total;
|
||||||
|
if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) {
|
||||||
|
request->_tempObject = malloc(total);
|
||||||
|
}
|
||||||
|
if (request->_tempObject != NULL) {
|
||||||
|
memcpy((uint8_t*)(request->_tempObject) + index, data, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -146,7 +146,7 @@ AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(uint8_t * data, size_t
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_data = new uint8_t[size + 1];
|
_data = new uint8_t[_len + 1];
|
||||||
|
|
||||||
if (_data) {
|
if (_data) {
|
||||||
memcpy(_data, data, _len);
|
memcpy(_data, data, _len);
|
||||||
@ -224,10 +224,10 @@ bool AsyncWebSocketMessageBuffer::reserve(size_t size)
|
|||||||
_data = nullptr;
|
_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_data = new uint8_t[size];
|
_data = new uint8_t[_len + 1];
|
||||||
|
|
||||||
if (_data) {
|
if (_data) {
|
||||||
_data[_len] = 0;
|
_data[_len] = 0;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -337,14 +337,31 @@ AsyncWebSocketBasicMessage::~AsyncWebSocketBasicMessage() {
|
|||||||
_status = WS_MSG_SENT;
|
_status = WS_MSG_SENT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t window = webSocketSendFrameWindow(client);
|
if(_sent > _len){
|
||||||
|
_status = WS_MSG_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t toSend = _len - _sent;
|
size_t toSend = _len - _sent;
|
||||||
if(window < toSend) toSend = window;
|
size_t window = webSocketSendFrameWindow(client);
|
||||||
bool final = ((toSend + _sent) == _len);
|
|
||||||
size_t sent = webSocketSendFrame(client, final, (_sent == 0)?_opcode:(int)WS_CONTINUATION, _mask, (uint8_t*)(_data+_sent), toSend);
|
if(window < toSend) {
|
||||||
_sent += sent;
|
toSend = window;
|
||||||
uint8_t headLen = ((sent < 126)?2:4)+(_mask*4);
|
}
|
||||||
_ack += sent + headLen;
|
|
||||||
|
_sent += toSend;
|
||||||
|
_ack += toSend + ((toSend < 126)?2:4) + (_mask * 4);
|
||||||
|
|
||||||
|
bool final = (_sent == _len);
|
||||||
|
uint8_t* dPtr = (uint8_t*)(_data + (_sent - toSend));
|
||||||
|
uint8_t opCode = (toSend && _sent == toSend)?_opcode:(uint8_t)WS_CONTINUATION;
|
||||||
|
|
||||||
|
size_t sent = webSocketSendFrame(client, final, opCode, _mask, dPtr, toSend);
|
||||||
|
_status = WS_MSG_SENDING;
|
||||||
|
if(toSend && sent != toSend){
|
||||||
|
_sent -= (toSend - sent);
|
||||||
|
_ack -= (toSend - sent);
|
||||||
|
}
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +401,7 @@ AsyncWebSocketMultiMessage::AsyncWebSocketMultiMessage(AsyncWebSocketMessageBuff
|
|||||||
_data = buffer->get();
|
_data = buffer->get();
|
||||||
_len = buffer->length();
|
_len = buffer->length();
|
||||||
_status = WS_MSG_SENDING;
|
_status = WS_MSG_SENDING;
|
||||||
|
//ets_printf("M: %u\n", _len);
|
||||||
} else {
|
} else {
|
||||||
_status = WS_MSG_ERROR;
|
_status = WS_MSG_ERROR;
|
||||||
}
|
}
|
||||||
@ -399,9 +417,10 @@ AsyncWebSocketMultiMessage::~AsyncWebSocketMultiMessage() {
|
|||||||
|
|
||||||
void AsyncWebSocketMultiMessage::ack(size_t len, uint32_t time) {
|
void AsyncWebSocketMultiMessage::ack(size_t len, uint32_t time) {
|
||||||
_acked += len;
|
_acked += len;
|
||||||
if(_sent == _len && _acked == _ack){
|
if(_sent >= _len && _acked >= _ack){
|
||||||
_status = WS_MSG_SENT;
|
_status = WS_MSG_SENT;
|
||||||
}
|
}
|
||||||
|
//ets_printf("A: %u\n", len);
|
||||||
}
|
}
|
||||||
size_t AsyncWebSocketMultiMessage::send(AsyncClient *client) {
|
size_t AsyncWebSocketMultiMessage::send(AsyncClient *client) {
|
||||||
if(_status != WS_MSG_SENDING)
|
if(_status != WS_MSG_SENDING)
|
||||||
@ -410,18 +429,39 @@ AsyncWebSocketMultiMessage::~AsyncWebSocketMultiMessage() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(_sent == _len){
|
if(_sent == _len){
|
||||||
if(_acked == _ack)
|
_status = WS_MSG_SENT;
|
||||||
_status = WS_MSG_SENT;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size_t window = webSocketSendFrameWindow(client);
|
if(_sent > _len){
|
||||||
|
_status = WS_MSG_ERROR;
|
||||||
|
//ets_printf("E: %u > %u\n", _sent, _len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t toSend = _len - _sent;
|
size_t toSend = _len - _sent;
|
||||||
if(window < toSend) toSend = window;
|
size_t window = webSocketSendFrameWindow(client);
|
||||||
bool final = ((toSend + _sent) == _len);
|
|
||||||
size_t sent = webSocketSendFrame(client, final, (_sent == 0)?_opcode:(int)WS_CONTINUATION, _mask, (uint8_t*)(_data+_sent), toSend);
|
if(window < toSend) {
|
||||||
_sent += sent;
|
toSend = window;
|
||||||
uint8_t headLen = ((sent < 126)?2:4)+(_mask*4);
|
}
|
||||||
_ack += sent + headLen;
|
|
||||||
|
_sent += toSend;
|
||||||
|
_ack += toSend + ((toSend < 126)?2:4) + (_mask * 4);
|
||||||
|
|
||||||
|
//ets_printf("W: %u %u\n", _sent - toSend, toSend);
|
||||||
|
|
||||||
|
bool final = (_sent == _len);
|
||||||
|
uint8_t* dPtr = (uint8_t*)(_data + (_sent - toSend));
|
||||||
|
uint8_t opCode = (toSend && _sent == toSend)?_opcode:(uint8_t)WS_CONTINUATION;
|
||||||
|
|
||||||
|
size_t sent = webSocketSendFrame(client, final, opCode, _mask, dPtr, toSend);
|
||||||
|
_status = WS_MSG_SENDING;
|
||||||
|
if(toSend && sent != toSend){
|
||||||
|
//ets_printf("E: %u != %u\n", toSend, sent);
|
||||||
|
_sent -= (toSend - sent);
|
||||||
|
_ack -= (toSend - sent);
|
||||||
|
}
|
||||||
|
//ets_printf("S: %u %u\n", _sent, sent);
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,7 +551,12 @@ void AsyncWebSocketClient::_queueMessage(AsyncWebSocketMessage *dataMessage){
|
|||||||
delete dataMessage;
|
delete dataMessage;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_messageQueue.add(dataMessage);
|
if(_messageQueue.length() > WS_MAX_QUEUED_MESSAGES){
|
||||||
|
ets_printf("ERROR: Too many messages queued\n");
|
||||||
|
delete dataMessage;
|
||||||
|
} else {
|
||||||
|
_messageQueue.add(dataMessage);
|
||||||
|
}
|
||||||
if(_client->canSend())
|
if(_client->canSend())
|
||||||
_runQueue();
|
_runQueue();
|
||||||
}
|
}
|
||||||
@ -565,83 +610,93 @@ void AsyncWebSocketClient::_onDisconnect(){
|
|||||||
_server->_handleDisconnect(this);
|
_server->_handleDisconnect(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebSocketClient::_onData(void *buf, size_t plen){
|
void AsyncWebSocketClient::_onData(void *pbuf, size_t plen){
|
||||||
_lastMessageTime = millis();
|
_lastMessageTime = millis();
|
||||||
uint8_t *fdata = (uint8_t*)buf;
|
uint8_t *data = (uint8_t*)pbuf;
|
||||||
uint8_t * data = fdata;
|
while(plen > 0){
|
||||||
if(!_pstate){
|
if(!_pstate){
|
||||||
_pinfo.index = 0;
|
const uint8_t *fdata = data;
|
||||||
_pinfo.final = (fdata[0] & 0x80) != 0;
|
_pinfo.index = 0;
|
||||||
_pinfo.opcode = fdata[0] & 0x0F;
|
_pinfo.final = (fdata[0] & 0x80) != 0;
|
||||||
_pinfo.masked = (fdata[1] & 0x80) != 0;
|
_pinfo.opcode = fdata[0] & 0x0F;
|
||||||
_pinfo.len = fdata[1] & 0x7F;
|
_pinfo.masked = (fdata[1] & 0x80) != 0;
|
||||||
data += 2;
|
_pinfo.len = fdata[1] & 0x7F;
|
||||||
plen = plen - 2;
|
|
||||||
if(_pinfo.len == 126){
|
|
||||||
_pinfo.len = fdata[3] | (uint16_t)(fdata[2]) << 8;
|
|
||||||
data += 2;
|
data += 2;
|
||||||
plen = plen - 2;
|
plen -= 2;
|
||||||
} else if(_pinfo.len == 127){
|
if(_pinfo.len == 126){
|
||||||
_pinfo.len = fdata[9] | (uint16_t)(fdata[8]) << 8 | (uint32_t)(fdata[7]) << 16 | (uint32_t)(fdata[6]) << 24 | (uint64_t)(fdata[5]) << 32 | (uint64_t)(fdata[4]) << 40 | (uint64_t)(fdata[3]) << 48 | (uint64_t)(fdata[2]) << 56;
|
_pinfo.len = fdata[3] | (uint16_t)(fdata[2]) << 8;
|
||||||
data += 8;
|
data += 2;
|
||||||
plen = plen - 8;
|
plen -= 2;
|
||||||
|
} else if(_pinfo.len == 127){
|
||||||
|
_pinfo.len = fdata[9] | (uint16_t)(fdata[8]) << 8 | (uint32_t)(fdata[7]) << 16 | (uint32_t)(fdata[6]) << 24 | (uint64_t)(fdata[5]) << 32 | (uint64_t)(fdata[4]) << 40 | (uint64_t)(fdata[3]) << 48 | (uint64_t)(fdata[2]) << 56;
|
||||||
|
data += 8;
|
||||||
|
plen -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_pinfo.masked){
|
||||||
|
memcpy(_pinfo.mask, data, 4);
|
||||||
|
data += 4;
|
||||||
|
plen -= 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const size_t datalen = std::min((size_t)(_pinfo.len - _pinfo.index), plen);
|
||||||
|
const auto datalast = data[datalen];
|
||||||
|
|
||||||
if(_pinfo.masked){
|
if(_pinfo.masked){
|
||||||
memcpy(_pinfo.mask, data, 4);
|
for(size_t i=0;i<datalen;i++)
|
||||||
data += 4;
|
data[i] ^= _pinfo.mask[(_pinfo.index+i)%4];
|
||||||
plen = plen - 4;
|
|
||||||
size_t i;
|
|
||||||
for(i=0;i<plen;i++)
|
|
||||||
data[i] = data[i] ^ _pinfo.mask[(_pinfo.index+i)%4];
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if(_pinfo.masked){
|
|
||||||
size_t i;
|
|
||||||
for(i=0;i<plen;i++)
|
|
||||||
data[i] = data[i] ^ _pinfo.mask[(_pinfo.index+i)%4];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((plen + _pinfo.index) < _pinfo.len){
|
|
||||||
_pstate = 1;
|
|
||||||
|
|
||||||
if(_pinfo.index == 0){
|
if((datalen + _pinfo.index) < _pinfo.len){
|
||||||
if(_pinfo.opcode){
|
_pstate = 1;
|
||||||
_pinfo.message_opcode = _pinfo.opcode;
|
|
||||||
_pinfo.num = 0;
|
|
||||||
} else _pinfo.num += 1;
|
|
||||||
}
|
|
||||||
_server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, (uint8_t*)data, plen);
|
|
||||||
|
|
||||||
_pinfo.index += plen;
|
if(_pinfo.index == 0){
|
||||||
} else if((plen + _pinfo.index) == _pinfo.len){
|
if(_pinfo.opcode){
|
||||||
_pstate = 0;
|
_pinfo.message_opcode = _pinfo.opcode;
|
||||||
if(_pinfo.opcode == WS_DISCONNECT){
|
_pinfo.num = 0;
|
||||||
if(plen){
|
} else _pinfo.num += 1;
|
||||||
uint16_t reasonCode = (uint16_t)(data[0] << 8) + data[1];
|
}
|
||||||
char * reasonString = (char*)(data+2);
|
_server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, (uint8_t*)data, datalen);
|
||||||
if(reasonCode > 1001){
|
|
||||||
_server->_handleEvent(this, WS_EVT_ERROR, (void *)&reasonCode, (uint8_t*)reasonString, strlen(reasonString));
|
_pinfo.index += datalen;
|
||||||
|
} else if((datalen + _pinfo.index) == _pinfo.len){
|
||||||
|
_pstate = 0;
|
||||||
|
if(_pinfo.opcode == WS_DISCONNECT){
|
||||||
|
if(datalen){
|
||||||
|
uint16_t reasonCode = (uint16_t)(data[0] << 8) + data[1];
|
||||||
|
char * reasonString = (char*)(data+2);
|
||||||
|
if(reasonCode > 1001){
|
||||||
|
_server->_handleEvent(this, WS_EVT_ERROR, (void *)&reasonCode, (uint8_t*)reasonString, strlen(reasonString));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if(_status == WS_DISCONNECTING){
|
||||||
|
_status = WS_DISCONNECTED;
|
||||||
|
_client->close(true);
|
||||||
|
} else {
|
||||||
|
_status = WS_DISCONNECTING;
|
||||||
|
_queueControl(new AsyncWebSocketControl(WS_DISCONNECT, data, datalen));
|
||||||
|
}
|
||||||
|
} else if(_pinfo.opcode == WS_PING){
|
||||||
|
_queueControl(new AsyncWebSocketControl(WS_PONG, data, datalen));
|
||||||
|
} else if(_pinfo.opcode == WS_PONG){
|
||||||
|
if(datalen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0)
|
||||||
|
_server->_handleEvent(this, WS_EVT_PONG, NULL, data, datalen);
|
||||||
|
} else if(_pinfo.opcode < 8){//continuation or text/binary frame
|
||||||
|
_server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, data, datalen);
|
||||||
}
|
}
|
||||||
if(_status == WS_DISCONNECTING){
|
} else {
|
||||||
_status = WS_DISCONNECTED;
|
//os_printf("frame error: len: %u, index: %llu, total: %llu\n", datalen, _pinfo.index, _pinfo.len);
|
||||||
_client->close(true);
|
//what should we do?
|
||||||
} else {
|
break;
|
||||||
_status = WS_DISCONNECTING;
|
|
||||||
_queueControl(new AsyncWebSocketControl(WS_DISCONNECT, data, plen));
|
|
||||||
}
|
|
||||||
} else if(_pinfo.opcode == WS_PING){
|
|
||||||
_queueControl(new AsyncWebSocketControl(WS_PONG, data, plen));
|
|
||||||
} else if(_pinfo.opcode == WS_PONG){
|
|
||||||
if(plen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0)
|
|
||||||
_server->_handleEvent(this, WS_EVT_PONG, NULL, (uint8_t*)data, plen);
|
|
||||||
} else if(_pinfo.opcode < 8){//continuation or text/binary frame
|
|
||||||
_server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, (uint8_t*)data, plen);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
//os_printf("frame error: len: %u, index: %llu, total: %llu\n", plen, _pinfo.index, _pinfo.len);
|
// restore byte as _handleEvent may have added a null terminator i.e., data[len] = 0;
|
||||||
//what should we do?
|
if (datalen > 0)
|
||||||
|
data[datalen] = datalast;
|
||||||
|
|
||||||
|
data += datalen;
|
||||||
|
plen -= datalen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,8 +928,9 @@ void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer * buffer){
|
|||||||
if (!buffer) return;
|
if (!buffer) return;
|
||||||
buffer->lock();
|
buffer->lock();
|
||||||
for(const auto& c: _clients){
|
for(const auto& c: _clients){
|
||||||
if(c->status() == WS_CONNECTED)
|
if(c->status() == WS_CONNECTED){
|
||||||
c->text(buffer);
|
c->text(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buffer->unlock();
|
buffer->unlock();
|
||||||
_cleanBuffers();
|
_cleanBuffers();
|
||||||
@ -946,7 +1002,7 @@ size_t AsyncWebSocket::printfAll(const char *format, ...) {
|
|||||||
va_end(arg);
|
va_end(arg);
|
||||||
delete[] temp;
|
delete[] temp;
|
||||||
|
|
||||||
AsyncWebSocketMessageBuffer * buffer = makeBuffer(len + 1);
|
AsyncWebSocketMessageBuffer * buffer = makeBuffer(len);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1140,9 +1196,10 @@ AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(uint8_t * data, size_t
|
|||||||
|
|
||||||
void AsyncWebSocket::_cleanBuffers()
|
void AsyncWebSocket::_cleanBuffers()
|
||||||
{
|
{
|
||||||
for(const auto& c: _buffers){
|
for(AsyncWebSocketMessageBuffer * c: _buffers){
|
||||||
if(c->canDelete())
|
if(c && c->canDelete()){
|
||||||
_buffers.remove(c);
|
_buffers.remove(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,10 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
|
#define WS_MAX_QUEUED_MESSAGES 32
|
||||||
#else
|
#else
|
||||||
#include <ESPAsyncTCP.h>
|
#include <ESPAsyncTCP.h>
|
||||||
|
#define WS_MAX_QUEUED_MESSAGES 8
|
||||||
#endif
|
#endif
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
@ -35,13 +37,26 @@ class AsyncWebSocketClient;
|
|||||||
class AsyncWebSocketControl;
|
class AsyncWebSocketControl;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/** Message type as defined by enum AwsFrameType.
|
||||||
|
* Note: Applications will only see WS_TEXT and WS_BINARY.
|
||||||
|
* All other types are handled by the library. */
|
||||||
uint8_t message_opcode;
|
uint8_t message_opcode;
|
||||||
|
/** Frame number of a fragmented message. */
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
|
/** Is this the last frame in a fragmented message ?*/
|
||||||
uint8_t final;
|
uint8_t final;
|
||||||
|
/** Is this frame masked? */
|
||||||
uint8_t masked;
|
uint8_t masked;
|
||||||
|
/** Message type as defined by enum AwsFrameType.
|
||||||
|
* This value is the same as message_opcode for non-fragmented
|
||||||
|
* messages, but may also be WS_CONTINUATION in a fragmented message. */
|
||||||
uint8_t opcode;
|
uint8_t opcode;
|
||||||
|
/** Length of the current frame.
|
||||||
|
* This equals the total length of the message if num == 0 && final == true */
|
||||||
uint64_t len;
|
uint64_t len;
|
||||||
|
/** Mask key */
|
||||||
uint8_t mask[4];
|
uint8_t mask[4];
|
||||||
|
/** Offset of the data inside the current frame. */
|
||||||
uint64_t index;
|
uint64_t index;
|
||||||
} AwsFrameInfo;
|
} AwsFrameInfo;
|
||||||
|
|
||||||
@ -154,6 +169,8 @@ class AsyncWebSocketClient {
|
|||||||
uint32_t id(){ return _clientId; }
|
uint32_t id(){ return _clientId; }
|
||||||
AwsClientStatus status(){ return _status; }
|
AwsClientStatus status(){ return _status; }
|
||||||
AsyncClient* client(){ return _client; }
|
AsyncClient* client(){ return _client; }
|
||||||
|
AsyncWebSocket *server(){ return _server; }
|
||||||
|
AwsFrameInfo const &pinfo() const { return _pinfo; }
|
||||||
|
|
||||||
IPAddress remoteIP();
|
IPAddress remoteIP();
|
||||||
uint16_t remotePort();
|
uint16_t remotePort();
|
||||||
@ -199,7 +216,7 @@ class AsyncWebSocketClient {
|
|||||||
void _onPoll();
|
void _onPoll();
|
||||||
void _onTimeout(uint32_t time);
|
void _onTimeout(uint32_t time);
|
||||||
void _onDisconnect();
|
void _onDisconnect();
|
||||||
void _onData(void *buf, size_t plen);
|
void _onData(void *pbuf, size_t plen);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)> AwsEventHandler;
|
typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)> AwsEventHandler;
|
||||||
|
@ -51,6 +51,7 @@ class AsyncStaticWebHandler;
|
|||||||
class AsyncCallbackWebHandler;
|
class AsyncCallbackWebHandler;
|
||||||
class AsyncResponseStream;
|
class AsyncResponseStream;
|
||||||
|
|
||||||
|
#ifndef WEBSERVER_H
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HTTP_GET = 0b00000001,
|
HTTP_GET = 0b00000001,
|
||||||
HTTP_POST = 0b00000010,
|
HTTP_POST = 0b00000010,
|
||||||
@ -61,6 +62,11 @@ typedef enum {
|
|||||||
HTTP_OPTIONS = 0b01000000,
|
HTTP_OPTIONS = 0b01000000,
|
||||||
HTTP_ANY = 0b01111111,
|
HTTP_ANY = 0b01111111,
|
||||||
} WebRequestMethod;
|
} WebRequestMethod;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//if this value is returned when asked for data, packet will not be sent and you will be asked for data again
|
||||||
|
#define RESPONSE_TRY_AGAIN 0xFFFFFFFF
|
||||||
|
|
||||||
typedef uint8_t WebRequestMethodComposite;
|
typedef uint8_t WebRequestMethodComposite;
|
||||||
typedef std::function<void(void)> ArDisconnectHandler;
|
typedef std::function<void(void)> ArDisconnectHandler;
|
||||||
|
|
||||||
@ -130,6 +136,7 @@ class AsyncWebServerRequest {
|
|||||||
AsyncWebServerResponse* _response;
|
AsyncWebServerResponse* _response;
|
||||||
StringArray _interestingHeaders;
|
StringArray _interestingHeaders;
|
||||||
ArDisconnectHandler _onDisconnectfn;
|
ArDisconnectHandler _onDisconnectfn;
|
||||||
|
|
||||||
String _temp;
|
String _temp;
|
||||||
uint8_t _parseState;
|
uint8_t _parseState;
|
||||||
|
|
||||||
@ -204,6 +211,7 @@ class AsyncWebServerRequest {
|
|||||||
RequestedConnectionType requestedConnType() const { return _reqconntype; }
|
RequestedConnectionType requestedConnType() const { return _reqconntype; }
|
||||||
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
|
bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED);
|
||||||
void onDisconnect (ArDisconnectHandler fn);
|
void onDisconnect (ArDisconnectHandler fn);
|
||||||
|
|
||||||
//hash is the string representation of:
|
//hash is the string representation of:
|
||||||
// base64(user:pass) for basic or
|
// base64(user:pass) for basic or
|
||||||
// user:realm:md5(user:realm:pass) for digest
|
// user:realm:md5(user:realm:pass) for digest
|
||||||
@ -323,6 +331,7 @@ class AsyncWebHandler {
|
|||||||
virtual void handleRequest(AsyncWebServerRequest *request __attribute__((unused))){}
|
virtual void handleRequest(AsyncWebServerRequest *request __attribute__((unused))){}
|
||||||
virtual void handleUpload(AsyncWebServerRequest *request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))){}
|
virtual void handleUpload(AsyncWebServerRequest *request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))){}
|
||||||
virtual void handleBody(AsyncWebServerRequest *request __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))){}
|
virtual void handleBody(AsyncWebServerRequest *request __attribute__((unused)), uint8_t *data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))){}
|
||||||
|
virtual bool isRequestHandlerTrivial(){return true;}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -477,7 +477,7 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){
|
|||||||
dir.close();
|
dir.close();
|
||||||
#endif
|
#endif
|
||||||
output += "]";
|
output += "]";
|
||||||
request->send(200, "text/json", output);
|
request->send(200, "application/json", output);
|
||||||
output = String();
|
output = String();
|
||||||
}
|
}
|
||||||
else if(request->hasParam("edit") || request->hasParam("download")){
|
else if(request->hasParam("edit") || request->hasParam("download")){
|
||||||
|
@ -18,6 +18,7 @@ class SPIFFSEditor: public AsyncWebHandler {
|
|||||||
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||||
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final;
|
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final;
|
||||||
|
virtual bool isRequestHandlerTrivial() override final {return false;}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -104,6 +104,7 @@ class AsyncCallbackWebHandler: public AsyncWebHandler {
|
|||||||
if(_onBody)
|
if(_onBody)
|
||||||
_onBody(request, data, len, index, total);
|
_onBody(request, data, len, index, total);
|
||||||
}
|
}
|
||||||
|
virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */
|
#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */
|
||||||
|
@ -127,12 +127,18 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(_parseState == PARSE_REQ_BODY){
|
} else if(_parseState == PARSE_REQ_BODY){
|
||||||
|
// A handler should be already attached at this point in _parseLine function.
|
||||||
|
// If handler does nothing (_onRequest is NULL), we don't need to really parse the body.
|
||||||
|
const bool needParse = _handler && !_handler->isRequestHandlerTrivial();
|
||||||
if(_isMultipart){
|
if(_isMultipart){
|
||||||
size_t i;
|
if(needParse){
|
||||||
for(i=0; i<len; i++){
|
size_t i;
|
||||||
_parseMultipartPostByte(((uint8_t*)buf)[i], i == len - 1);
|
for(i=0; i<len; i++){
|
||||||
_parsedLength++;
|
_parseMultipartPostByte(((uint8_t*)buf)[i], i == len - 1);
|
||||||
}
|
_parsedLength++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
_parsedLength += len;
|
||||||
} else {
|
} else {
|
||||||
if(_parsedLength == 0){
|
if(_parsedLength == 0){
|
||||||
if(_contentType.startsWith("application/x-www-form-urlencoded")){
|
if(_contentType.startsWith("application/x-www-form-urlencoded")){
|
||||||
@ -149,12 +155,14 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
|
|||||||
//check if authenticated before calling the body
|
//check if authenticated before calling the body
|
||||||
if(_handler) _handler->handleBody(this, (uint8_t*)buf, len, _parsedLength, _contentLength);
|
if(_handler) _handler->handleBody(this, (uint8_t*)buf, len, _parsedLength, _contentLength);
|
||||||
_parsedLength += len;
|
_parsedLength += len;
|
||||||
} else {
|
} else if(needParse) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for(i=0; i<len; i++){
|
for(i=0; i<len; i++){
|
||||||
_parsedLength++;
|
_parsedLength++;
|
||||||
_parsePlainPostChar(((uint8_t*)buf)[i]);
|
_parsePlainPostChar(((uint8_t*)buf)[i]);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_parsedLength += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(_parsedLength == _contentLength){
|
if(_parsedLength == _contentLength){
|
||||||
@ -886,7 +894,7 @@ const String& AsyncWebServerRequest::arg(const __FlashStringHelper * data) const
|
|||||||
size_t n = strlen_P(p);
|
size_t n = strlen_P(p);
|
||||||
char * name = (char*) malloc(n+1);
|
char * name = (char*) malloc(n+1);
|
||||||
if (name) {
|
if (name) {
|
||||||
strcpy(name, p);
|
strcpy_P(name, p);
|
||||||
const String & result = arg( String(name) );
|
const String & result = arg( String(name) );
|
||||||
free(name);
|
free(name);
|
||||||
return result;
|
return result;
|
||||||
|
@ -42,6 +42,10 @@ class AsyncBasicResponse: public AsyncWebServerResponse {
|
|||||||
class AsyncAbstractResponse: public AsyncWebServerResponse {
|
class AsyncAbstractResponse: public AsyncWebServerResponse {
|
||||||
private:
|
private:
|
||||||
String _head;
|
String _head;
|
||||||
|
// Data is inserted into cache at begin().
|
||||||
|
// This is inefficient with vector, but if we use some other container,
|
||||||
|
// we won't be able to access it as contiguous array of bytes when reading from it,
|
||||||
|
// so by gaining performance in one place, we'll lose it in another.
|
||||||
std::vector<uint8_t> _cache;
|
std::vector<uint8_t> _cache;
|
||||||
size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len);
|
size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len);
|
||||||
size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen);
|
size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen);
|
||||||
@ -55,7 +59,10 @@ class AsyncAbstractResponse: public AsyncWebServerResponse {
|
|||||||
virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; }
|
virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef TEMPLATE_PLACEHOLDER
|
||||||
#define TEMPLATE_PLACEHOLDER '%'
|
#define TEMPLATE_PLACEHOLDER '%'
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TEMPLATE_PARAM_NAME_LENGTH 32
|
#define TEMPLATE_PARAM_NAME_LENGTH 32
|
||||||
class AsyncFileResponse: public AsyncAbstractResponse {
|
class AsyncFileResponse: public AsyncAbstractResponse {
|
||||||
using File = fs::File;
|
using File = fs::File;
|
||||||
|
@ -302,9 +302,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(headLen){
|
if(headLen){
|
||||||
//TODO: memcpy should be faster?
|
memcpy(buf, _head.c_str(), _head.length());
|
||||||
sprintf((char*)buf, "%s", _head.c_str());
|
|
||||||
_head = String();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t readLen = 0;
|
size_t readLen = 0;
|
||||||
@ -313,6 +311,10 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
|
|||||||
// HTTP 1.1 allows leading zeros in chunk length. Or spaces may be added.
|
// HTTP 1.1 allows leading zeros in chunk length. Or spaces may be added.
|
||||||
// See RFC2616 sections 2, 3.6.1.
|
// See RFC2616 sections 2, 3.6.1.
|
||||||
readLen = _fillBufferAndProcessTemplates(buf+headLen+6, outLen - 8);
|
readLen = _fillBufferAndProcessTemplates(buf+headLen+6, outLen - 8);
|
||||||
|
if(readLen == RESPONSE_TRY_AGAIN){
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
outLen = sprintf((char*)buf+headLen, "%x", readLen) + headLen;
|
outLen = sprintf((char*)buf+headLen, "%x", readLen) + headLen;
|
||||||
while(outLen < headLen + 4) buf[outLen++] = ' ';
|
while(outLen < headLen + 4) buf[outLen++] = ' ';
|
||||||
buf[outLen++] = '\r';
|
buf[outLen++] = '\r';
|
||||||
@ -321,16 +323,27 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
|
|||||||
buf[outLen++] = '\r';
|
buf[outLen++] = '\r';
|
||||||
buf[outLen++] = '\n';
|
buf[outLen++] = '\n';
|
||||||
} else {
|
} else {
|
||||||
outLen = _fillBufferAndProcessTemplates(buf+headLen, outLen) + headLen;
|
readLen = _fillBufferAndProcessTemplates(buf+headLen, outLen);
|
||||||
|
if(readLen == RESPONSE_TRY_AGAIN){
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
outLen = readLen + headLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(outLen)
|
if(headLen){
|
||||||
_writtenLength += request->client()->write((const char*)buf, outLen);
|
_head = String();
|
||||||
|
}
|
||||||
|
|
||||||
if(_chunked)
|
if(outLen){
|
||||||
_sentLength += readLen;
|
_writtenLength += request->client()->write((const char*)buf, outLen);
|
||||||
else
|
}
|
||||||
_sentLength += outLen - headLen;
|
|
||||||
|
if(_chunked){
|
||||||
|
_sentLength += readLen;
|
||||||
|
} else {
|
||||||
|
_sentLength += outLen - headLen;
|
||||||
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
@ -378,8 +391,6 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
|
|||||||
// temporary buffer to hold parameter name
|
// temporary buffer to hold parameter name
|
||||||
uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1];
|
uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1];
|
||||||
String paramName;
|
String paramName;
|
||||||
// cache position to insert remainder of template parameter value
|
|
||||||
std::vector<uint8_t>::iterator i = _cache.end();
|
|
||||||
// If closing placeholder is found:
|
// If closing placeholder is found:
|
||||||
if(pTemplateEnd) {
|
if(pTemplateEnd) {
|
||||||
// prepare argument to callback
|
// prepare argument to callback
|
||||||
@ -403,16 +414,14 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
|
|||||||
// prepare argument to callback
|
// prepare argument to callback
|
||||||
*pTemplateEnd = 0;
|
*pTemplateEnd = 0;
|
||||||
paramName = String(reinterpret_cast<char*>(buf));
|
paramName = String(reinterpret_cast<char*>(buf));
|
||||||
// Copy remaining read-ahead data into cache (when std::vector::insert returning iterator will be available, these 3 lines can be simplified into 1)
|
// Copy remaining read-ahead data into cache
|
||||||
const size_t pos = _cache.size();
|
_cache.insert(_cache.begin(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
||||||
_cache.insert(_cache.end(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
|
||||||
i = _cache.begin() + pos;
|
|
||||||
pTemplateEnd = &data[len - 1];
|
pTemplateEnd = &data[len - 1];
|
||||||
}
|
}
|
||||||
else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position
|
else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position
|
||||||
{
|
{
|
||||||
// but first, store read file data in cache
|
// but first, store read file data in cache
|
||||||
_cache.insert(_cache.end(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
_cache.insert(_cache.begin(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent);
|
||||||
++pTemplateStart;
|
++pTemplateStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -434,9 +443,7 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
|
|||||||
// make room for param value
|
// make room for param value
|
||||||
// 1. move extra data to cache if parameter value is longer than placeholder AND if there is no room to store
|
// 1. move extra data to cache if parameter value is longer than placeholder AND if there is no room to store
|
||||||
if((pTemplateEnd + 1 < pTemplateStart + numBytesCopied) && (originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1) < len)) {
|
if((pTemplateEnd + 1 < pTemplateStart + numBytesCopied) && (originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1) < len)) {
|
||||||
size_t pos = i - _cache.begin();
|
_cache.insert(_cache.begin(), &data[originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1)], &data[len]);
|
||||||
_cache.insert(i, &data[originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1)], &data[len]);
|
|
||||||
i = _cache.begin() + pos;
|
|
||||||
//2. parameter value is longer than placeholder text, push the data after placeholder which not saved into cache further to the end
|
//2. parameter value is longer than placeholder text, push the data after placeholder which not saved into cache further to the end
|
||||||
memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[originalLen] - pTemplateStart - numBytesCopied);
|
memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[originalLen] - pTemplateStart - numBytesCopied);
|
||||||
} else if(pTemplateEnd + 1 != pTemplateStart + numBytesCopied)
|
} else if(pTemplateEnd + 1 != pTemplateStart + numBytesCopied)
|
||||||
@ -447,7 +454,7 @@ size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size
|
|||||||
memcpy(pTemplateStart, pvstr, numBytesCopied);
|
memcpy(pTemplateStart, pvstr, numBytesCopied);
|
||||||
// If result is longer than buffer, copy the remainder into cache (this could happen only if placeholder text itself did not fit entirely in buffer)
|
// If result is longer than buffer, copy the remainder into cache (this could happen only if placeholder text itself did not fit entirely in buffer)
|
||||||
if(numBytesCopied < pvlen) {
|
if(numBytesCopied < pvlen) {
|
||||||
_cache.insert(i, pvstr + numBytesCopied, pvstr + pvlen);
|
_cache.insert(_cache.begin(), pvstr + numBytesCopied, pvstr + pvlen);
|
||||||
} else if(pTemplateStart + numBytesCopied < pTemplateEnd + 1) { // result is copied fully; if result is shorter than placeholder text...
|
} else if(pTemplateStart + numBytesCopied < pTemplateEnd + 1) { // result is copied fully; if result is shorter than placeholder text...
|
||||||
// there is some free room, fill it from cache
|
// there is some free room, fill it from cache
|
||||||
const size_t roomFreed = pTemplateEnd + 1 - pTemplateStart - numBytesCopied;
|
const size_t roomFreed = pTemplateEnd + 1 - pTemplateStart - numBytesCopied;
|
||||||
@ -476,7 +483,7 @@ void AsyncFileResponse::_setContentType(const String& path){
|
|||||||
if (path.endsWith(".html")) _contentType = "text/html";
|
if (path.endsWith(".html")) _contentType = "text/html";
|
||||||
else if (path.endsWith(".htm")) _contentType = "text/html";
|
else if (path.endsWith(".htm")) _contentType = "text/html";
|
||||||
else if (path.endsWith(".css")) _contentType = "text/css";
|
else if (path.endsWith(".css")) _contentType = "text/css";
|
||||||
else if (path.endsWith(".json")) _contentType = "text/json";
|
else if (path.endsWith(".json")) _contentType = "application/json";
|
||||||
else if (path.endsWith(".js")) _contentType = "application/javascript";
|
else if (path.endsWith(".js")) _contentType = "application/javascript";
|
||||||
else if (path.endsWith(".png")) _contentType = "image/png";
|
else if (path.endsWith(".png")) _contentType = "image/png";
|
||||||
else if (path.endsWith(".gif")) _contentType = "image/gif";
|
else if (path.endsWith(".gif")) _contentType = "image/gif";
|
||||||
@ -599,7 +606,9 @@ AsyncCallbackResponse::AsyncCallbackResponse(const String& contentType, size_t l
|
|||||||
|
|
||||||
size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
|
size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
size_t ret = _content(data, len, _filledLength);
|
size_t ret = _content(data, len, _filledLength);
|
||||||
_filledLength += ret;
|
if(ret != RESPONSE_TRY_AGAIN){
|
||||||
|
_filledLength += ret;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +628,9 @@ AsyncChunkedResponse::AsyncChunkedResponse(const String& contentType, AwsRespons
|
|||||||
|
|
||||||
size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
|
size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
size_t ret = _content(data, len, _filledLength);
|
size_t ret = _content(data, len, _filledLength);
|
||||||
_filledLength += ret;
|
if(ret != RESPONSE_TRY_AGAIN){
|
||||||
|
_filledLength += ret;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebServer::begin(){
|
void AsyncWebServer::begin(){
|
||||||
|
_server.setNoDelay(true);
|
||||||
_server.begin();
|
_server.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +60,9 @@
|
|||||||
bool can_process_serial = true;
|
bool can_process_serial = true;
|
||||||
|
|
||||||
extern bool deleteRecursive(String path);
|
extern bool deleteRecursive(String path);
|
||||||
extern void CloseSerialUpload (bool iserror, String & filename);
|
extern bool sendLine2Serial (String & line, int32_t linenb, int32_t * newlinenb);
|
||||||
extern bool sendLine2Serial (String & line);
|
extern void CloseSerialUpload (bool iserror, String & filename , int32_t linenb);
|
||||||
|
extern bool purge_serial();
|
||||||
extern long id_connection;
|
extern long id_connection;
|
||||||
|
|
||||||
const uint8_t PAGE_404 [] PROGMEM = "<HTML>\n<HEAD>\n<title>Redirecting...</title> \n</HEAD>\n<BODY>\n<CENTER>Unknown page : $QUERY$- you will be redirected...\n<BR><BR>\nif not redirected, <a href='http://$WEB_ADDRESS$'>click here</a>\n<BR><BR>\n<PROGRESS name='prg' id='prg'></PROGRESS>\n\n<script>\nvar i = 0; \nvar x = document.getElementById(\"prg\"); \nx.max=5; \nvar interval=setInterval(function(){\ni=i+1; \nvar x = document.getElementById(\"prg\"); \nx.value=i; \nif (i>5) \n{\nclearInterval(interval);\nwindow.location.href='/';\n}\n},1000);\n</script>\n</CENTER>\n</BODY>\n</HTML>\n\n";
|
const uint8_t PAGE_404 [] PROGMEM = "<HTML>\n<HEAD>\n<title>Redirecting...</title> \n</HEAD>\n<BODY>\n<CENTER>Unknown page : $QUERY$- you will be redirected...\n<BR><BR>\nif not redirected, <a href='http://$WEB_ADDRESS$'>click here</a>\n<BR><BR>\n<PROGRESS name='prg' id='prg'></PROGRESS>\n\n<script>\nvar i = 0; \nvar x = document.getElementById(\"prg\"); \nx.max=5; \nvar interval=setInterval(function(){\ni=i+1; \nvar x = document.getElementById(\"prg\"); \nx.value=i; \nif (i>5) \n{\nclearInterval(interval);\nwindow.location.href='/';\n}\n},1000);\n</script>\n</CENTER>\n</BODY>\n</HTML>\n\n";
|
||||||
@ -1092,6 +1093,7 @@ void SDFile_serial_upload (AsyncWebServerRequest *request, String filename, size
|
|||||||
LOG ("Uploading: ")
|
LOG ("Uploading: ")
|
||||||
LOG (filename)
|
LOG (filename)
|
||||||
LOG ("\n")
|
LOG ("\n")
|
||||||
|
static int32_t lineNb =-1;
|
||||||
static String current_line;
|
static String current_line;
|
||||||
static bool is_comment = false;
|
static bool is_comment = false;
|
||||||
static String current_filename;
|
static String current_filename;
|
||||||
@ -1107,75 +1109,66 @@ void SDFile_serial_upload (AsyncWebServerRequest *request, String filename, size
|
|||||||
//Upload start
|
//Upload start
|
||||||
//**************
|
//**************
|
||||||
if (!index) {
|
if (!index) {
|
||||||
LOG ("Starting\n")
|
LOG("Upload Start\r\n")
|
||||||
//need to lock serial out to avoid garbage in file
|
String command = "M29";
|
||||||
(web_interface->blockserial) = true;
|
String resetcmd = "M110 N0";
|
||||||
current_line = "";
|
if (CONFIG::GetFirmwareTarget() == SMOOTHIEWARE)resetcmd = "N0 M110";
|
||||||
//init flags
|
lineNb=1;
|
||||||
is_comment = false;
|
//close any ongoing upload and get current line number
|
||||||
current_filename = filename;
|
if(!sendLine2Serial (command,1, &lineNb)){
|
||||||
web_interface->_upload_status = UPLOAD_STATUS_ONGOING;
|
//it can failed for repetier
|
||||||
ESPCOM::println (F ("Uploading..."), PRINTER_PIPE);
|
if ( ( CONFIG::GetFirmwareTarget() == REPETIER4DV) || (CONFIG::GetFirmwareTarget() == REPETIER) ) {
|
||||||
ESPCOM::flush (DEFAULT_PRINTER_PIPE);
|
if(!sendLine2Serial (command,-1, NULL)){
|
||||||
LOG ("Clear Serial\r\n");
|
LOG("Start Upload failed")
|
||||||
if(ESPCOM::available(DEFAULT_PRINTER_PIPE)) {
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
||||||
ESPCOM::bridge();
|
|
||||||
CONFIG::wait(1);
|
|
||||||
}
|
|
||||||
//command to pritnter to start print
|
|
||||||
String command = "M28 " + filename;
|
|
||||||
LOG (command);
|
|
||||||
LOG ("\r\n");
|
|
||||||
ESPCOM::println (command, DEFAULT_PRINTER_PIPE);
|
|
||||||
ESPCOM::flush (DEFAULT_PRINTER_PIPE);
|
|
||||||
CONFIG::wait (500);
|
|
||||||
uint32_t timeout = millis();
|
|
||||||
bool done = false;
|
|
||||||
while (!done) { //time out is 2000ms
|
|
||||||
CONFIG::wdtFeed();
|
|
||||||
//if there is something in serial buffer
|
|
||||||
size_t len = ESPCOM::available(DEFAULT_PRINTER_PIPE);
|
|
||||||
//get size of buffer
|
|
||||||
if (len > 0) {
|
|
||||||
CONFIG::wdtFeed();
|
|
||||||
uint8_t * sbuf = (uint8_t *)malloc(len+1);
|
|
||||||
if(!sbuf){
|
|
||||||
web_interface->_upload_status = UPLOAD_STATUS_CANCELLED;
|
|
||||||
ESPCOM::println (F ("SD upload rejected"), PRINTER_PIPE);
|
|
||||||
LOG ("SD upload rejected\r\n");
|
|
||||||
request->client()->abort();
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
//read buffer
|
|
||||||
ESPCOM::readBytes (DEFAULT_PRINTER_PIPE, sbuf, len);
|
|
||||||
//convert buffer to zero end array
|
|
||||||
sbuf[len] = '\0';
|
|
||||||
//use string because easier to handle
|
|
||||||
response = (const char*) sbuf;
|
|
||||||
LOG (response);
|
|
||||||
//if there is a wait it means purge is done
|
|
||||||
if (response.indexOf ("wait") > -1) {
|
|
||||||
LOG ("Exit start writing\r\n");
|
|
||||||
done = true;
|
|
||||||
free(sbuf);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//it is first command if it is failed no need to continue
|
|
||||||
//and resend command won't help
|
|
||||||
if (response.indexOf ("Resend") > -1 || response.indexOf ("failed") > -1) {
|
|
||||||
web_interface->blockserial = false;
|
|
||||||
LOG ("Error start writing\r\n");
|
|
||||||
web_interface->_upload_status = UPLOAD_STATUS_FAILED;
|
|
||||||
request->client()->abort();
|
|
||||||
free(sbuf);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(sbuf);
|
} else {
|
||||||
}
|
LOG("Start Upload failed")
|
||||||
if ( (millis() - timeout) > SERIAL_CHECK_TIMEOUT) {
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
||||||
done = true;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Mount SD card
|
||||||
|
command = "M21";
|
||||||
|
if(!sendLine2Serial (command,-1, NULL)){
|
||||||
|
LOG("Mounting SD failed")
|
||||||
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Reset line numbering
|
||||||
|
if(!sendLine2Serial (resetcmd,-1, NULL)){
|
||||||
|
LOG("Reset Numbering failed")
|
||||||
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lineNb=1;
|
||||||
|
//need to lock serial out to avoid garbage in file
|
||||||
|
(web_interface->blockserial) = true;
|
||||||
|
current_line ="";
|
||||||
|
current_filename = filename;
|
||||||
|
is_comment = false;
|
||||||
|
String response;
|
||||||
|
ESPCOM::println (F ("Uploading..."), PRINTER_PIPE);
|
||||||
|
//Clear all serial
|
||||||
|
ESPCOM::flush (DEFAULT_PRINTER_PIPE);
|
||||||
|
purge_serial();
|
||||||
|
//besure nothing left again
|
||||||
|
purge_serial();
|
||||||
|
command = "M28 " + current_filename;
|
||||||
|
//send start upload
|
||||||
|
//no correction allowed because it means reset numbering was failed
|
||||||
|
if (sendLine2Serial(command, lineNb, NULL)){
|
||||||
|
CONFIG::wait(1200);
|
||||||
|
//additional purge, in case it is slow to answer
|
||||||
|
purge_serial();
|
||||||
|
web_interface->_upload_status= UPLOAD_STATUS_ONGOING;
|
||||||
|
LOG("Creation Ok\r\n")
|
||||||
|
|
||||||
|
} else {
|
||||||
|
web_interface->_upload_status= UPLOAD_STATUS_FAILED;
|
||||||
|
LOG("Creation failed\r\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//Upload write
|
//Upload write
|
||||||
//**************
|
//**************
|
||||||
@ -1196,10 +1189,10 @@ void SDFile_serial_upload (AsyncWebServerRequest *request, String filename, size
|
|||||||
if (current_line.length() < 126) {
|
if (current_line.length() < 126) {
|
||||||
//do we have something in buffer ?
|
//do we have something in buffer ?
|
||||||
if (current_line.length() > 0 ) {
|
if (current_line.length() > 0 ) {
|
||||||
current_line += "\r\n";
|
lineNb++;
|
||||||
if (!sendLine2Serial (current_line) ) {
|
if (!sendLine2Serial (current_line, lineNb, NULL) ) {
|
||||||
LOG ("Error over buffer\n")
|
LOG ("Error sending line\n")
|
||||||
CloseSerialUpload (true, current_filename);
|
CloseSerialUpload (true, current_filename,lineNb);
|
||||||
request->client()->abort();
|
request->client()->abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1212,7 +1205,8 @@ void SDFile_serial_upload (AsyncWebServerRequest *request, String filename, size
|
|||||||
} else {
|
} else {
|
||||||
//error buffer overload
|
//error buffer overload
|
||||||
LOG ("Error over buffer\n")
|
LOG ("Error over buffer\n")
|
||||||
CloseSerialUpload (true, current_filename);
|
lineNb++;
|
||||||
|
CloseSerialUpload (true, current_filename, lineNb);
|
||||||
request->client()->abort();
|
request->client()->abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1221,7 +1215,8 @@ void SDFile_serial_upload (AsyncWebServerRequest *request, String filename, size
|
|||||||
current_line += char (data[pos]); //copy current char to buffer to send/resend
|
current_line += char (data[pos]); //copy current char to buffer to send/resend
|
||||||
} else {
|
} else {
|
||||||
LOG ("Error over buffer\n")
|
LOG ("Error over buffer\n")
|
||||||
CloseSerialUpload (true, current_filename);
|
lineNb++;
|
||||||
|
CloseSerialUpload (true, current_filename, lineNb);
|
||||||
request->client()->abort();
|
request->client()->abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1238,16 +1233,18 @@ void SDFile_serial_upload (AsyncWebServerRequest *request, String filename, size
|
|||||||
LOG ("Final is reached\n")
|
LOG ("Final is reached\n")
|
||||||
//if last part does not have '\n'
|
//if last part does not have '\n'
|
||||||
if (current_line.length() > 0) {
|
if (current_line.length() > 0) {
|
||||||
current_line += "\r\n";
|
lineNb++;
|
||||||
if (!sendLine2Serial (current_line) ) {
|
if (!sendLine2Serial (current_line, lineNb, NULL) ) {
|
||||||
LOG ("Error sending buffer\n")
|
LOG ("Error sending buffer\n")
|
||||||
CloseSerialUpload (true, current_filename);
|
lineNb++;
|
||||||
|
CloseSerialUpload (true, current_filename, lineNb);
|
||||||
request->client()->abort();
|
request->client()->abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG ("Upload finished ");
|
LOG ("Upload finished ");
|
||||||
CloseSerialUpload (false, current_filename);
|
lineNb++;
|
||||||
|
CloseSerialUpload (false, current_filename, lineNb);
|
||||||
}
|
}
|
||||||
LOG ("Exit fn\n")
|
LOG ("Exit fn\n")
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//version and sources location
|
//version and sources location
|
||||||
#define FW_VERSION "2.0.0.c24"
|
#define FW_VERSION "2.0.0.c25"
|
||||||
#define REPOSITORY "https://github.com/luc-github/ESP3D"
|
#define REPOSITORY "https://github.com/luc-github/ESP3D"
|
||||||
|
|
||||||
//Customize ESP3D ////////////////////////////////////////////////////////////////////////
|
//Customize ESP3D ////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
x
Reference in New Issue
Block a user