Skip to content

Commit

Permalink
feat: automatic receive is turned back on - ESP-AT does not properly …
Browse files Browse the repository at this point in the history
…handle manual TCP receive in some corner cases, fall back before it is fixed!
  • Loading branch information
MaJerle committed Jun 24, 2023
1 parent ac3824c commit 1a52ebf
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 59 deletions.
1 change: 1 addition & 0 deletions dev/lwesp_opts.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
#define LWESP_CFG_FLASH 1

#define LWESP_CFG_RESET_ON_INIT 1
#define LWESP_CFG_CONN_MANUAL_TCP_RECEIVE 0

#define LWESP_CFG_ACCESS_POINT_STRUCT_FULL_FIELDS 1
#define LWESP_CFG_LIST_CMD 1
Expand Down
57 changes: 33 additions & 24 deletions lwesp/src/api/lwesp_netconn.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,21 @@
* \brief Sequential API structure
*/
typedef struct lwesp_netconn {
struct lwesp_netconn* next; /*!< Linked list entry */
struct lwesp_netconn* next; /*!< Linked list entry */

lwesp_netconn_type_t type; /*!< Netconn type */
lwesp_port_t listen_port; /*!< Port on which we are listening */
lwesp_netconn_type_t type; /*!< Netconn type */
lwesp_port_t listen_port; /*!< Port on which we are listening */

size_t rcv_packets; /*!< Number of received packets so far on this connection */
lwesp_conn_p conn; /*!< Pointer to actual connection */
size_t rcv_packets; /*!< Number of received packets so far on this connection */
lwesp_conn_p conn; /*!< Pointer to actual connection */

lwesp_sys_mbox_t mbox_accept; /*!< List of active connections waiting to be processed */
lwesp_sys_mbox_t mbox_receive; /*!< Message queue for receive mbox */
size_t mbox_receive_entries; /*!< Number of entries written to receive mbox */

lwesp_linbuff_t buff; /*!< Linear buffer structure */
lwesp_linbuff_t buff; /*!< Linear buffer structure */

uint16_t conn_timeout; /*!< Connection timeout in units of seconds when
uint16_t conn_timeout; /*!< Connection timeout in units of seconds when
netconn is in server (listen) mode.
Connection will be automatically closed if there is no
data exchange in time. Set to `0` when timeout feature is disabled. */
Expand Down Expand Up @@ -150,9 +150,9 @@ netconn_evt(lwesp_evt_t* evt) {
if (lwesp_conn_is_client(conn)) { /* Was connection started by us? */
nc = lwesp_conn_get_arg(conn); /* Argument should be already set */
if (nc != NULL) {
nc->conn = conn; /* Save actual connection */
nc->conn = conn; /* Save actual connection */
} else {
close = 1; /* Close this connection, invalid netconn */
close = 1; /* Close this connection, invalid netconn */
}

/* Is the connection server type and we have known listening API? */
Expand Down Expand Up @@ -192,7 +192,7 @@ netconn_evt(lwesp_evt_t* evt) {
lwesp_conn_set_arg(conn, NULL); /* Reset argument */
lwesp_netconn_delete(nc); /* Free memory for API */
}
lwesp_conn_close(conn, 0); /* Close the connection */
lwesp_conn_close(conn, 0); /* Close the connection */
close = 0;
}
break;
Expand All @@ -208,20 +208,26 @@ netconn_evt(lwesp_evt_t* evt) {
nc = lwesp_conn_get_arg(conn); /* Get API from connection */
pbuf = lwesp_evt_conn_recv_get_buff(evt); /* Get received buff */

lwesp_pbuf_ref(pbuf); /* Increase reference counter */
#if !LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
lwesp_conn_recved(conn, pbuf); /* Notify stack about received data */
#endif /* !LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */

lwesp_pbuf_ref(pbuf); /* Increase reference counter */
if (nc == NULL || !lwesp_sys_mbox_isvalid(&nc->mbox_receive)
|| !lwesp_sys_mbox_putnow(&nc->mbox_receive, pbuf)) {
LWESP_DEBUGF(LWESP_CFG_DBG_NETCONN, "[LWESP NETCONN] Ignoring more data for receive!\r\n");
lwesp_pbuf_free(pbuf); /* Free pbuf */
return lwespOKIGNOREMORE; /* Return OK to free the memory and ignore further data */
}
++nc->mbox_receive_entries; /* Increase number of packets in receive mbox */
++nc->mbox_receive_entries; /* Increase number of packets in receive mbox */
#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
/* Check against 1 less to still allow potential close event to be written to queue */
if (nc->mbox_receive_entries >= (LWESP_CFG_NETCONN_RECEIVE_QUEUE_LEN - 1)) {
conn->status.f.receive_blocked = 1; /* Block reading more data */
}
#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */

++nc->rcv_packets; /* Increase number of packets received */
++nc->rcv_packets; /* Increase number of packets received */
LWESP_DEBUGF(LWESP_CFG_DBG_NETCONN | LWESP_DBG_TYPE_TRACE,
"[LWESP NETCONN] Received pbuf contains %d bytes. Handle written to receive mbox\r\n",
(int)lwesp_pbuf_length(pbuf, 0));
Expand Down Expand Up @@ -290,10 +296,10 @@ lwesp_netconn_new(lwesp_netconn_type_t type) {
lwesp_evt_register(lwesp_evt); /* Register global event function */
}
lwesp_core_unlock();
a = lwesp_mem_calloc(1, sizeof(*a)); /* Allocate memory for core object */
a = lwesp_mem_calloc(1, sizeof(*a)); /* Allocate memory for core object */
if (a != NULL) {
a->type = type; /* Save netconn type */
a->conn_timeout = 0; /* Default connection timeout */
a->type = type; /* Save netconn type */
a->conn_timeout = 0; /* Default connection timeout */
if (!lwesp_sys_mbox_create(
&a->mbox_accept, LWESP_CFG_NETCONN_ACCEPT_QUEUE_LEN)) { /* Allocate memory for accepting message box */
LWESP_DEBUGF(LWESP_CFG_DBG_NETCONN | LWESP_DBG_TYPE_TRACE | LWESP_DBG_LVL_DANGER,
Expand Down Expand Up @@ -547,17 +553,17 @@ lwesp_netconn_accept(lwesp_netconn_p nc, lwesp_netconn_p* client) {
}
if ((uint8_t*)tmp == (uint8_t*)&recv_closed) {
lwesp_core_lock();
listen_api = NULL; /* Disable listening at this point */
listen_api = NULL; /* Disable listening at this point */
lwesp_core_unlock();
return lwespERRWIFINOTCONNECTED; /* Wifi disconnected */
} else if ((uint8_t*)tmp == (uint8_t*)&recv_not_present) {
lwesp_core_lock();
listen_api = NULL; /* Disable listening at this point */
listen_api = NULL; /* Disable listening at this point */
lwesp_core_unlock();
return lwespERRNODEVICE; /* Device not present */
}
*client = tmp; /* Set new pointer */
return lwespOK; /* We have a new connection */
*client = tmp; /* Set new pointer */
return lwespOK; /* We have a new connection */
}

/**
Expand Down Expand Up @@ -628,15 +634,15 @@ lwesp_netconn_write(lwesp_netconn_p nc, const void* data, size_t btw) {
}

/* Step 3 */
if (nc->buff.buff == NULL) { /* Check if we should allocate a new buffer */
if (nc->buff.buff == NULL) { /* Check if we should allocate a new buffer */
nc->buff.buff = lwesp_mem_malloc(sizeof(*nc->buff.buff) * LWESP_CFG_CONN_MAX_DATA_LEN);
nc->buff.len = LWESP_CFG_CONN_MAX_DATA_LEN; /* Save buffer length */
nc->buff.ptr = 0; /* Save buffer pointer */
}

/* Step 4 */
if (nc->buff.buff != NULL) { /* Memory available? */
LWESP_MEMCPY(&nc->buff.buff[nc->buff.ptr], d, btw); /* Copy data to buffer */
if (nc->buff.buff != NULL) { /* Memory available? */
LWESP_MEMCPY(&nc->buff.buff[nc->buff.ptr], d, btw); /* Copy data to buffer */
nc->buff.ptr += btw;
} else { /* Still no memory available? */
return lwesp_conn_send(nc->conn, data, btw, NULL, 1); /* Simply send directly blocking */
Expand Down Expand Up @@ -747,12 +753,15 @@ lwesp_netconn_receive(lwesp_netconn_p nc, lwesp_pbuf_p* pbuf) {
if ((uint8_t*)(*pbuf) == (uint8_t*)&recv_closed) {
*pbuf = NULL; /* Reset pbuf */
return lwespCLOSED;
} else {
}
#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
else {
lwesp_core_lock();
nc->conn->status.f.receive_blocked = 0; /* Resume reading more data */
lwesp_conn_recved(nc->conn, *pbuf); /* Notify stack about received data */
lwesp_core_unlock();
}
#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */
return lwespOK; /* We have data available */
}

Expand Down
18 changes: 18 additions & 0 deletions lwesp/src/include/lwesp/lwesp_opt.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,29 @@
#define LWESP_CFG_CONN_MAX_DATA_LEN 2048
#endif

/**
* \brief Enables `1` or disables `0` manual `TCP` data receive from ESP device
*
* Normally ESP automatically sends received TCP data to host device
* in async mode. When host device is slow or if there is memory constrain,
* it may happen that processing cannot handle all received data.
*
* When feature is enabled, ESP will notify host device about new data
* available for read and then user may start read process
*
* \note This feature is only available for `TCP/SSL` connections.
*/
#ifndef LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
#define LWESP_CFG_CONN_MANUAL_TCP_RECEIVE 1
#endif

/**
* \brief Minimal buffer in bytes for connection receive allocation.
*
* Allocation will always start with (up to) \ref LWESP_CFG_CONN_MAX_DATA_LEN
* and will continue with trial down to this setting up until allocating is successful.
*
* \note This feature is used together with \ref LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
*/
#ifndef LWESP_CFG_CONN_MIN_DATA_LEN
#define LWESP_CFG_CONN_MIN_DATA_LEN 16
Expand Down
19 changes: 13 additions & 6 deletions lwesp/src/include/lwesp/lwesp_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,24 +193,28 @@ typedef struct lwesp_conn {

lwesp_linbuff_t buff; /*!< Linear buffer structure */
size_t total_recved; /*!< Total number of bytes received */
#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE || __DOXYGEN__
size_t tcp_available_bytes; /*!< Number of bytes in ESP ready to be read on connection.
This variable always holds last known info from ESP
device and is not decremented (or incremented) by application */
#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE || __DOXYGEN__ */
size_t tcp_not_ack_bytes; /*!< Number of bytes not acknowledge by application done with processing
This variable is increased everytime new packet is
read to be sent to application and decreased
when application acknowledges it */

union {
struct {
uint8_t active : 1; /*!< Status whether connection is active */
uint8_t client : 1; /*!< Status whether connection is in client mode */
uint8_t data_received : 1; /*!< Status whether first data were received on connection */
uint8_t in_closing : 1; /*!< Status if connection is in closing mode.
uint8_t active : 1; /*!< Status whether connection is active */
uint8_t client : 1; /*!< Status whether connection is in client mode */
uint8_t data_received : 1; /*!< Status whether first data were received on connection */
uint8_t in_closing : 1; /*!< Status if connection is in closing mode.
When in closing mode, ignore any possible
received data from function */
#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE || __DOXYGEN__
uint8_t receive_blocked : 1; /*!< Status whether we should block manual receive for some time */
uint8_t receive_is_command_queued : 1; /*!< Status whether manual read command is in the queue already */
#endif /* #if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE || __DOXYGEN__ */
} f; /*!< Connection flags */
} status; /*!< Connection status union with flag bits */
} lwesp_conn_t;
Expand Down Expand Up @@ -242,8 +246,8 @@ typedef struct {
lwesp_port_t port; /*!< Remote port on IPD data */

size_t buff_ptr; /*!< Buffer pointer to save data to.
When set to `NULL` while `read = 1`,
reading should ignore incoming data */
When set to `NULL` while `read = 1`,
reading should ignore incoming data */
lwesp_pbuf_p buff; /*!< Pointer to data buffer used for receiving data */
} lwesp_ipd_t;

Expand Down Expand Up @@ -414,6 +418,7 @@ typedef struct lwesp_msg {
uint8_t val_id; /*!< Connection current validation ID when command was sent to queue */
} conn_send; /*!< Structure to send data on connection */

#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
struct {
lwesp_conn_t* conn; /*!< Connection handle */
lwesp_pbuf_p buff; /*!< Buffer handle to write received data to */
Expand All @@ -426,6 +431,7 @@ typedef struct lwesp_msg {
size_t tot_len; /*!< Total length expected for this read operation (actual data len received from device) */
size_t buff_ptr; /*!< Buffer pointer to save data to (next character) */
} conn_recv; /*!< Structure to manually read TCP data */
#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */

/* TCP/IP based commands */
struct {
Expand Down Expand Up @@ -584,6 +590,7 @@ typedef struct {
uint32_t active_conns_last; /*!< The same as previous but status before last check */

lwesp_link_conn_t link_conn; /*!< Link connection handle */
lwesp_ipd_t ipd; /*!< Connection incoming data structure */
lwesp_conn_t conns[LWESP_CFG_MAX_CONNS]; /*!< Array of all connection structures */

#if LWESP_CFG_MODE_STATION || __DOXYGEN__
Expand Down
11 changes: 11 additions & 0 deletions lwesp/src/lwesp/lwesp_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ prv_conn_timeout_cb(void* arg) {
lwespi_conn_start_timeout(conn); /* Schedule new timeout */
LWESP_DEBUGF(LWESP_CFG_DBG_CONN | LWESP_DBG_TYPE_TRACE, "[LWESP CONN] Poll event: %p\r\n", (void*)conn);
}
#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
lwespi_conn_manual_tcp_try_read_data(conn); /* Try to read data manually */
#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */
}

/**
Expand All @@ -80,6 +82,8 @@ lwespi_conn_start_timeout(lwesp_conn_p conn) {
lwesp_timeout_add(LWESP_CFG_CONN_POLL_INTERVAL, prv_conn_timeout_cb, conn); /* Add connection timeout */
}

#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE || __DOXYGEN__

/**
* \brief Callback function when manual TCP receive finishes
* \param[in] res: Result of reading
Expand Down Expand Up @@ -165,6 +169,8 @@ lwespi_conn_check_available_rx_data(void) {
return lwespi_send_msg_to_producer_mbox(&LWESP_MSG_VAR_REF(msg), lwespi_initiate_cmd, 1000);
}

#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE || __DOXYGEN__ */

/**
* \brief Get connection validation ID
* \param[in] conn: Connection handle
Expand Down Expand Up @@ -460,6 +466,7 @@ lwesp_conn_send(lwesp_conn_p conn, const void* data, size_t btw, size_t* const b
*/
lwespr_t
lwesp_conn_recved(lwesp_conn_p conn, lwesp_pbuf_p pbuf) {
#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
size_t len;
len = lwesp_pbuf_length(pbuf, 1); /* Get length of pbuf */
if (conn->tcp_not_ack_bytes >= len) { /* Check length of not-acknowledged bytes */
Expand All @@ -468,6 +475,10 @@ lwesp_conn_recved(lwesp_conn_p conn, lwesp_pbuf_p pbuf) {
/* Warning here, de-sync happened somewhere! */
}
lwespi_conn_manual_tcp_try_read_data(conn); /* Try to read more connection data */
#else
LWESP_UNUSED(conn);
LWESP_UNUSED(pbuf);
#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */
return lwespOK;
}

Expand Down

0 comments on commit 1a52ebf

Please sign in to comment.