rewrite serbridge buffering

v1.0 v1.0.2
Thorsten von Eicken 9 years ago
parent b48614c373
commit 45cfe914d5
  1. 114
      serial/serbridge.c
  2. 7
      serial/serbridge.h

@ -22,19 +22,6 @@ sint8 ICACHE_FLASH_ATTR espbuffsend(serbridgeConnData *conn, const char *data,
// Connection pool
serbridgeConnData connData[MAX_CONN];
// Transmit buffers for the connection pool
static char txbuffer[MAX_CONN][MAX_TXBUFFER];
// Given a pointer to an espconn struct find the connection that correcponds to it
static serbridgeConnData ICACHE_FLASH_ATTR *serbridgeFindConnData(void *arg) {
for (int i=0; i<MAX_CONN; i++) {
if (connData[i].conn == (struct espconn *)arg) {
return &connData[i];
}
}
//os_printf("FindConnData: Huh? Couldn't find connection for %p\n", arg);
return NULL; // not found, may be closed already...
}
// Send all data in conn->txbuffer
// returns result from espconn_sent if data in buffer or ESPCONN_OK (0)
@ -45,40 +32,67 @@ static sint8 ICACHE_FLASH_ATTR sendtxbuffer(serbridgeConnData *conn) {
//os_printf("%d TX %d\n", system_get_time(), conn->txbufferlen);
conn->readytosend = false;
result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen);
conn->txbufferlen = 0;
if (result != ESPCONN_OK) {
os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn);
conn->txbufferlen = 0;
} else {
conn->sentbuffer = conn->txbuffer;
conn->txbuffer = NULL;
conn->txbufferlen = 0;
}
}
return result;
}
static char *tx_full_msg = "espbuffsend: txbuffer full on conn %p\n";
// espbuffsend adds data to the send buffer. If the previous send was completed it calls
// sendtxbuffer and espconn_sent.
// Returns ESPCONN_OK (0) for success, -128 if buffer is full or error from espconn_sent
// Use espbuffsend instead of espconn_sent as it solves the problem that espconn_sent must
// only be called *after* receiving an espconn_sent_callback for the previous packet.
sint8 ICACHE_FLASH_ATTR espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) {
if (conn->txbufferlen + len > MAX_TXBUFFER) {
os_printf("espbuffsend: txbuffer full on conn %p\n", conn);
if (conn->txbufferlen >= MAX_TXBUFFER) {
os_printf(tx_full_msg, conn);
return -128;
}
// make sure we indeed have a buffer
if (conn->txbuffer == NULL) conn->txbuffer = os_zalloc(MAX_TXBUFFER);
if (conn->txbuffer == NULL) {
os_printf("espbuffsend: cannot alloc tx buffer\n");
return -128;
}
os_memcpy(conn->txbuffer + conn->txbufferlen, data, len);
// add to send buffer
uint16_t avail = conn->txbufferlen+len > MAX_TXBUFFER ? MAX_TXBUFFER-conn->txbufferlen : len;
os_memcpy(conn->txbuffer + conn->txbufferlen, data, avail);
conn->txbufferlen += len;
if (conn->readytosend) {
return sendtxbuffer(conn);
} else {
//os_printf("%d QU %d\n", system_get_time(), conn->txbufferlen);
// try to send
sint8 result = ESPCONN_OK;
if (conn->readytosend) result = sendtxbuffer(conn);
if (avail < len) {
// some data didn't fit into the buffer
if (conn->txbufferlen == 0) {
// we sent the prior buffer, so try again
return espbuffsend(conn, data+avail, len-avail);
}
os_printf(tx_full_msg, conn);
return -128;
}
return ESPCONN_OK;
return result;
}
//callback after the data are sent
static void ICACHE_FLASH_ATTR serbridgeSentCb(void *arg) {
serbridgeConnData *conn = serbridgeFindConnData(arg);
serbridgeConnData *conn = ((struct espconn*)arg)->reverse;
//os_printf("Sent callback on conn %p\n", conn);
if (conn == NULL) return;
//os_printf("%d ST\n", system_get_time());
if (conn->sentbuffer != NULL) os_free(conn->sentbuffer);
conn->sentbuffer = NULL;
conn->readytosend = true;
sendtxbuffer(conn); // send possible new data in txbuffer
}
@ -192,7 +206,7 @@ void ICACHE_FLASH_ATTR serbridgeReset() {
// Receive callback
static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned short len) {
serbridgeConnData *conn = serbridgeFindConnData(arg);
serbridgeConnData *conn = ((struct espconn*)arg)->reverse;
//os_printf("Receive callback on conn %p\n", conn);
if (conn == NULL) return;
@ -245,35 +259,29 @@ static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned sh
serledFlash(50); // short blink on serial LED
}
// Error callback (it's really poorly named, it's not a "connection reconnected" callback,
// it's really a "connection broken, please reconnect" callback)
static void ICACHE_FLASH_ATTR serbridgeReconCb(void *arg, sint8 err) {
serbridgeConnData *conn=serbridgeFindConnData(arg);
if (conn == NULL) return;
// Close the connection
espconn_disconnect(conn->conn);
conn->conn = NULL;
}
// Disconnection callback
static void ICACHE_FLASH_ATTR serbridgeDisconCb(void *arg) {
// Iterate through all the connections and deallocate the ones that are in a state that
// indicates that they're closed
for (int i=0; i<MAX_CONN; i++) {
if (connData[i].conn != NULL &&
(connData[i].conn->state == ESPCONN_NONE || connData[i].conn->state == ESPCONN_CLOSE))
{
if (connData[i].conn_mode == cmAVR) {
// send reset to arduino/ARM
if (mcu_reset_pin >= 0) {
serbridgeConnData *conn = ((struct espconn*)arg)->reverse;
if (conn == NULL) return;
// Free buffers
if (conn->sentbuffer != NULL) os_free(conn->sentbuffer);
conn->sentbuffer = NULL;
if (conn->txbuffer != NULL) os_free(conn->txbuffer);
conn->txbuffer = NULL;
conn->txbufferlen = 0;
// Send reset to attached uC if it was in programming mode
if (conn->conn_mode == cmAVR && mcu_reset_pin >= 0) {
GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L);
GPIO_OUTPUT_SET(mcu_reset_pin, 1);
}
}
connData[i].conn = NULL;
}
}
conn->conn = NULL;
}
// Connection reset callback (note that there will be no DisconCb)
static void ICACHE_FLASH_ATTR serbridgeResetCb(void *arg, sint8 err) {
os_printf("serbridge: connection reset err=%d\n", err);
serbridgeDisconCb(arg);
}
// New connection callback, use one of the connection descriptors, if we have one left.
@ -290,15 +298,15 @@ static void ICACHE_FLASH_ATTR serbridgeConnectCb(void *arg) {
return;
}
connData[i].conn=conn;
connData[i].txbufferlen = 0;
os_memset(connData+i, 0, sizeof(struct serbridgeConnData));
connData[i].conn = conn;
conn->reverse = connData+i;
connData[i].readytosend = true;
connData[i].telnet_state = 0;
connData[i].conn_mode = cmInit;
espconn_regist_recvcb(conn, serbridgeRecvCb);
espconn_regist_reconcb(conn, serbridgeReconCb);
espconn_regist_disconcb(conn, serbridgeDisconCb);
espconn_regist_reconcb(conn, serbridgeResetCb);
espconn_regist_sentcb(conn, serbridgeSentCb);
espconn_set_opt(conn, ESPCONN_REUSEADDR|ESPCONN_NODELAY);
@ -349,10 +357,8 @@ void ICACHE_FLASH_ATTR serbridgeInitPins() {
void ICACHE_FLASH_ATTR serbridgeInit(int port) {
serbridgeInitPins();
int i;
for (i = 0; i < MAX_CONN; i++) {
for (int i = 0; i < MAX_CONN; i++) {
connData[i].conn = NULL;
connData[i].txbuffer = txbuffer[i];
}
serbridgeConn.type = ESPCONN_TCP;
serbridgeConn.state = ESPCONN_NONE;

@ -8,8 +8,8 @@
#define MAX_CONN 4
#define SER_BRIDGE_TIMEOUT 28799
//Max send buffer len
#define MAX_TXBUFFER 1024
// Send buffer size
#define MAX_TXBUFFER 2048
typedef struct serbridgeConnData serbridgeConnData;
@ -28,7 +28,8 @@ struct serbridgeConnData {
enum connModes conn_mode; // connection mode
char *txbuffer; // buffer for the data to send
uint16 txbufferlen; // length of data in txbuffer
bool readytosend; // true, if txbuffer can send by espconn_sent
char *sentbuffer; // buffer sent, awaiting callback to get freed
bool readytosend; // true, if txbuffer can be sent by espconn_sent
uint8_t telnet_state;
};

Loading…
Cancel
Save