pull/49/head
Benjamin Runnels 9 years ago
commit 587df27d78
  1. 40
      cmd/cmd.c
  2. 2
      cmd/cmd.h
  3. 18
      cmd/handlers.c
  4. 5
      esp-link/cgimqtt.c
  5. 2
      esp-link/main.c
  6. 2
      include/user_config.h
  7. 16
      mqtt/mqtt.c
  8. 5
      mqtt/mqtt.h
  9. 352
      mqtt/mqtt_cmd.c
  10. 1
      mqtt/mqtt_cmd.h
  11. 129
      serial/serbridge.c
  12. 17
      serial/serbridge.h
  13. 2
      serial/slip.c

@ -81,9 +81,7 @@ CMD_Exec(const CmdList *scp, CmdPacket *packet) {
// Iterate through the command table and call the appropriate function // Iterate through the command table and call the appropriate function
while (scp->sc_function != NULL) { while (scp->sc_function != NULL) {
if(scp->sc_name == packet->cmd) { if(scp->sc_name == packet->cmd) {
#ifdef CMD_DBG //os_printf("CMD: Dispatching cmd=%d\n", packet->cmd);
os_printf("CMD: Dispatching cmd=%d\n", packet->cmd);
#endif
// call command function // call command function
uint32_t ret = scp->sc_function(packet); uint32_t ret = scp->sc_function(packet);
// if requestor asked for a response, send it // if requestor asked for a response, send it
@ -108,6 +106,14 @@ CMD_Exec(const CmdList *scp, CmdPacket *packet) {
return 0; 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 // Parse a packet and print info about it
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
CMD_parse_packet(uint8_t *buf, short len) { CMD_parse_packet(uint8_t *buf, short len) {
@ -118,29 +124,25 @@ CMD_parse_packet(uint8_t *buf, short len) {
CmdPacket *packet = (CmdPacket*)buf; CmdPacket *packet = (CmdPacket*)buf;
uint8_t *data_ptr = (uint8_t*)&packet->args; uint8_t *data_ptr = (uint8_t*)&packet->args;
uint8_t *data_limit = data_ptr+len; uint8_t *data_limit = data_ptr+len;
uint16_t argc = packet->argc;
#ifdef CMD_DBG #ifdef CMD_DBG
uint16_t argn = 0; uint16_t argn = 0;
os_printf("CMD: cmd=%d argc=%d cb=%p ret=%lu\n", os_printf("CMD: cmd=%d(%s) argc=%d cb=%p ret=%lu\n",
packet->cmd, packet->argc, (void *)packet->callback, packet->_return); packet->cmd, cmd_names[packet->cmd], packet->argc, (void *)packet->callback, packet->_return);
#endif #endif
#if 0
// print out arguments // print out arguments
uint16_t argc = packet->argc;
while (data_ptr+2 < data_limit && argc--) { while (data_ptr+2 < data_limit && argc--) {
short l = *(uint16_t*)data_ptr; short l = *(uint16_t*)data_ptr;
#ifdef CMD_DBG
os_printf("CMD: arg[%d] len=%d:", argn++, l); os_printf("CMD: arg[%d] len=%d:", argn++, l);
#endif
data_ptr += 2; data_ptr += 2;
while (data_ptr < data_limit && l--) { while (data_ptr < data_limit && l--) {
#ifdef CMD_DBG
os_printf(" %02X", *data_ptr++); os_printf(" %02X", *data_ptr++);
#endif
} }
#ifdef CMD_DBG
os_printf("\n"); os_printf("\n");
#endif
} }
#endif
if (data_ptr <= data_limit) { if (data_ptr <= data_limit) {
CMD_Exec(commands, packet); CMD_Exec(commands, packet);
@ -187,6 +189,20 @@ CMD_PopArg(CmdRequest *req, void *data, uint16_t len) {
return 0; 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 // Return the length of the next argument
uint16_t ICACHE_FLASH_ATTR uint16_t ICACHE_FLASH_ATTR
CMD_ArgLen(CmdRequest *req) { CMD_ArgLen(CmdRequest *req) {

@ -99,5 +99,7 @@ uint32_t CMD_GetArgc(CmdRequest *req);
uint16_t CMD_ArgLen(CmdRequest *req); uint16_t CMD_ArgLen(CmdRequest *req);
// Copy next arg from request into the data pointer, returns 0 on success, -1 on error // 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); int32_t CMD_PopArg(CmdRequest *req, void *data, uint16_t len);
// Skip next arg
void CMD_SkipArg(CmdRequest *req);
#endif #endif

@ -52,18 +52,12 @@ cmdCallback callbacks[MAX_CALLBACKS]; // cleared in CMD_Reset
// Command handler for IsReady (healthcheck) command // Command handler for IsReady (healthcheck) command
static uint32_t ICACHE_FLASH_ATTR static uint32_t ICACHE_FLASH_ATTR
CMD_IsReady(CmdPacket *cmd) { CMD_IsReady(CmdPacket *cmd) {
#ifdef CMD_DBG
os_printf("CMD_IsReady: Check ready\n");
#endif
return 1; return 1;
} }
// Command handler for Null command // Command handler for Null command
static uint32_t ICACHE_FLASH_ATTR static uint32_t ICACHE_FLASH_ATTR
CMD_Null(CmdPacket *cmd) { CMD_Null(CmdPacket *cmd) {
#ifdef CMD_DBG
os_printf("CMD_Null: NULL/unsupported command\n");
#endif
return 1; return 1;
} }
@ -72,9 +66,6 @@ CMD_Null(CmdPacket *cmd) {
// uC. // uC.
static uint32_t ICACHE_FLASH_ATTR static uint32_t ICACHE_FLASH_ATTR
CMD_Reset(CmdPacket *cmd) { CMD_Reset(CmdPacket *cmd) {
#ifdef CMD_DBG
os_printf("CMD_Reset\n");
#endif
// clear callbacks table // clear callbacks table
os_memset(callbacks, 0, sizeof(callbacks)); os_memset(callbacks, 0, sizeof(callbacks));
return 1; return 1;
@ -140,9 +131,6 @@ static uint32_t ICACHE_FLASH_ATTR
CMD_WifiConnect(CmdPacket *cmd) { CMD_WifiConnect(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); 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) if(cmd->argc != 2 || cmd->callback == 0)
return 0; return 0;
@ -162,9 +150,6 @@ static uint32_t ICACHE_FLASH_ATTR
CMD_AddCallback(CmdPacket *cmd) { CMD_AddCallback(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); 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) if (cmd->argc != 1 || cmd->callback == 0)
return 0; return 0;
@ -173,9 +158,6 @@ CMD_AddCallback(CmdPacket *cmd) {
// get the sensor name // get the sensor name
len = CMD_ArgLen(&req); 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 (len > 15) return 0; // max size of name is 15 characters
if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0; if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0;
name[len] = 0; name[len] = 0;

@ -119,7 +119,10 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) {
#ifdef CGIMQTT_DBG #ifdef CGIMQTT_DBG
os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable); os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable);
#endif #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 // no action required if mqtt status settings change, they just get picked up at the

@ -127,7 +127,7 @@ void user_init(void) {
// mount the http handlers // mount the http handlers
httpdInit(builtInUrls, 80); httpdInit(builtInUrls, 80);
// init the wifi-serial transparent bridge (port 23) // init the wifi-serial transparent bridge (port 23)
serbridgeInit(23); serbridgeInit(23, 2323);
uart_add_recv_cb(&serbridgeUartCb); uart_add_recv_cb(&serbridgeUartCb);
#ifdef SHOW_HEAP_USE #ifdef SHOW_HEAP_USE
os_timer_disarm(&prHeapTimer); os_timer_disarm(&prHeapTimer);

@ -25,7 +25,7 @@
#define RESTCMD_DBG #define RESTCMD_DBG
#define SERBR_DBG #define SERBR_DBG
#define SERLED_DBG #define SERLED_DBG
#define SLIP_DBG #undef SLIP_DBG
#define UART_DBG #define UART_DBG
// If defined, the default hostname for DHCP will include the chip ID to make it unique // If defined, the default hostname for DHCP will include the chip ID to make it unique

@ -743,8 +743,19 @@ mqtt_doAbort(MQTT_Client* client) {
client->timeoutTick = 2; // reconnect in a few seconds 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 void ICACHE_FLASH_ATTR
MQTT_Disconnect(MQTT_Client* mqttClient) { MQTT_Disconnect(MQTT_Client* mqttClient) {
DBG_MQTT("MQTT: Disconnect requested\n");
os_timer_disarm(&mqttClient->mqttTimer); os_timer_disarm(&mqttClient->mqttTimer);
if (mqttClient->connState == MQTT_DISCONNECTED) return; if (mqttClient->connState == MQTT_DISCONNECTED) return;
if (mqttClient->connState == TCP_RECONNECT_REQ) { if (mqttClient->connState == TCP_RECONNECT_REQ) {
@ -767,11 +778,6 @@ MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb) {
mqttClient->disconnectedCb = disconnectedCb; mqttClient->disconnectedCb = disconnectedCb;
} }
void ICACHE_FLASH_ATTR
MQTT_OnTcpDisconnected(MQTT_Client *mqttClient, MqttCallback tcpDisconnectedCb) {
mqttClient->tcpDisconnectedCb = tcpDisconnectedCb;
}
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb) { MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb) {
mqttClient->dataCb = dataCb; mqttClient->dataCb = dataCb;

@ -82,8 +82,6 @@ typedef struct {
MqttCallback cmdConnectedCb; MqttCallback cmdConnectedCb;
MqttCallback disconnectedCb; MqttCallback disconnectedCb;
MqttCallback cmdDisconnectedCb; MqttCallback cmdDisconnectedCb;
MqttCallback tcpDisconnectedCb;
MqttCallback cmdTcpDisconnectedCb;
MqttCallback publishedCb; MqttCallback publishedCb;
MqttCallback cmdPublishedCb; MqttCallback cmdPublishedCb;
MqttDataCallback dataCb; 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, void MQTT_InitLWT(MQTT_Client* mqttClient, char* will_topic, char* will_msg,
uint8_t will_qos, uint8_t will_retain); 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 // Kick of a persistent connection to the broker, will reconnect anytime conn breaks
void MQTT_Connect(MQTT_Client* mqttClient); void MQTT_Connect(MQTT_Client* mqttClient);

@ -1,5 +1,10 @@
//
// MQTT Commands coming in from the attache microcontrollver over the serial port
//
#include <esp8266.h> #include <esp8266.h>
#include "mqtt.h" #include "mqtt.h"
#include "mqtt_client.h"
#include "mqtt_cmd.h" #include "mqtt_cmd.h"
#ifdef MQTTCMD_DBG #ifdef MQTTCMD_DBG
@ -8,8 +13,13 @@
#define DBG_MQTTCMD(format, ...) do { } while(0) #define DBG_MQTTCMD(format, ...) do { } while(0)
#endif #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 void ICACHE_FLASH_ATTR
cmdMqttConnectedCb(uint32_t* args) { cmdMqttConnectedCb(uint32_t* args) {
@ -24,15 +34,6 @@ cmdMqttConnectedCb(uint32_t* args) {
CMD_ResponseEnd(crc); 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 void ICACHE_FLASH_ATTR
cmdMqttDisconnectedCb(uint32_t* args) { cmdMqttDisconnectedCb(uint32_t* args) {
MQTT_Client* client = (MQTT_Client*)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); 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 uint32_t ICACHE_FLASH_ATTR
MQTTCMD_Setup(CmdPacket *cmd) { MQTTCMD_Setup(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); 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) if (CMD_GetArgc(&req) != 9)
return 0; return 0;
@ -77,12 +242,9 @@ MQTTCMD_Setup(CmdPacket *cmd) {
if (client == NULL) return 0; if (client == NULL) return 0;
os_memset(client, 0, clientLen); os_memset(client, 0, clientLen);
return 0;
#if 0
uint16_t len; uint16_t len;
uint8_t *client_id, *user_data, *pass_data; uint8_t *client_id, *user_data, *pass_data;
uint32_t keepalive, clean_session, cb_data; uint32_t keepalive, clean_session;
// get client id // get client id
len = CMD_ArgLen(&req); 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? // 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); 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 // create callback
MqttCmdCb* callback = (MqttCmdCb*)os_zalloc(sizeof(MqttCmdCb)); MqttCmdCb* callback = (MqttCmdCb*)os_zalloc(sizeof(MqttCmdCb));
uint32_t cb_data;
CMD_PopArg(&req, (uint8_t*)&cb_data, 4); CMD_PopArg(&req, (uint8_t*)&cb_data, 4);
callback->connectedCb = cb_data; callback->connectedCb = cb_data;
@ -137,72 +305,18 @@ MQTTCMD_Setup(CmdPacket *cmd) {
client->cmdPublishedCb = cmdMqttPublishedCb; client->cmdPublishedCb = cmdMqttPublishedCb;
client->cmdDataCb = cmdMqttDataCb; client->cmdDataCb = cmdMqttDataCb;
if (CMD_GetArgc(&req) == 10) { return 0xf00df00d; //(uint32_t)client;
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
} }
uint32_t ICACHE_FLASH_ATTR uint32_t ICACHE_FLASH_ATTR
MQTTCMD_Lwt(CmdPacket *cmd) { MQTTCMD_Connect(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); CMD_Request(&req, cmd);
if (CMD_GetArgc(&req) != 5) #ifdef MQTT_1_CLIENT
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);
return 1; return 1;
}
uint32_t ICACHE_FLASH_ATTR
MQTTCMD_Connect(CmdPacket *cmd) {
CmdRequest req;
CMD_Request(&req, cmd);
#else
if (CMD_GetArgc(&req) != 4) if (CMD_GetArgc(&req) != 4)
return 0; return 0;
@ -235,6 +349,7 @@ MQTTCMD_Connect(CmdPacket *cmd) {
MQTT_Connect(client); MQTT_Connect(client);
return 1; return 1;
#endif
} }
uint32_t ICACHE_FLASH_ATTR uint32_t ICACHE_FLASH_ATTR
@ -242,6 +357,10 @@ MQTTCMD_Disconnect(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); CMD_Request(&req, cmd);
#ifdef MQTT_1_CLIENT
return 1;
#else
if (CMD_GetArgc(&req) != 1) if (CMD_GetArgc(&req) != 1)
return 0; return 0;
@ -254,92 +373,5 @@ MQTTCMD_Disconnect(CmdPacket *cmd) {
// disconnect // disconnect
MQTT_Disconnect(client); MQTT_Disconnect(client);
return 1; return 1;
} #endif
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;
} }

@ -8,7 +8,6 @@ typedef struct {
uint32_t disconnectedCb; uint32_t disconnectedCb;
uint32_t publishedCb; uint32_t publishedCb;
uint32_t dataCb; uint32_t dataCb;
uint32_t tcpDisconnectedCb;
} MqttCmdCb; } MqttCmdCb;
uint32_t MQTTCMD_Connect(CmdPacket *cmd); uint32_t MQTTCMD_Connect(CmdPacket *cmd);

@ -17,8 +17,9 @@
#include "slip.h" #include "slip.h"
#include "cmd.h" #include "cmd.h"
static struct espconn serbridgeConn; static struct espconn serbridgeConn1; // plain bridging port
static esp_tcp serbridgeTcp; static struct espconn serbridgeConn2; // programming port
static esp_tcp serbridgeTcp1, serbridgeTcp2;
static int8_t mcu_reset_pin, mcu_isp_pin; static int8_t mcu_reset_pin, mcu_isp_pin;
extern uint8_t slip_disabled; // disable slip to allow flashing of attached MCU 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); //os_printf("Receive callback on conn %p\n", conn);
if (conn == NULL) return; 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 // 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 // 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 // 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) || if ((len == 2 && strncmp(data, "0 ", 2) == 0) ||
(len == 2 && strncmp(data, "?\n", 2) == 0) || (len == 2 && strncmp(data, "?\n", 2) == 0) ||
(len == 3 && strncmp(data, "?\r\n", 3) == 0)) { (len == 3 && strncmp(data, "?\r\n", 3) == 0)) {
#ifdef SERBR_DBG startPGM = true;
os_printf("MCU Reset=gpio%d ISP=gpio%d\n", mcu_reset_pin, mcu_isp_pin); conn->conn_mode = cmPGM;
#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
// If the connection starts with a telnet negotiation we will do telnet // 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; 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 // write the buffer to the uart
if (conn->conn_mode == cmTelnet) { if (conn->conn_mode == cmTelnet) {
conn->telnet_state = telnetUnwrap((uint8_t *)data, len, conn->telnet_state); conn->telnet_state = telnetUnwrap((uint8_t *)data, len, conn->telnet_state);
@ -228,15 +243,14 @@ sendtxbuffer(serbridgeConnData *conn)
{ {
sint8 result = ESPCONN_OK; sint8 result = ESPCONN_OK;
if (conn->txbufferlen != 0) { 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; conn->readytosend = false;
result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen); result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen);
conn->txbufferlen = 0; conn->txbufferlen = 0;
if (result != ESPCONN_OK) { if (result != ESPCONN_OK) {
#ifdef SERBR_DBG
os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn); os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn);
#endif
conn->txbufferlen = 0; conn->txbufferlen = 0;
if (!conn->txoverflow_at) conn->txoverflow_at = system_get_time();
} else { } else {
conn->sentbuffer = conn->txbuffer; conn->sentbuffer = conn->txbuffer;
conn->txbuffer = NULL; conn->txbuffer = NULL;
@ -254,12 +268,7 @@ sendtxbuffer(serbridgeConnData *conn)
static sint8 ICACHE_FLASH_ATTR static sint8 ICACHE_FLASH_ATTR
espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) espbuffsend(serbridgeConnData *conn, const char *data, uint16 len)
{ {
if (conn->txbufferlen >= MAX_TXBUFFER) { if (conn->txbufferlen >= MAX_TXBUFFER) goto overflow;
#ifdef SERBR_DBG
os_printf("espbuffsend: txbuffer full on conn %p\n", conn);
#endif
return -128;
}
// make sure we indeed have a buffer // make sure we indeed have a buffer
if (conn->txbuffer == NULL) conn->txbuffer = os_zalloc(MAX_TXBUFFER); if (conn->txbuffer == NULL) conn->txbuffer = os_zalloc(MAX_TXBUFFER);
@ -283,10 +292,25 @@ espbuffsend(serbridgeConnData *conn, const char *data, uint16 len)
// we sent the prior buffer, so try again // we sent the prior buffer, so try again
return espbuffsend(conn, data+avail, len-avail); return espbuffsend(conn, data+avail, len-avail);
} }
os_printf("espbuffsend: txbuffer full on conn %p\n", conn); goto overflow;
return -128;
} }
return result; 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 //callback after the data are sent
@ -294,12 +318,13 @@ static void ICACHE_FLASH_ATTR
serbridgeSentCb(void *arg) serbridgeSentCb(void *arg)
{ {
serbridgeConnData *conn = ((struct espconn*)arg)->reverse; 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; if (conn == NULL) return;
//os_printf("%d ST\n", system_get_time()); //os_printf("%d ST\n", system_get_time());
if (conn->sentbuffer != NULL) os_free(conn->sentbuffer); if (conn->sentbuffer != NULL) os_free(conn->sentbuffer);
conn->sentbuffer = NULL; conn->sentbuffer = NULL;
conn->readytosend = true; conn->readytosend = true;
conn->txoverflow_at = 0;
sendtxbuffer(conn); // send possible new data in txbuffer sendtxbuffer(conn); // send possible new data in txbuffer
} }
@ -346,7 +371,9 @@ serbridgeDisconCb(void *arg)
conn->txbuffer = NULL; conn->txbuffer = NULL;
conn->txbufferlen = 0; conn->txbufferlen = 0;
// Send reset to attached uC if it was in programming mode // 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); GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L); os_delay_us(100L);
GPIO_OUTPUT_SET(mcu_reset_pin, 1); GPIO_OUTPUT_SET(mcu_reset_pin, 1);
@ -387,6 +414,9 @@ serbridgeConnectCb(void *arg)
conn->reverse = connData+i; conn->reverse = connData+i;
connData[i].readytosend = true; connData[i].readytosend = true;
connData[i].conn_mode = cmInit; 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_recvcb(conn, serbridgeRecvCb);
espconn_regist_disconcb(conn, serbridgeDisconCb); espconn_regist_disconcb(conn, serbridgeDisconCb);
@ -430,20 +460,33 @@ serbridgeInitPins()
// Start transparent serial bridge TCP server on specified port (typ. 23) // Start transparent serial bridge TCP server on specified port (typ. 23)
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
serbridgeInit(int port) serbridgeInit(int port1, int port2)
{ {
serbridgeInitPins(); serbridgeInitPins();
for (int i = 0; i < MAX_CONN; i++) { os_memset(connData, 0, sizeof(connData));
connData[i].conn = NULL; os_memset(&serbridgeTcp1, 0, sizeof(serbridgeTcp1));
} os_memset(&serbridgeTcp2, 0, sizeof(serbridgeTcp2));
serbridgeConn.type = ESPCONN_TCP;
serbridgeConn.state = ESPCONN_NONE; // set-up the primary port for plain bridging
serbridgeTcp.local_port = port; serbridgeConn1.type = ESPCONN_TCP;
serbridgeConn.proto.tcp = &serbridgeTcp; serbridgeConn1.state = ESPCONN_NONE;
serbridgeTcp1.local_port = port1;
espconn_regist_connectcb(&serbridgeConn, serbridgeConnectCb); serbridgeConn1.proto.tcp = &serbridgeTcp1;
espconn_accept(&serbridgeConn);
espconn_tcp_set_max_con_allow(&serbridgeConn, MAX_CONN); espconn_regist_connectcb(&serbridgeConn1, serbridgeConnectCb);
espconn_regist_time(&serbridgeConn, SER_BRIDGE_TIMEOUT, 0); 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);
} }

@ -6,31 +6,32 @@
#include <espconn.h> #include <espconn.h>
#define MAX_CONN 4 #define MAX_CONN 4
#define SER_BRIDGE_TIMEOUT 28799 #define SER_BRIDGE_TIMEOUT 300 // 300 seconds = 5 minutes
// Send buffer size // Send buffer size
#define MAX_TXBUFFER 2048 #define MAX_TXBUFFER (2*1460)
enum connModes { enum connModes {
cmInit = 0, // initialization mode: nothing received yet cmInit = 0, // initialization mode: nothing received yet
cmPGMInit, // initialization mode for programming
cmTransparent, // transparent mode cmTransparent, // transparent mode
cmAVR, // Arduino/AVR programming mode cmPGM, // Arduino/AVR/ARM programming mode
cmARM, // ARM (LPC8xx) programming
cmEcho, // simply echo characters (used for debugging latency)
cmTelnet, // use telnet escape sequences for programming mode cmTelnet, // use telnet escape sequences for programming mode
}; };
typedef struct serbridgeConnData { typedef struct serbridgeConnData {
struct espconn *conn; struct espconn *conn;
enum connModes conn_mode; // connection mode 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 uint16 txbufferlen; // length of data in txbuffer
char *txbuffer; // buffer for the data to send
char *sentbuffer; // buffer sent, awaiting callback to get freed 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 bool readytosend; // true, if txbuffer can be sent by espconn_sent
uint8_t telnet_state;
} serbridgeConnData; } 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 serbridgeInitPins(void);
void ICACHE_FLASH_ATTR serbridgeUartCb(char *buf, short len); void ICACHE_FLASH_ATTR serbridgeUartCb(char *buf, short len);
void ICACHE_FLASH_ATTR serbridgeReset(); void ICACHE_FLASH_ATTR serbridgeReset();

@ -46,9 +46,9 @@ slip_process() {
if (crc == rcv) { if (crc == rcv) {
CMD_parse_packet((uint8_t*)slip_buf, slip_len-2); CMD_parse_packet((uint8_t*)slip_buf, slip_len-2);
} else { } else {
#ifdef SLIP_DBG
os_printf("SLIP: bad CRC, crc=%x rcv=%x\n", crc, rcv); os_printf("SLIP: bad CRC, crc=%x rcv=%x\n", crc, rcv);
#ifdef SLIP_DBG
for (short i=0; i<slip_len; i++) { for (short i=0; i<slip_len; i++) {
if (slip_buf[i] >= ' ' && slip_buf[i] <= '~') if (slip_buf[i] >= ' ' && slip_buf[i] <= '~')
os_printf("%c", slip_buf[i]); os_printf("%c", slip_buf[i]);

Loading…
Cancel
Save