From 737fabbd4c25c905e2e8b4cb092a03a9892b8448 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Sun, 13 Sep 2015 23:53:47 -0700 Subject: [PATCH 1/4] support programming-only port in serbridge --- esp-link/main.c | 2 +- serial/serbridge.c | 95 +++++++++++++++++++++++++++++++--------------- serial/serbridge.h | 8 ++-- 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/esp-link/main.c b/esp-link/main.c index 8061dfb..980fc11 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -127,7 +127,7 @@ void user_init(void) { // mount the http handlers httpdInit(builtInUrls, 80); // init the wifi-serial transparent bridge (port 23) - serbridgeInit(23); + serbridgeInit(23, 2323); uart_add_recv_cb(&serbridgeUartCb); #ifdef SHOW_HEAP_USE os_timer_disarm(&prHeapTimer); diff --git a/serial/serbridge.c b/serial/serbridge.c index 97ae22f..cecc065 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -17,8 +17,9 @@ #include "slip.h" #include "cmd.h" -static struct espconn serbridgeConn; -static esp_tcp serbridgeTcp; +static struct espconn serbridgeConn1; // plain bridging port +static struct espconn serbridgeConn2; // programming port +static esp_tcp serbridgeTcp1, serbridgeTcp2; static int8_t mcu_reset_pin, mcu_isp_pin; extern uint8_t slip_disabled; // disable slip to allow flashing of attached MCU @@ -162,6 +163,8 @@ serbridgeRecvCb(void *arg, char *data, unsigned short len) //os_printf("Receive callback on conn %p\n", conn); if (conn == NULL) return; + bool startPGM = false; + // at the start of a connection we're in cmInit mode and we wait for the first few characters // to arrive in order to decide what type of connection this is.. The following if statements // do this dispatch. An issue here is that we assume that the first few characters all arrive @@ -174,21 +177,8 @@ serbridgeRecvCb(void *arg, char *data, unsigned short len) if ((len == 2 && strncmp(data, "0 ", 2) == 0) || (len == 2 && strncmp(data, "?\n", 2) == 0) || (len == 3 && strncmp(data, "?\r\n", 3) == 0)) { -#ifdef SERBR_DBG - os_printf("MCU Reset=gpio%d ISP=gpio%d\n", mcu_reset_pin, mcu_isp_pin); -#endif - os_delay_us(2*1000L); // time for os_printf to happen - // send reset to arduino/ARM - if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 0); - os_delay_us(100L); - if (mcu_isp_pin >= 0) GPIO_OUTPUT_SET(mcu_isp_pin, 0); - os_delay_us(100L); - if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 1); - os_delay_us(100L); - if (mcu_isp_pin >= 0) GPIO_OUTPUT_SET(mcu_isp_pin, 1); - os_delay_us(1000L); - conn->conn_mode = cmAVR; - slip_disabled++; // disable SLIP so it doesn't interfere with flashing + startPGM = true; + conn->conn_mode = cmPGM; // If the connection starts with a telnet negotiation we will do telnet } @@ -206,8 +196,33 @@ serbridgeRecvCb(void *arg, char *data, unsigned short len) conn->conn_mode = cmTransparent; } + // if we start out in cmPGM mode due to a connection to the second port we need to do the + // reset dance right away + } else if (conn->conn_mode == cmPGMInit) { + conn->conn_mode = cmPGM; + startPGM = true; + } + + // do the programming reset dance + if (startPGM) { +#ifdef SERBR_DBG + os_printf("MCU Reset=gpio%d ISP=gpio%d\n", mcu_reset_pin, mcu_isp_pin); + os_delay_us(2*1000L); // time for os_printf to happen +#endif + // send reset to arduino/ARM, send "ISP" signal for the duration of the programming + if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 0); + os_delay_us(100L); + if (mcu_isp_pin >= 0) GPIO_OUTPUT_SET(mcu_isp_pin, 0); + os_delay_us(100L); + if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 1); + //os_delay_us(100L); + //if (mcu_isp_pin >= 0) GPIO_OUTPUT_SET(mcu_isp_pin, 1); + os_delay_us(1000L); // wait a millisecond before writing to the UART below + conn->conn_mode = cmPGM; + slip_disabled++; // disable SLIP so it doesn't interfere with flashing } + // write the buffer to the uart if (conn->conn_mode == cmTelnet) { conn->telnet_state = telnetUnwrap((uint8_t *)data, len, conn->telnet_state); @@ -346,7 +361,9 @@ serbridgeDisconCb(void *arg) 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) { + if (conn->conn_mode == cmPGM && mcu_reset_pin >= 0) { + if (mcu_isp_pin >= 0) GPIO_OUTPUT_SET(mcu_isp_pin, 1); + os_delay_us(100L); GPIO_OUTPUT_SET(mcu_reset_pin, 0); os_delay_us(100L); GPIO_OUTPUT_SET(mcu_reset_pin, 1); @@ -387,6 +404,9 @@ serbridgeConnectCb(void *arg) conn->reverse = connData+i; connData[i].readytosend = true; connData[i].conn_mode = cmInit; + // if it's the second port we start out in programming mode + if (conn->proto.tcp->local_port == serbridgeConn2.proto.tcp->local_port) + connData[i].conn_mode = cmPGMInit; espconn_regist_recvcb(conn, serbridgeRecvCb); espconn_regist_disconcb(conn, serbridgeDisconCb); @@ -430,20 +450,33 @@ serbridgeInitPins() // Start transparent serial bridge TCP server on specified port (typ. 23) void ICACHE_FLASH_ATTR -serbridgeInit(int port) +serbridgeInit(int port1, int port2) { serbridgeInitPins(); - for (int i = 0; i < MAX_CONN; i++) { - connData[i].conn = NULL; - } - serbridgeConn.type = ESPCONN_TCP; - serbridgeConn.state = ESPCONN_NONE; - serbridgeTcp.local_port = port; - serbridgeConn.proto.tcp = &serbridgeTcp; - - espconn_regist_connectcb(&serbridgeConn, serbridgeConnectCb); - espconn_accept(&serbridgeConn); - espconn_tcp_set_max_con_allow(&serbridgeConn, MAX_CONN); - espconn_regist_time(&serbridgeConn, SER_BRIDGE_TIMEOUT, 0); + os_memset(connData, 0, sizeof(connData)); + os_memset(&serbridgeTcp1, 0, sizeof(serbridgeTcp1)); + os_memset(&serbridgeTcp2, 0, sizeof(serbridgeTcp2)); + + // set-up the primary port for plain bridging + serbridgeConn1.type = ESPCONN_TCP; + serbridgeConn1.state = ESPCONN_NONE; + serbridgeTcp1.local_port = port1; + serbridgeConn1.proto.tcp = &serbridgeTcp1; + + espconn_regist_connectcb(&serbridgeConn1, serbridgeConnectCb); + espconn_accept(&serbridgeConn1); + espconn_tcp_set_max_con_allow(&serbridgeConn1, MAX_CONN); + espconn_regist_time(&serbridgeConn1, SER_BRIDGE_TIMEOUT, 0); + + // set-up the secondary port for programming + serbridgeConn2.type = ESPCONN_TCP; + serbridgeConn2.state = ESPCONN_NONE; + serbridgeTcp2.local_port = port2; + serbridgeConn2.proto.tcp = &serbridgeTcp2; + + espconn_regist_connectcb(&serbridgeConn2, serbridgeConnectCb); + espconn_accept(&serbridgeConn2); + espconn_tcp_set_max_con_allow(&serbridgeConn2, MAX_CONN); + espconn_regist_time(&serbridgeConn2, SER_BRIDGE_TIMEOUT, 0); } diff --git a/serial/serbridge.h b/serial/serbridge.h index 7c29159..d8d6e96 100644 --- a/serial/serbridge.h +++ b/serial/serbridge.h @@ -13,10 +13,9 @@ enum connModes { cmInit = 0, // initialization mode: nothing received yet + cmPGMInit, // initialization mode for programming cmTransparent, // transparent mode - cmAVR, // Arduino/AVR programming mode - cmARM, // ARM (LPC8xx) programming - cmEcho, // simply echo characters (used for debugging latency) + cmPGM, // Arduino/AVR/ARM programming mode cmTelnet, // use telnet escape sequences for programming mode }; @@ -30,7 +29,8 @@ typedef struct serbridgeConnData { uint8_t telnet_state; } serbridgeConnData; -void ICACHE_FLASH_ATTR serbridgeInit(int port); +// port1 is transparent&programming, second port is programming only +void ICACHE_FLASH_ATTR serbridgeInit(int port1, int port2); void ICACHE_FLASH_ATTR serbridgeInitPins(void); void ICACHE_FLASH_ATTR serbridgeUartCb(char *buf, short len); void ICACHE_FLASH_ATTR serbridgeReset(); From e9b0132eeb07c38703daf58363093b3157bebbf6 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Sun, 13 Sep 2015 23:54:10 -0700 Subject: [PATCH 2/4] fix issues with MQTT CMD callbacks --- cmd/cmd.c | 40 +++-- cmd/cmd.h | 2 + cmd/handlers.c | 18 --- esp-link/cgimqtt.c | 5 +- include/user_config.h | 2 +- mqtt/mqtt.c | 16 +- mqtt/mqtt.h | 5 +- mqtt/mqtt_cmd.c | 352 +++++++++++++++++++++++------------------- mqtt/mqtt_cmd.h | 1 - serial/slip.c | 2 +- 10 files changed, 242 insertions(+), 201 deletions(-) diff --git a/cmd/cmd.c b/cmd/cmd.c index f3bcbba..520143e 100644 --- a/cmd/cmd.c +++ b/cmd/cmd.c @@ -81,9 +81,7 @@ CMD_Exec(const CmdList *scp, CmdPacket *packet) { // Iterate through the command table and call the appropriate function while (scp->sc_function != NULL) { if(scp->sc_name == packet->cmd) { -#ifdef CMD_DBG - os_printf("CMD: Dispatching cmd=%d\n", packet->cmd); -#endif + //os_printf("CMD: Dispatching cmd=%d\n", packet->cmd); // call command function uint32_t ret = scp->sc_function(packet); // if requestor asked for a response, send it @@ -108,6 +106,14 @@ CMD_Exec(const CmdList *scp, CmdPacket *packet) { return 0; } +char *cmd_names[] = { + "NULL", "RESET", "IS_READY", "WIFI_CONNECT", + "MQTT_SETUP", "MQTT_CONNECT", "MQTT_DISCONNECT", + "MQTT_PUBLISH", "MQTT_SUBSCRIBE", "MQTT_LWT", "MQTT_EVENTS", + "REST_SETUP", "REST_REQUEST", "REST_SETHEADER", "REST_EVENTS", + "CB_ADD", "CB_EVENTS", +}; + // Parse a packet and print info about it void ICACHE_FLASH_ATTR CMD_parse_packet(uint8_t *buf, short len) { @@ -118,29 +124,25 @@ CMD_parse_packet(uint8_t *buf, short len) { CmdPacket *packet = (CmdPacket*)buf; uint8_t *data_ptr = (uint8_t*)&packet->args; uint8_t *data_limit = data_ptr+len; - uint16_t argc = packet->argc; #ifdef CMD_DBG uint16_t argn = 0; - os_printf("CMD: cmd=%d argc=%d cb=%p ret=%lu\n", - packet->cmd, packet->argc, (void *)packet->callback, packet->_return); + os_printf("CMD: cmd=%d(%s) argc=%d cb=%p ret=%lu\n", + packet->cmd, cmd_names[packet->cmd], packet->argc, (void *)packet->callback, packet->_return); #endif +#if 0 // print out arguments + uint16_t argc = packet->argc; while (data_ptr+2 < data_limit && argc--) { short l = *(uint16_t*)data_ptr; -#ifdef CMD_DBG os_printf("CMD: arg[%d] len=%d:", argn++, l); -#endif data_ptr += 2; while (data_ptr < data_limit && l--) { -#ifdef CMD_DBG os_printf(" %02X", *data_ptr++); -#endif } -#ifdef CMD_DBG os_printf("\n"); -#endif } +#endif if (data_ptr <= data_limit) { CMD_Exec(commands, packet); @@ -187,6 +189,20 @@ CMD_PopArg(CmdRequest *req, void *data, uint16_t len) { return 0; } +// Skip the next argument +void ICACHE_FLASH_ATTR +CMD_SkipArg(CmdRequest *req) { + uint16_t length; + + if (req->arg_num >= req->cmd->argc) return; + + length = *(uint16_t*)req->arg_ptr; + + req->arg_ptr += 2; + req->arg_ptr += length; + req->arg_num ++; +} + // Return the length of the next argument uint16_t ICACHE_FLASH_ATTR CMD_ArgLen(CmdRequest *req) { diff --git a/cmd/cmd.h b/cmd/cmd.h index 2d07e1c..d8b5550 100644 --- a/cmd/cmd.h +++ b/cmd/cmd.h @@ -99,5 +99,7 @@ uint32_t CMD_GetArgc(CmdRequest *req); uint16_t CMD_ArgLen(CmdRequest *req); // Copy next arg from request into the data pointer, returns 0 on success, -1 on error int32_t CMD_PopArg(CmdRequest *req, void *data, uint16_t len); +// Skip next arg +void CMD_SkipArg(CmdRequest *req); #endif diff --git a/cmd/handlers.c b/cmd/handlers.c index 339c1dd..3b21aea 100644 --- a/cmd/handlers.c +++ b/cmd/handlers.c @@ -52,18 +52,12 @@ cmdCallback callbacks[MAX_CALLBACKS]; // cleared in CMD_Reset // Command handler for IsReady (healthcheck) command static uint32_t ICACHE_FLASH_ATTR CMD_IsReady(CmdPacket *cmd) { -#ifdef CMD_DBG - os_printf("CMD_IsReady: Check ready\n"); -#endif return 1; } // Command handler for Null command static uint32_t ICACHE_FLASH_ATTR CMD_Null(CmdPacket *cmd) { -#ifdef CMD_DBG - os_printf("CMD_Null: NULL/unsupported command\n"); -#endif return 1; } @@ -72,9 +66,6 @@ CMD_Null(CmdPacket *cmd) { // uC. static uint32_t ICACHE_FLASH_ATTR CMD_Reset(CmdPacket *cmd) { -#ifdef CMD_DBG - os_printf("CMD_Reset\n"); -#endif // clear callbacks table os_memset(callbacks, 0, sizeof(callbacks)); return 1; @@ -140,9 +131,6 @@ static uint32_t ICACHE_FLASH_ATTR CMD_WifiConnect(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); -#ifdef CMD_DBG - os_printf("CMD_WifiConnect: setup argc=%ld\n", CMD_GetArgc(&req)); -#endif if(cmd->argc != 2 || cmd->callback == 0) return 0; @@ -162,9 +150,6 @@ static uint32_t ICACHE_FLASH_ATTR CMD_AddCallback(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); -#ifdef CMD_DBG - os_printf("CMD_AddCallback: setup argc=%ld\n", CMD_GetArgc(&req)); -#endif if (cmd->argc != 1 || cmd->callback == 0) return 0; @@ -173,9 +158,6 @@ CMD_AddCallback(CmdPacket *cmd) { // get the sensor name len = CMD_ArgLen(&req); -#ifdef CMD_DBG - os_printf("CMD_AddCallback: name len=%d\n", len); -#endif if (len > 15) return 0; // max size of name is 15 characters if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0; name[len] = 0; diff --git a/esp-link/cgimqtt.c b/esp-link/cgimqtt.c index 98fcd8b..19a950e 100644 --- a/esp-link/cgimqtt.c +++ b/esp-link/cgimqtt.c @@ -119,7 +119,10 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) { #ifdef CGIMQTT_DBG os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable); #endif - // TODO + if (flashConfig.mqtt_enable && strlen(flashConfig.mqtt_host) > 0) + MQTT_Reconnect(&mqttClient); + else + MQTT_Disconnect(&mqttClient); } // no action required if mqtt status settings change, they just get picked up at the diff --git a/include/user_config.h b/include/user_config.h index bdbe66c..78c2ded 100644 --- a/include/user_config.h +++ b/include/user_config.h @@ -25,7 +25,7 @@ #define RESTCMD_DBG #define SERBR_DBG #define SERLED_DBG -#define SLIP_DBG +#undef SLIP_DBG #define UART_DBG // If defined, the default hostname for DHCP will include the chip ID to make it unique diff --git a/mqtt/mqtt.c b/mqtt/mqtt.c index cf0bbd5..fe5c191 100644 --- a/mqtt/mqtt.c +++ b/mqtt/mqtt.c @@ -743,8 +743,19 @@ mqtt_doAbort(MQTT_Client* client) { client->timeoutTick = 2; // reconnect in a few seconds } +void ICACHE_FLASH_ATTR +MQTT_Reconnect(MQTT_Client* mqttClient) { + DBG_MQTT("MQTT: Reconnect requested\n"); + if (mqttClient->connState == MQTT_DISCONNECTED) + MQTT_Connect(mqttClient); + else if (mqttClient->connState == MQTT_CONNECTED) + mqtt_doAbort(mqttClient); + // in other cases we're already in the reconnecting process +} + void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client* mqttClient) { + DBG_MQTT("MQTT: Disconnect requested\n"); os_timer_disarm(&mqttClient->mqttTimer); if (mqttClient->connState == MQTT_DISCONNECTED) return; if (mqttClient->connState == TCP_RECONNECT_REQ) { @@ -767,11 +778,6 @@ MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb) { mqttClient->disconnectedCb = disconnectedCb; } -void ICACHE_FLASH_ATTR -MQTT_OnTcpDisconnected(MQTT_Client *mqttClient, MqttCallback tcpDisconnectedCb) { - mqttClient->tcpDisconnectedCb = tcpDisconnectedCb; -} - void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb) { mqttClient->dataCb = dataCb; diff --git a/mqtt/mqtt.h b/mqtt/mqtt.h index 3155dc8..fe3fe0e 100644 --- a/mqtt/mqtt.h +++ b/mqtt/mqtt.h @@ -82,8 +82,6 @@ typedef struct { MqttCallback cmdConnectedCb; MqttCallback disconnectedCb; MqttCallback cmdDisconnectedCb; - MqttCallback tcpDisconnectedCb; - MqttCallback cmdTcpDisconnectedCb; MqttCallback publishedCb; MqttCallback cmdPublishedCb; MqttDataCallback dataCb; @@ -102,6 +100,9 @@ void MQTT_Init(MQTT_Client* mqttClient, char* host, uint32 port, void MQTT_InitLWT(MQTT_Client* mqttClient, char* will_topic, char* will_msg, uint8_t will_qos, uint8_t will_retain); +// Disconnect and reconnect in order to change params (such as LWT) +void MQTT_Reconnect(MQTT_Client* mqttClient); + // Kick of a persistent connection to the broker, will reconnect anytime conn breaks void MQTT_Connect(MQTT_Client* mqttClient); diff --git a/mqtt/mqtt_cmd.c b/mqtt/mqtt_cmd.c index 421aae7..503b41e 100644 --- a/mqtt/mqtt_cmd.c +++ b/mqtt/mqtt_cmd.c @@ -1,5 +1,10 @@ +// +// MQTT Commands coming in from the attache microcontrollver over the serial port +// + #include #include "mqtt.h" +#include "mqtt_client.h" #include "mqtt_cmd.h" #ifdef MQTTCMD_DBG @@ -8,8 +13,13 @@ #define DBG_MQTTCMD(format, ...) do { } while(0) #endif +// if MQTT_1_CLIENT is defined we only support the one client that is built into esp-link. +// this keeps everything simpler. Undefining it brings back old code that supports creating +// a new client and setting all its params. Most likely that old code no longer works... +#define MQTT_1_CLIENT -uint32_t connectedCb = 0, disconnectCb = 0, tcpDisconnectedCb = 0, publishedCb = 0, dataCb = 0; +// callbacks to the attached uC +uint32_t connectedCb = 0, disconnectCb = 0, publishedCb = 0, dataCb = 0; void ICACHE_FLASH_ATTR cmdMqttConnectedCb(uint32_t* args) { @@ -24,15 +34,6 @@ cmdMqttConnectedCb(uint32_t* args) { CMD_ResponseEnd(crc); } -void ICACHE_FLASH_ATTR -cmdMqttTcpDisconnectedCb(uint32_t *args) { - MQTT_Client* client = (MQTT_Client*)args; - MqttCmdCb *cb = (MqttCmdCb*)client->user_data; - DBG_MQTTCMD("MQTT: TCP Disconnected\n"); - uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0); - CMD_ResponseEnd(crc); -} - void ICACHE_FLASH_ATTR cmdMqttDisconnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; @@ -63,11 +64,175 @@ cmdMqttDataCb(uint32_t* args, const char* topic, uint32_t topic_len, const char* CMD_ResponseEnd(crc); } +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Lwt(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 5) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); +#ifdef MQTT_1_CLIENT + MQTT_Client* client = &mqttClient; +#else + MQTT_Client* client = (MQTT_Client*)client_ptr; + DBG_MQTTCMD("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr); +#endif + + // free old topic & message + if (client->connect_info.will_topic) + os_free(client->connect_info.will_topic); + if (client->connect_info.will_message) + os_free(client->connect_info.will_message); + + uint16_t len; + + // get topic + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + client->connect_info.will_topic = (char*)os_zalloc(len + 1); + CMD_PopArg(&req, client->connect_info.will_topic, len); + client->connect_info.will_topic[len] = 0; + + // get message + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + client->connect_info.will_message = (char*)os_zalloc(len + 1); + CMD_PopArg(&req, client->connect_info.will_message, len); + client->connect_info.will_message[len] = 0; + + // get qos + CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_qos, 4); + + // get retain + CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); + + DBG_MQTTCMD("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%d, retain=%d\n", + client->connect_info.will_topic, + client->connect_info.will_message, + client->connect_info.will_qos, + client->connect_info.will_retain); + + // trigger a reconnect to set the LWT + MQTT_Reconnect(client); + return 1; +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Publish(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 6) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); +#ifdef MQTT_1_CLIENT + MQTT_Client* client = &mqttClient; +#else + MQTT_Client* client = (MQTT_Client*)client_ptr; + DBG_MQTTCMD("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr); +#endif + + uint16_t len; + + // get topic + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + uint8_t *topic = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, topic, len); + topic[len] = 0; + + // get data + len = CMD_ArgLen(&req); + uint8_t *data = (uint8_t*)os_zalloc(len+1); + if (!data) { // safety check + os_free(topic); + return 0; + } + CMD_PopArg(&req, data, len); + data[len] = 0; + + uint32_t qos, retain, data_len; + + // get data length + // this isn't used but we have to pull it off the stack + CMD_PopArg(&req, (uint8_t*)&data_len, 4); + + // get qos + CMD_PopArg(&req, (uint8_t*)&qos, 4); + + // get retain + CMD_PopArg(&req, (uint8_t*)&retain, 4); + + DBG_MQTTCMD("MQTT: MQTTCMD_Publish topic=%s, data_len=%d, qos=%ld, retain=%ld\n", + topic, + os_strlen((char*)data), + qos, + retain); + + MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain); + os_free(topic); + os_free(data); + return 1; +} + +uint32_t ICACHE_FLASH_ATTR +MQTTCMD_Subscribe(CmdPacket *cmd) { + CmdRequest req; + CMD_Request(&req, cmd); + + if (CMD_GetArgc(&req) != 3) + return 0; + + // get mqtt client + uint32_t client_ptr; + CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); +#ifdef MQTT_1_CLIENT + MQTT_Client* client = &mqttClient; +#else + MQTT_Client* client = (MQTT_Client*)client_ptr; + DBG_MQTTCMD("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr); +#endif + + uint16_t len; + + // get topic + len = CMD_ArgLen(&req); + if (len > 128) return 0; // safety check + uint8_t* topic = (uint8_t*)os_zalloc(len + 1); + CMD_PopArg(&req, topic, len); + topic[len] = 0; + + // get qos + uint32_t qos = 0; + CMD_PopArg(&req, (uint8_t*)&qos, 4); + + DBG_MQTTCMD("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos); + + MQTT_Subscribe(client, (char*)topic, (uint8_t)qos); + os_free(topic); + return 1; +} + uint32_t ICACHE_FLASH_ATTR MQTTCMD_Setup(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef MQTT_1_CLIENT + MQTT_Client* client = &mqttClient; + CMD_SkipArg(&req); + CMD_SkipArg(&req); + CMD_SkipArg(&req); + CMD_SkipArg(&req); + CMD_SkipArg(&req); +#else if (CMD_GetArgc(&req) != 9) return 0; @@ -77,12 +242,9 @@ MQTTCMD_Setup(CmdPacket *cmd) { if (client == NULL) return 0; os_memset(client, 0, clientLen); - return 0; -#if 0 - uint16_t len; uint8_t *client_id, *user_data, *pass_data; - uint32_t keepalive, clean_session, cb_data; + uint32_t keepalive, clean_session; // get client id len = CMD_ArgLen(&req); @@ -118,8 +280,14 @@ MQTTCMD_Setup(CmdPacket *cmd) { // TODO: why malloc these all here, pass to MQTT_InitClient to be malloc'd again? MQTT_InitClient(client, (char*)client_id, (char*)user_data, (char*)pass_data, keepalive, clean_session); + os_free(client_id); + os_free(user_data); + os_free(pass_data); +#endif + // create callback MqttCmdCb* callback = (MqttCmdCb*)os_zalloc(sizeof(MqttCmdCb)); + uint32_t cb_data; CMD_PopArg(&req, (uint8_t*)&cb_data, 4); callback->connectedCb = cb_data; @@ -137,72 +305,18 @@ MQTTCMD_Setup(CmdPacket *cmd) { client->cmdPublishedCb = cmdMqttPublishedCb; client->cmdDataCb = cmdMqttDataCb; - if (CMD_GetArgc(&req) == 10) { - CMD_PopArg(&req, (uint8_t*)&cb_data, 4); - callback->tcpDisconnectedCb = cb_data; - client->cmdTcpDisconnectedCb = cmdMqttTcpDisconnectedCb; - } - - os_free(client_id); - os_free(user_data); - os_free(pass_data); - - return (uint32_t)client; -#endif + return 0xf00df00d; //(uint32_t)client; } uint32_t ICACHE_FLASH_ATTR -MQTTCMD_Lwt(CmdPacket *cmd) { +MQTTCMD_Connect(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); - if (CMD_GetArgc(&req) != 5) - return 0; - - // get mqtt client - uint32_t client_ptr; - CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); - MQTT_Client* client = (MQTT_Client*)client_ptr; - DBG_MQTTCMD("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr); - - uint16_t len; - - // get topic - if (client->connect_info.will_topic) - os_free(client->connect_info.will_topic); - len = CMD_ArgLen(&req); - if (len > 128) return 0; // safety check - client->connect_info.will_topic = (char*)os_zalloc(len + 1); - CMD_PopArg(&req, client->connect_info.will_topic, len); - client->connect_info.will_topic[len] = 0; - - // get message - if (client->connect_info.will_message) - os_free(client->connect_info.will_message); - len = CMD_ArgLen(&req); - // TODO: safety check - client->connect_info.will_message = (char*)os_zalloc(len + 1); - CMD_PopArg(&req, client->connect_info.will_message, len); - client->connect_info.will_message[len] = 0; - - // get qos - CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_qos, 4); - - // get retain - CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); - DBG_MQTTCMD("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%d, retain=%d\n", - client->connect_info.will_topic, - client->connect_info.will_message, - client->connect_info.will_qos, - client->connect_info.will_retain); +#ifdef MQTT_1_CLIENT return 1; -} - -uint32_t ICACHE_FLASH_ATTR -MQTTCMD_Connect(CmdPacket *cmd) { - CmdRequest req; - CMD_Request(&req, cmd); +#else if (CMD_GetArgc(&req) != 4) return 0; @@ -235,6 +349,7 @@ MQTTCMD_Connect(CmdPacket *cmd) { MQTT_Connect(client); return 1; +#endif } uint32_t ICACHE_FLASH_ATTR @@ -242,6 +357,10 @@ MQTTCMD_Disconnect(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef MQTT_1_CLIENT + return 1; + +#else if (CMD_GetArgc(&req) != 1) return 0; @@ -254,92 +373,5 @@ MQTTCMD_Disconnect(CmdPacket *cmd) { // disconnect MQTT_Disconnect(client); return 1; -} - -uint32_t ICACHE_FLASH_ATTR -MQTTCMD_Publish(CmdPacket *cmd) { - CmdRequest req; - CMD_Request(&req, cmd); - - if (CMD_GetArgc(&req) != 6) - return 0; - - // get mqtt client - uint32_t client_ptr; - CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); - MQTT_Client* client = (MQTT_Client*)client_ptr; - DBG_MQTTCMD("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr); - - uint16_t len; - uint8_t *topic, *data; - uint32_t qos = 0, retain = 0, data_len; - - // get topic - len = CMD_ArgLen(&req); - if (len > 128) return 0; // safety check - topic = (uint8_t*)os_zalloc(len + 1); - CMD_PopArg(&req, topic, len); - topic[len] = 0; - - // get data - len = CMD_ArgLen(&req); - // TODO: Safety check - // TODO: this was orignially zalloc len not len+1 - data = (uint8_t*)os_zalloc(len+1); - CMD_PopArg(&req, data, len); - // TODO: next line not originally present - data[len] = 0; - - // get data length - // TODO: this isn't used but we have to pull it off the stack - CMD_PopArg(&req, (uint8_t*)&data_len, 4); - - // get qos - CMD_PopArg(&req, (uint8_t*)&qos, 4); - - // get retain - CMD_PopArg(&req, (uint8_t*)&retain, 4); - DBG_MQTTCMD("MQTT: MQTTCMD_Publish topic=%s, data_len=%d, qos=%ld, retain=%ld\n", - topic, - os_strlen((char*)data), - qos, - retain); - - MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain); - os_free(topic); - os_free(data); - return 1; -} - -uint32_t ICACHE_FLASH_ATTR -MQTTCMD_Subscribe(CmdPacket *cmd) { - CmdRequest req; - CMD_Request(&req, cmd); - - if (CMD_GetArgc(&req) != 3) - return 0; - - // get mqtt client - uint32_t client_ptr; - CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); - MQTT_Client* client = (MQTT_Client*)client_ptr; - DBG_MQTTCMD("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr); - - uint16_t len; - uint8_t* topic; - uint32_t qos = 0; - - // get topic - len = CMD_ArgLen(&req); - if (len > 128) return 0; // safety check - topic = (uint8_t*)os_zalloc(len + 1); - CMD_PopArg(&req, topic, len); - topic[len] = 0; - - // get qos - CMD_PopArg(&req, (uint8_t*)&qos, 4); - DBG_MQTTCMD("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos); - MQTT_Subscribe(client, (char*)topic, (uint8_t)qos); - os_free(topic); - return 1; +#endif } diff --git a/mqtt/mqtt_cmd.h b/mqtt/mqtt_cmd.h index 72ffe98..69997d1 100644 --- a/mqtt/mqtt_cmd.h +++ b/mqtt/mqtt_cmd.h @@ -8,7 +8,6 @@ typedef struct { uint32_t disconnectedCb; uint32_t publishedCb; uint32_t dataCb; - uint32_t tcpDisconnectedCb; } MqttCmdCb; uint32_t MQTTCMD_Connect(CmdPacket *cmd); diff --git a/serial/slip.c b/serial/slip.c index 9db748e..4125a08 100644 --- a/serial/slip.c +++ b/serial/slip.c @@ -46,9 +46,9 @@ slip_process() { if (crc == rcv) { CMD_parse_packet((uint8_t*)slip_buf, slip_len-2); } else { -#ifdef SLIP_DBG os_printf("SLIP: bad CRC, crc=%x rcv=%x\n", crc, rcv); +#ifdef SLIP_DBG for (short i=0; i= ' ' && slip_buf[i] <= '~') os_printf("%c", slip_buf[i]); From 726d45869a5e0e614755f13a935f18bd81595e68 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 15 Sep 2015 20:27:48 -0700 Subject: [PATCH 3/4] add logging to serbridge --- serial/serbridge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serial/serbridge.c b/serial/serbridge.c index cecc065..391dd37 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -243,7 +243,7 @@ sendtxbuffer(serbridgeConnData *conn) { sint8 result = ESPCONN_OK; if (conn->txbufferlen != 0) { - //os_printf("%d TX %d\n", system_get_time(), conn->txbufferlen); + os_printf("TX %p %d\n", conn, conn->txbufferlen); conn->readytosend = false; result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen); conn->txbufferlen = 0; @@ -309,7 +309,7 @@ static void ICACHE_FLASH_ATTR serbridgeSentCb(void *arg) { serbridgeConnData *conn = ((struct espconn*)arg)->reverse; - //os_printf("Sent callback on conn %p\n", conn); + os_printf("Sent CB %p\n", conn); if (conn == NULL) return; //os_printf("%d ST\n", system_get_time()); if (conn->sentbuffer != NULL) os_free(conn->sentbuffer); From 2c29e2940a51aa182493da9890ceac2b2e652398 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 15 Sep 2015 21:00:37 -0700 Subject: [PATCH 4/4] handle dead connections in serbridge --- serial/serbridge.c | 28 ++++++++++++++++++++-------- serial/serbridge.h | 9 +++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/serial/serbridge.c b/serial/serbridge.c index 765ed77..b3207f1 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -35,6 +35,7 @@ static sint8 ICACHE_FLASH_ATTR sendtxbuffer(serbridgeConnData *conn) { if (result != ESPCONN_OK) { os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn); conn->txbufferlen = 0; + conn->txoverflow_at = system_get_time(); } else { conn->sentbuffer = conn->txbuffer; conn->txbuffer = NULL; @@ -44,18 +45,13 @@ static sint8 ICACHE_FLASH_ATTR sendtxbuffer(serbridgeConnData *conn) { 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 >= MAX_TXBUFFER) { - os_printf(tx_full_msg, conn); - return -128; - } + if (conn->txbufferlen >= MAX_TXBUFFER) goto overflow; // make sure we indeed have a buffer if (conn->txbuffer == NULL) conn->txbuffer = os_zalloc(MAX_TXBUFFER); @@ -79,10 +75,25 @@ sint8 ICACHE_FLASH_ATTR espbuffsend(serbridgeConnData *conn, const char *data, u // we sent the prior buffer, so try again return espbuffsend(conn, data+avail, len-avail); } - os_printf(tx_full_msg, conn); - return -128; + goto overflow; } return result; + +overflow: + if (conn->txoverflow_at) { + // we've already been overflowing + if (system_get_time() - conn->txoverflow_at > 10*1000*1000) { + // no progress in 10 seconds, kill the connection + os_printf("serbridge: killing overlowing stuck conn %p\n", conn); + espconn_disconnect(conn->conn); + } + // else be silent, we already printed an error + } else { + // print 1-time message and take timestamp + os_printf("serbridge: txbuffer full, conn %p\n", conn); + conn->txoverflow_at = system_get_time(); + } + return -128; } //callback after the data are sent @@ -94,6 +105,7 @@ static void ICACHE_FLASH_ATTR serbridgeSentCb(void *arg) { if (conn->sentbuffer != NULL) os_free(conn->sentbuffer); conn->sentbuffer = NULL; conn->readytosend = true; + conn->txoverflow_at = 0; sendtxbuffer(conn); // send possible new data in txbuffer } diff --git a/serial/serbridge.h b/serial/serbridge.h index f824027..02ded11 100644 --- a/serial/serbridge.h +++ b/serial/serbridge.h @@ -6,10 +6,10 @@ #include #define MAX_CONN 4 -#define SER_BRIDGE_TIMEOUT 28799 +#define SER_BRIDGE_TIMEOUT 300 // 300 seconds = 5 minutes // Send buffer size -#define MAX_TXBUFFER 2048 +#define MAX_TXBUFFER (2*1460) typedef struct serbridgeConnData serbridgeConnData; @@ -26,11 +26,12 @@ enum connModes { struct serbridgeConnData { struct espconn *conn; enum connModes conn_mode; // connection mode - char *txbuffer; // buffer for the data to send + uint8_t telnet_state; uint16 txbufferlen; // length of data in txbuffer + char *txbuffer; // buffer for the data to send char *sentbuffer; // buffer sent, awaiting callback to get freed + uint32_t txoverflow_at; // when the transmitter started to overflow bool readytosend; // true, if txbuffer can be sent by espconn_sent - uint8_t telnet_state; }; void ICACHE_FLASH_ATTR serbridgeInit(int port);