diff --git a/README.md b/README.md index 90ec76e3..13a817da 100644 --- a/README.md +++ b/README.md @@ -225,8 +225,10 @@ m:on("message", function(conn, topic, data) end end) --- for secure: m:connect("192.168.11.118", 1880, 1) -m:connect("192.168.11.118", 1880, 0, function(conn) print("connected") end) +-- m:connect( host, port, secure, auto_reconnect, function(client) ) +-- for secure: m:connect("192.168.11.118", 1880, 1, 0) +-- for auto-reconnect: m:connect("192.168.11.118", 1880, 0, 1) +m:connect("192.168.11.118", 1880, 0, 0, function(conn) print("connected") end) -- subscribe topic with qos = 0 m:subscribe("/topic",0, function(conn) print("subscribe success") end) @@ -235,7 +237,7 @@ m:subscribe("/topic",0, function(conn) print("subscribe success") end) -- publish a message with data = hello, QoS = 0, retain = 0 m:publish("/topic","hello",0,0, function(conn) print("sent") end) -m:close(); +m:close(); -- if auto-reconnect = 1, will reconnect. -- you can call m:connect again ``` diff --git a/app/cjson/strbuf.c b/app/cjson/strbuf.c index 44a1bd69..53ade23b 100644 --- a/app/cjson/strbuf.c +++ b/app/cjson/strbuf.c @@ -46,7 +46,7 @@ int strbuf_init(strbuf_t *s, int len) s->reallocs = 0; s->debug = 0; - s->buf = c_malloc(size); + s->buf = (char *)c_malloc(size); if (!s->buf){ NODE_ERR("not enough memory\n"); return -1; @@ -60,7 +60,7 @@ strbuf_t *strbuf_new(int len) { strbuf_t *s; - s = c_malloc(sizeof(strbuf_t)); + s = (strbuf_t *)c_malloc(sizeof(strbuf_t)); if (!s){ NODE_ERR("not enough memory\n"); return NULL; diff --git a/app/include/user_version.h b/app/include/user_version.h index bc64f36d..79d104c5 100644 --- a/app/include/user_version.h +++ b/app/include/user_version.h @@ -7,6 +7,6 @@ #define NODE_VERSION_INTERNAL 0U #define NODE_VERSION "NodeMCU 0.9.5" -#define BUILD_DATE "build 20150318" +#define BUILD_DATE "build 20150331" #endif /* __USER_VERSION_H__ */ diff --git a/app/libc/c_stdio.h b/app/libc/c_stdio.h index 88c368f6..c652f0bf 100644 --- a/app/libc/c_stdio.h +++ b/app/libc/c_stdio.h @@ -47,9 +47,9 @@ extern int c_stderr; #define SEEK_END 2 /* set file offset to EOF plus offset */ #endif -#define c_malloc os_malloc -#define c_zalloc os_zalloc -#define c_free os_free +// #define c_malloc os_malloc +// #define c_zalloc os_zalloc +// #define c_free os_free extern void output_redirect(const char *str); #define c_puts output_redirect diff --git a/app/libc/c_stdlib.h b/app/libc/c_stdlib.h index 3757c135..f0a6f265 100644 --- a/app/libc/c_stdlib.h +++ b/app/libc/c_stdlib.h @@ -29,9 +29,9 @@ #define os_realloc(p, s) mem_realloc((p), (s)) #endif -// #define c_free os_free -// #define c_malloc os_malloc -// #define c_zalloc os_zalloc +#define c_free os_free +#define c_malloc os_malloc +#define c_zalloc os_zalloc #define c_realloc os_realloc #define c_abs abs @@ -47,9 +47,9 @@ // c_getenv() get env "LUA_INIT" string for lua initialization. const char *c_getenv(const char *__string); -void *c_malloc(size_t __size); -void *c_zalloc(size_t __size); -void c_free(void *); +// void *c_malloc(size_t __size); +// void *c_zalloc(size_t __size); +// void c_free(void *); // int c_rand(void); // void c_srand(unsigned int __seed); diff --git a/app/modules/adc.c b/app/modules/adc.c index b64697ba..eee15fe4 100644 --- a/app/modules/adc.c +++ b/app/modules/adc.c @@ -8,6 +8,7 @@ #include "lrotable.h" #include "c_types.h" +#include "user_interface.h" // Lua: read(id) , return system adc static int adc_sample( lua_State* L ) @@ -19,12 +20,33 @@ static int adc_sample( lua_State* L ) return 1; } +// Lua: readvdd33() +static int adc_readvdd33( lua_State* L ) +{ + uint32_t vdd33 = 0; + if(STATION_MODE == wifi_get_opmode()) + { + // Bug fix + wifi_set_opmode( STATIONAP_MODE ); + vdd33 = readvdd33(); + wifi_set_opmode( STATION_MODE ); + } + else + { + vdd33 = readvdd33(); + } + + lua_pushinteger(L, vdd33); + return 1; +} + // Module function map #define MIN_OPT_LEVEL 2 #include "lrodefs.h" const LUA_REG_TYPE adc_map[] = { { LSTRKEY( "read" ), LFUNCVAL( adc_sample ) }, + { LSTRKEY( "readvdd33" ), LFUNCVAL( adc_readvdd33) }, #if LUA_OPTIMIZE_MEMORY > 0 #endif diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index 018e034e..2cc3ad6d 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -15,6 +15,7 @@ #include "espconn.h" #include "mqtt_msg.h" +#include "msg_queue.h" static lua_State *gL = NULL; @@ -24,10 +25,11 @@ static lua_State *gL = NULL; #define MQTT_MAX_USER_LEN 64 #define MQTT_MAX_PASS_LEN 64 #define MQTT_SEND_TIMEOUT 5 +#define MQTT_CONNECT_TIMEOUT 5 typedef enum { MQTT_INIT, - MQTT_CONNECT_SEND, + MQTT_CONNECT_SENT, MQTT_CONNECT_SENDING, MQTT_DATA } tConnState; @@ -55,10 +57,7 @@ typedef struct mqtt_state_t uint16_t message_length_read; mqtt_message_t* outbound_message; mqtt_connection_t mqtt_connection; - - uint16_t pending_msg_id; - int pending_msg_type; - int pending_publish_qos; + msg_queue_t* pending_msg_q; } mqtt_state_t; typedef struct lmqtt_userdata @@ -73,53 +72,86 @@ typedef struct lmqtt_userdata mqtt_state_t mqtt_state; mqtt_connect_info_t connect_info; uint32_t keep_alive_tick; - uint32_t send_timeout; + uint32_t event_timeout; uint8_t secure; - uint8_t connected; + bool connected; // indicate socket connected, not mqtt prot connected. ETSTimer mqttTimer; tConnState connState; }lmqtt_userdata; +static void socket_connect(struct espconn *pesp_conn); + static void mqtt_socket_disconnected(void *arg) // tcp only { - NODE_DBG("mqtt_socket_disconnected is called.\n"); + NODE_DBG("enter mqtt_socket_disconnected.\n"); + struct espconn *pesp_conn = arg; + bool call_back = false; + if(pesp_conn == NULL) + return; + lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; + if(mud == NULL) + return; + + os_timer_disarm(&mud->mqttTimer); + + if(mud->pesp_conn){ + mud->pesp_conn->reverse = NULL; + if(mud->pesp_conn->proto.tcp) + c_free(mud->pesp_conn->proto.tcp); + mud->pesp_conn->proto.tcp = NULL; + c_free(mud->pesp_conn); + mud->pesp_conn = NULL; + } + + if(mud->connected){ // call back only called when socket is from connection to disconnection. + mud->connected = false; + if((mud->cb_disconnect_ref != LUA_NOREF) && (mud->self_ref != LUA_NOREF)) { + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_disconnect_ref); + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua + call_back = true; + } + } + + lua_gc(gL, LUA_GCSTOP, 0); + if(mud->self_ref != LUA_NOREF){ // TODO: should we unref the client and delete it? + luaL_unref(gL, LUA_REGISTRYINDEX, mud->self_ref); + mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self + } + lua_gc(gL, LUA_GCRESTART, 0); + + if(call_back){ + lua_call(gL, 1, 0); + } + + NODE_DBG("leave mqtt_socket_disconnected.\n"); +} + +static void mqtt_socket_reconnected(void *arg, sint8_t err) +{ + NODE_DBG("enter mqtt_socket_reconnected.\n"); + // mqtt_socket_disconnected(arg); struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; if(mud == NULL) return; - if(mud->cb_disconnect_ref != LUA_NOREF && mud->self_ref != LUA_NOREF) - { - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_disconnect_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua - lua_call(gL, 1, 0); - } - mud->connected = 0; + + pesp_conn->proto.tcp->remote_port = mud->mqtt_state.port; + pesp_conn->proto.tcp->local_port = espconn_port(); + os_timer_disarm(&mud->mqttTimer); - - if(pesp_conn->proto.tcp) - c_free(pesp_conn->proto.tcp); - pesp_conn->proto.tcp = NULL; - if(mud->pesp_conn) - c_free(mud->pesp_conn); - mud->pesp_conn = NULL; // espconn is already disconnected - lua_gc(gL, LUA_GCSTOP, 0); - if(mud->self_ref != LUA_NOREF){ - luaL_unref(gL, LUA_REGISTRYINDEX, mud->self_ref); - mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self + if( (mud->event_timeout != 0) || mud->mqtt_state.auto_reconnect ){ + socket_connect(pesp_conn); + } else { + mqtt_socket_disconnected(arg); } - lua_gc(gL, LUA_GCRESTART, 0); -} - -static void mqtt_socket_reconnected(void *arg, sint8_t err) -{ - NODE_DBG("mqtt_socket_reconnected is called.\n"); - mqtt_socket_disconnected(arg); + NODE_DBG("leave mqtt_socket_reconnected.\n"); } static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) { + NODE_DBG("enter deliver_publish.\n"); const char comma[] = ","; mqtt_event_data_t event_data; @@ -135,10 +167,7 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) return; lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_message_ref); lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua - // expose_array(gL, pdata, len); - // *(pdata+len) = 0; - // NODE_DBG(pdata); - // NODE_DBG("\n"); + lua_pushlstring(gL, event_data.topic, event_data.topic_length); if(event_data.data_length > 0){ lua_pushlstring(gL, event_data.data, event_data.data_length); @@ -146,15 +175,17 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) } else { lua_call(gL, 2, 0); } + NODE_DBG("leave deliver_publish.\n"); } static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) { - NODE_DBG("mqtt_socket_received is called.\n"); + NODE_DBG("enter mqtt_socket_received.\n"); uint8_t msg_type; uint8_t msg_qos; uint16_t msg_id; + msg_queue_t *node = NULL; struct espconn *pesp_conn = arg; if(pesp_conn == NULL) @@ -171,15 +202,14 @@ READPACKET: mud->mqtt_state.outbound_message = NULL; switch(mud->connState){ case MQTT_CONNECT_SENDING: + case MQTT_CONNECT_SENT: if(mqtt_get_type(mud->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK){ NODE_DBG("MQTT: Invalid packet\r\n"); mud->connState = MQTT_INIT; - if(mud->secure){ + if(mud->secure) espconn_secure_disconnect(pesp_conn); - } - else { + else espconn_disconnect(pesp_conn); - } } else { mud->connState = MQTT_DATA; NODE_DBG("MQTT: Connected\r\n"); @@ -201,39 +231,54 @@ READPACKET: msg_qos = mqtt_get_qos(mud->mqtt_state.in_buffer); msg_id = mqtt_get_id(mud->mqtt_state.in_buffer, mud->mqtt_state.in_buffer_length); + msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; + NODE_DBG("MQTT_DATA: type: %d, qos: %d, msg_id: %d, pending_id: %d\r\n", msg_type, msg_qos, msg_id, - mud->mqtt_state.pending_msg_id); + (pending_msg)?pending_msg->msg_id:0); switch(msg_type) { case MQTT_MSG_TYPE_SUBACK: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && mud->mqtt_state.pending_msg_id == msg_id) + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Subscribe successful\r\n"); - if (mud->cb_suback_ref == LUA_NOREF) - break; - if (mud->self_ref == LUA_NOREF) - break; - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_suback_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); - lua_call(gL, 1, 0); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); + if (mud->cb_suback_ref == LUA_NOREF) + break; + if (mud->self_ref == LUA_NOREF) + break; + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_suback_ref); + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); + lua_call(gL, 1, 0); + } break; case MQTT_MSG_TYPE_UNSUBACK: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && mud->mqtt_state.pending_msg_id == msg_id) + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: UnSubscribe successful\r\n"); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); + } break; case MQTT_MSG_TYPE_PUBLISH: - if(msg_qos == 1) + if(msg_qos == 1){ mud->mqtt_state.outbound_message = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id); - else if(msg_qos == 2) + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBACK, (int)msg_qos ); + } + else if(msg_qos == 2){ mud->mqtt_state.outbound_message = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id); - + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBREC, (int)msg_qos ); + } + if(msg_qos == 1 || msg_qos == 2){ + NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos); + } deliver_publish(mud, mud->mqtt_state.in_buffer, mud->mqtt_state.message_length_read); break; case MQTT_MSG_TYPE_PUBACK: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && mud->mqtt_state.pending_msg_id == msg_id){ + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Publish with QoS = 1 successful\r\n"); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) @@ -246,15 +291,20 @@ READPACKET: break; case MQTT_MSG_TYPE_PUBREC: mud->mqtt_state.outbound_message = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id); + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBREL, (int)msg_qos ); NODE_DBG("MQTT: Response PUBREL\r\n"); break; case MQTT_MSG_TYPE_PUBREL: mud->mqtt_state.outbound_message = mqtt_msg_pubcomp(&mud->mqtt_state.mqtt_connection, msg_id); + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBCOMP, (int)msg_qos ); NODE_DBG("MQTT: Response PUBCOMP\r\n"); break; case MQTT_MSG_TYPE_PUBCOMP: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && mud->mqtt_state.pending_msg_id == msg_id){ + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Publish with QoS = 2 successful\r\n"); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) @@ -266,9 +316,13 @@ READPACKET: break; case MQTT_MSG_TYPE_PINGREQ: mud->mqtt_state.outbound_message = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection); + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PINGRESP, (int)msg_qos ); + NODE_DBG("MQTT: Response PINGRESP\r\n"); break; case MQTT_MSG_TYPE_PINGRESP: // Ignore + NODE_DBG("MQTT: PINGRESP received\r\n"); break; } // NOTE: this is done down here and not in the switch case above @@ -291,19 +345,23 @@ READPACKET: break; } - if(mud->mqtt_state.outbound_message != NULL){ - if(mud->secure) - espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("Sent: %d\n", node->msg.length); + if( mud->secure ) + espconn_secure_sent( pesp_conn, node->msg.data, node->msg.length ); else - espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + espconn_sent( pesp_conn, node->msg.data, node->msg.length ); + mud->keep_alive_tick = 0; mud->mqtt_state.outbound_message = NULL; } + NODE_DBG("leave mqtt_socket_received.\n"); return; } static void mqtt_socket_sent(void *arg) { - // NODE_DBG("mqtt_socket_sent is called.\n"); + NODE_DBG("enter mqtt_socket_sent.\n"); struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; @@ -311,10 +369,18 @@ static void mqtt_socket_sent(void *arg) if(mud == NULL) return; if(!mud->connected) - return; + return; + if(mud->connState == MQTT_CONNECT_SENDING){ + mud->connState = MQTT_CONNECT_SENT; + } + // call mqtt_sent() - mud->send_timeout = 0; - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && mud->mqtt_state.pending_publish_qos == 0) { + mud->event_timeout = 0; + + // qos = 0, publish and forgot. + msg_queue_t *node = mud->mqtt_state.pending_msg_q; + if(node && node->msg_type == MQTT_MSG_TYPE_PUBLISH && node->publish_qos == 0) { + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) return; if(mud->self_ref == LUA_NOREF) @@ -323,12 +389,12 @@ static void mqtt_socket_sent(void *arg) lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua lua_call(gL, 1, 0); } + NODE_DBG("leave mqtt_socket_sent.\n"); } -static int mqtt_socket_client( lua_State* L ); static void mqtt_socket_connected(void *arg) { - NODE_DBG("mqtt_socket_connected is called.\n"); + NODE_DBG("enter mqtt_socket_connected.\n"); struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; @@ -344,53 +410,91 @@ static void mqtt_socket_connected(void *arg) mqtt_msg_init(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.out_buffer, mud->mqtt_state.out_buffer_length); mud->mqtt_state.outbound_message = mqtt_msg_connect(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.connect_info); NODE_DBG("Send MQTT connection infomation, data len: %d, d[0]=%d \r\n", mud->mqtt_state.outbound_message->length, mud->mqtt_state.outbound_message->data[0]); - if(mud->secure){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + if(mud->secure) espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - } else - { espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - } mud->mqtt_state.outbound_message = NULL; mud->connState = MQTT_CONNECT_SENDING; + NODE_DBG("leave mqtt_socket_connected.\n"); return; } void mqtt_socket_timer(void *arg) { + // NODE_DBG("enter mqtt_socket_timer.\n"); lmqtt_userdata *mud = (lmqtt_userdata*) arg; - if(mud->connState == MQTT_DATA){ - mud->keep_alive_tick ++; - if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ - mud->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; - mud->send_timeout = MQTT_SEND_TIMEOUT; - NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); - mud->mqtt_state.outbound_message = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); - - if(mud->secure) - espconn_secure_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - else - espconn_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - mud->keep_alive_tick = 0; + if(mud == NULL) + return; + if(mud->event_timeout > 0){ + NODE_DBG("event_timeout: %d.\n", mud->event_timeout); + mud->event_timeout --; + if(mud->event_timeout > 0){ + return; } } - if(mud->send_timeout > 0) - mud->send_timeout --; + + if(mud->pesp_conn == NULL){ + NODE_DBG("mud->pesp_conn is NULL.\n"); + return; + } + + if(mud->connState == MQTT_INIT){ // socket connect time out. + NODE_DBG("Can not connect to broker.\n"); + } else if(mud->connState == MQTT_CONNECT_SENDING){ // MQTT_CONNECT send time out. + mud->connState = MQTT_INIT; + if(mud->secure) + espconn_secure_disconnect(mud->pesp_conn); + else + espconn_disconnect(mud->pesp_conn); + mud->keep_alive_tick = 0; // not need count anymore + } else if(mud->connState == MQTT_CONNECT_SENT){ // wait for CONACK time out. + NODE_DBG("MQTT_CONNECT failed.\n"); + } else if(mud->connState == MQTT_DATA){ + msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; + if(pending_msg){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + if(mud->secure) + espconn_secure_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); + else + espconn_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); + mud->keep_alive_tick = 0; + NODE_DBG("id: %d - qos: %d, length: %d\n", pending_msg->msg_id, pending_msg->publish_qos, pending_msg->msg.length); + } else { + // no queued event. + mud->keep_alive_tick ++; + if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); + mud->mqtt_state.outbound_message = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); + if(mud->secure) + espconn_secure_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + else + espconn_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + mud->keep_alive_tick = 0; + } + } + } + // NODE_DBG("leave mqtt_socket_timer.\n"); } // Lua: mqtt.Client(clientid, keepalive, user, pass) static int mqtt_socket_client( lua_State* L ) { - NODE_DBG("mqtt_socket_client is called.\n"); + NODE_DBG("enter mqtt_socket_client.\n"); lmqtt_userdata *mud; char tempid[20] = {0}; c_sprintf(tempid, "%s%x", "NodeMCU_", system_get_chip_id() ); NODE_DBG(tempid); NODE_DBG("\n"); - size_t il = c_strlen(tempid); + const char *clientId = tempid, *username = NULL, *password = NULL; + size_t idl = c_strlen(tempid); + size_t unl = 0, pwl = 0; + int keepalive = 0; int stack = 1; unsigned secure = 0; int top = lua_gettop(L); @@ -409,8 +513,9 @@ static int mqtt_socket_client( lua_State* L ) mud->secure = 0; mud->keep_alive_tick = 0; - mud->send_timeout = 0; + mud->event_timeout = 0; mud->connState = MQTT_INIT; + mud->connected = false; c_memset(&mud->mqttTimer, 0, sizeof(ETSTimer)); c_memset(&mud->mqtt_state, 0, sizeof(mqtt_state_t)); c_memset(&mud->connect_info, 0, sizeof(mqtt_connect_info_t)); @@ -419,87 +524,92 @@ static int mqtt_socket_client( lua_State* L ) luaL_getmetatable(L, "mqtt.socket"); lua_setmetatable(L, -2); + gL = L; // global L for mqtt module. + if( lua_isstring(L,stack) ) // deal with the clientid string { - clientId = luaL_checklstring( L, stack, &il ); + clientId = luaL_checklstring( L, stack, &idl ); stack++; } - // TODO: check the zalloc result. - mud->connect_info.client_id = (uint8_t *)c_zalloc(il+1); - if(!mud->connect_info.client_id){ - return luaL_error(L, "not enough memory"); - } - c_memcpy(mud->connect_info.client_id, clientId, il); - mud->connect_info.client_id[il] = 0; - - mud->mqtt_state.in_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); - if(!mud->mqtt_state.in_buffer){ - return luaL_error(L, "not enough memory"); - } - - mud->mqtt_state.out_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); - if(!mud->mqtt_state.out_buffer){ - return luaL_error(L, "not enough memory"); - } - - mud->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; - mud->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; - - mud->connState = MQTT_INIT; - mud->connect_info.clean_session = 1; - mud->connect_info.will_qos = 0; - mud->connect_info.will_retain = 0; - mud->keep_alive_tick = 0; - mud->connect_info.keepalive = 0; - mud->mqtt_state.connect_info = &mud->connect_info; - - gL = L; // global L for mqtt module. - if(lua_isnumber( L, stack )) { - mud->connect_info.keepalive = luaL_checkinteger( L, stack); + keepalive = luaL_checkinteger( L, stack); stack++; } - if(mud->connect_info.keepalive == 0){ - mud->connect_info.keepalive = MQTT_DEFAULT_KEEPALIVE; - return 1; + if(keepalive == 0){ + keepalive = MQTT_DEFAULT_KEEPALIVE; } if(lua_isstring( L, stack )){ - username = luaL_checklstring( L, stack, &il ); + username = luaL_checklstring( L, stack, &unl ); stack++; } if(username == NULL) - il = 0; - NODE_DBG("lengh username: %d\r\n", il); - mud->connect_info.username = (uint8_t *)c_zalloc(il + 1); - if(!mud->connect_info.username){ - return luaL_error(L, "not enough memory"); - } + unl = 0; + NODE_DBG("lengh username: %d\r\n", unl); - c_memcpy(mud->connect_info.username, username, il); - mud->connect_info.username[il] = 0; - if(lua_isstring( L, stack )){ - password = luaL_checklstring( L, stack, &il ); + password = luaL_checklstring( L, stack, &pwl ); stack++; } if(password == NULL) - il = 0; - NODE_DBG("lengh password: %d\r\n", il); + pwl = 0; + NODE_DBG("lengh password: %d\r\n", pwl); - mud->connect_info.password = (uint8_t *)c_zalloc(il + 1); - if(!mud->connect_info.password){ - return luaL_error(L, "not enough memory"); - } + // TODO: check the zalloc result. + mud->connect_info.client_id = (uint8_t *)c_zalloc(idl+1); + mud->connect_info.username = (uint8_t *)c_zalloc(unl + 1); + mud->connect_info.password = (uint8_t *)c_zalloc(pwl + 1); + mud->mqtt_state.in_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); + mud->mqtt_state.out_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); + if(!mud->connect_info.client_id || !mud->connect_info.username || !mud->connect_info.password || !mud->mqtt_state.in_buffer || !mud->mqtt_state.out_buffer){ + if(mud->connect_info.client_id) { + c_free(mud->connect_info.client_id); + mud->connect_info.client_id = NULL; + } + if(mud->connect_info.username) { + c_free(mud->connect_info.username); + mud->connect_info.username = NULL; + } + if(mud->connect_info.password) { + c_free(mud->connect_info.password); + mud->connect_info.password = NULL; + } + if(mud->mqtt_state.in_buffer) { + c_free(mud->mqtt_state.in_buffer); + mud->mqtt_state.in_buffer = NULL; + } + if(mud->mqtt_state.out_buffer) { + c_free(mud->mqtt_state.out_buffer); + mud->mqtt_state.out_buffer = NULL; + } + return luaL_error(L, "not enough memory"); + } - c_memcpy(mud->connect_info.password, password, il); - mud->connect_info.password[il] = 0; + c_memcpy(mud->connect_info.client_id, clientId, idl); + mud->connect_info.client_id[idl] = 0; + c_memcpy(mud->connect_info.username, username, unl); + mud->connect_info.username[unl] = 0; + c_memcpy(mud->connect_info.password, password, pwl); + mud->connect_info.password[pwl] = 0; NODE_DBG("MQTT: Init info: %s, %s, %s\r\n", mud->connect_info.client_id, mud->connect_info.username, mud->connect_info.password); + mud->connect_info.clean_session = 1; + mud->connect_info.will_qos = 0; + mud->connect_info.will_retain = 0; + mud->connect_info.keepalive = keepalive; + + mud->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; + mud->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; + mud->mqtt_state.pending_msg_q = NULL; + mud->mqtt_state.auto_reconnect = 1; + mud->mqtt_state.port = 1883; + mud->mqtt_state.connect_info = &mud->connect_info; + + NODE_DBG("leave mqtt_socket_client.\n"); return 1; } @@ -508,7 +618,7 @@ static int mqtt_socket_client( lua_State* L ) // socket: unref everything static int mqtt_delete( lua_State* L ) { - NODE_DBG("mqtt_delete is called.\n"); + NODE_DBG("enter mqtt_delete.\n"); lmqtt_userdata *mud = (lmqtt_userdata *)luaL_checkudata(L, 1, "mqtt.socket"); luaL_argcheck(L, mud, 1, "mqtt.socket expected"); @@ -518,7 +628,9 @@ static int mqtt_delete( lua_State* L ) } os_timer_disarm(&mud->mqttTimer); - mud->connected = 0; + mud->connected = false; + + // ---- alloc-ed in mqtt_socket_connect() if(mud->pesp_conn){ // for client connected to tcp server, this should set NULL in disconnect cb mud->pesp_conn->reverse = NULL; if(mud->pesp_conn->proto.tcp) @@ -528,16 +640,19 @@ static int mqtt_delete( lua_State* L ) mud->pesp_conn = NULL; // for socket, it will free this when disconnected } + // ---- alloc-ed in mqtt_socket_lwt() if(mud->connect_info.will_topic){ c_free(mud->connect_info.will_topic); mud->connect_info.will_topic = NULL; } if(mud->connect_info.will_message){ - c_free(mud->connect_info.will_message); - mud->connect_info.will_message = NULL; - } + c_free(mud->connect_info.will_message); + mud->connect_info.will_message = NULL; + } + // ---- + //--------- alloc-ed in mqtt_socket_client() if(mud->connect_info.client_id){ c_free(mud->connect_info.client_id); mud->connect_info.client_id = NULL; @@ -558,6 +673,7 @@ static int mqtt_delete( lua_State* L ) c_free(mud->mqtt_state.out_buffer); mud->mqtt_state.out_buffer = NULL; } + // ------- // free (unref) callback ref if(LUA_NOREF!=mud->cb_connect_ref){ @@ -586,26 +702,27 @@ static int mqtt_delete( lua_State* L ) mud->self_ref = LUA_NOREF; } lua_gc(gL, LUA_GCRESTART, 0); + NODE_DBG("leave mqtt_delete.\n"); return 0; } static void socket_connect(struct espconn *pesp_conn) { + NODE_DBG("enter socket_connect.\n"); if(pesp_conn == NULL) return; lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; if(mud == NULL) return; - if(mud->secure){ + if(mud->secure) espconn_secure_connect(pesp_conn); - } else - { espconn_connect(pesp_conn); - } + + os_timer_arm(&mud->mqttTimer, 1000, 1); - NODE_DBG("socket_connect is called.\n"); + NODE_DBG("leave socket_connect.\n"); } static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg); @@ -613,7 +730,7 @@ static dns_reconn_count = 0; static ip_addr_t host_ip; // for dns static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { - NODE_DBG("socket_dns_found is called.\n"); + NODE_DBG("enter socket_dns_found.\n"); struct espconn *pesp_conn = arg; if(pesp_conn == NULL){ NODE_DBG("pesp_conn null.\n"); @@ -645,78 +762,20 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) NODE_DBG("\n"); socket_connect(pesp_conn); } + NODE_DBG("leave socket_dns_found.\n"); } -// Lua: mqtt:connect( host, port, secure, function(client) ) -static int mqtt_socket_lwt( lua_State* L ) -{ - uint8_t stack = 1; - size_t topicSize, il; - NODE_DBG("mqtt_socket_lwt.\n"); - lmqtt_userdata *mud = NULL; - const char *lwtTopic, *lwtMsg; - uint8_t lwtQoS, lwtRetain; - - mud = (lmqtt_userdata *)luaL_checkudata( L, stack, "mqtt.socket" ); - luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); - - if(mud == NULL) - return 0; - - stack++; - lwtTopic = luaL_checklstring( L, stack, &topicSize ); - if (lwtTopic == NULL) - { - return luaL_error( L, "need lwt topic"); - } - - stack++; - lwtMsg = luaL_checklstring( L, stack, &il ); - if (lwtMsg == NULL) - { - return luaL_error( L, "need lwt message"); - } - - mud->connect_info.will_topic = (uint8_t*) c_zalloc( topicSize + 1 ); - if(!mud->connect_info.will_topic){ - return luaL_error( L, "not enough memory"); - } - c_memcpy(mud->connect_info.will_topic, lwtTopic, topicSize); - mud->connect_info.will_topic[topicSize] = 0; - - mud->connect_info.will_message = (uint8_t*) c_zalloc( il + 1 ); - if(!mud->connect_info.will_message){ - return luaL_error( L, "not enough memory"); - } - c_memcpy(mud->connect_info.will_message, lwtMsg, il); - mud->connect_info.will_message[il] = 0; - - - stack++; - mud->connect_info.will_qos = luaL_checkinteger( L, stack ); - - stack++; - mud->connect_info.will_retain = luaL_checkinteger( L, stack ); - - NODE_DBG("mqtt_socket_lwt: topic: %s, message: %s, qos: %d, retain: %d\n", - mud->connect_info.will_topic, - mud->connect_info.will_message, - mud->connect_info.will_qos, - mud->connect_info.will_retain); - return 0; -} - -// Lua: mqtt:connect( host, port, secure, function(client) ) +// Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) ) static int mqtt_socket_connect( lua_State* L ) { - NODE_DBG("mqtt_socket_connect is called.\n"); + NODE_DBG("enter mqtt_socket_connect.\n"); lmqtt_userdata *mud = NULL; unsigned port = 1883; size_t il; ip_addr_t ipaddr; const char *domain; int stack = 1; - unsigned secure = 0; + unsigned secure = 0, auto_reconnect = 0; int top = lua_gettop(L); mud = (lmqtt_userdata *)luaL_checkudata(L, stack, "mqtt.socket"); @@ -725,6 +784,10 @@ static int mqtt_socket_connect( lua_State* L ) if(mud == NULL) return 0; + if(mud->connected){ + return luaL_error(L, "already connected"); + } + if(mud->pesp_conn){ //TODO: should I free tcp struct directly or ask user to call close()??? mud->pesp_conn->reverse = NULL; if(mud->pesp_conn->proto.tcp) @@ -750,7 +813,7 @@ static int mqtt_socket_connect( lua_State* L ) pesp_conn->reverse = mud; pesp_conn->type = ESPCONN_TCP; pesp_conn->state = ESPCONN_NONE; - mud->connected = 0; + mud->connected = false; if( (stack<=top) && lua_isstring(L,stack) ) // deal with the domain string { @@ -776,6 +839,7 @@ static int mqtt_socket_connect( lua_State* L ) } pesp_conn->proto.tcp->remote_port = port; pesp_conn->proto.tcp->local_port = espconn_port(); + mud->mqtt_state.port = port; if ( (stack<=top) && lua_isnumber(L, stack) ) { @@ -789,6 +853,18 @@ static int mqtt_socket_connect( lua_State* L ) } mud->secure = secure; // save + if ( (stack<=top) && lua_isnumber(L, stack) ) + { + auto_reconnect = lua_tointeger(L, stack); + stack++; + if ( auto_reconnect != 0 && auto_reconnect != 1 ){ + auto_reconnect = 0; // default to 0 + } + } else { + auto_reconnect = 0; // default to 0 + } + mud->mqtt_state.auto_reconnect = auto_reconnect; + // call back function when a connection is obtained, tcp only if ((stack<=top) && (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack @@ -806,6 +882,12 @@ static int mqtt_socket_connect( lua_State* L ) espconn_regist_connectcb(pesp_conn, mqtt_socket_connected); espconn_regist_reconcb(pesp_conn, mqtt_socket_reconnected); + os_timer_disarm(&mud->mqttTimer); + os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); + // timer started in socket_connect() + mud->event_timeout = MQTT_CONNECT_TIMEOUT; + mud->connState = MQTT_INIT; + if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0)) { host_ip.addr = 0; @@ -819,10 +901,7 @@ static int mqtt_socket_connect( lua_State* L ) socket_connect(pesp_conn); } - os_timer_disarm(&mud->mqttTimer); - os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); - os_timer_arm(&mud->mqttTimer, 1000, 1); - + NODE_DBG("leave mqtt_socket_connect.\n"); return 0; } @@ -830,7 +909,7 @@ static int mqtt_socket_connect( lua_State* L ) // client disconnect and unref itself static int mqtt_socket_close( lua_State* L ) { - NODE_DBG("mqtt_socket_close is called.\n"); + NODE_DBG("enter mqtt_socket_close.\n"); int i = 0; lmqtt_userdata *mud = NULL; @@ -853,13 +932,14 @@ static int mqtt_socket_close( lua_State* L ) if(mud->pesp_conn->proto.tcp->remote_port || mud->pesp_conn->proto.tcp->local_port) espconn_disconnect(mud->pesp_conn); } + NODE_DBG("leave mqtt_socket_close.\n"); return 0; } // Lua: mqtt:on( "method", function() ) static int mqtt_socket_on( lua_State* L ) { - NODE_DBG("mqtt_on is called.\n"); + NODE_DBG("enter mqtt_socket_on.\n"); lmqtt_userdata *mud; size_t sl; @@ -893,20 +973,16 @@ static int mqtt_socket_on( lua_State* L ) lua_pop(L, 1); return luaL_error( L, "method not supported" ); } - + NODE_DBG("leave mqtt_socket_on.\n"); return 0; } -// Lua: mqtt:subscribe(topic, qos, function()) +// Lua: bool = mqtt:subscribe(topic, qos, function()) static int mqtt_socket_subscribe( lua_State* L ) { - NODE_DBG("mqtt_socket_subscribe is called.\n"); - typedef struct SUB_STORAGE { - uint32_t length; - uint8_t *data; - struct SUB_STORAGE *next; - } SUB_STORAGE; + NODE_DBG("enter mqtt_socket_subscribe.\n"); uint8_t stack = 1, qos = 0; + uint16_t msg_id = 0; const char *topic; size_t il; lmqtt_userdata *mud; @@ -915,133 +991,125 @@ static int mqtt_socket_subscribe( lua_State* L ) { luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); stack++; - if( mud->send_timeout != 0 ) - return luaL_error( L, "sending in process" ); - - if( !mud->connected ) - return luaL_error( L, "not connected" ); + if(!mud->connected){ + luaL_error( L, "not connected" ); + lua_pushboolean(L, 0); + return 1; + } if( lua_istable( L, stack ) ) { NODE_DBG("subscribe table\n"); lua_pushnil( L ); /* first key */ - SUB_STORAGE *first, *last, *curr; - first = (SUB_STORAGE*) c_zalloc(sizeof(SUB_STORAGE)); - if( first == NULL ) - return luaL_error( L, "not enough memory" ); - first->length = 0; - last = first; - first->next = NULL; - while( lua_next( L, stack ) != 0 ) { - curr = (SUB_STORAGE*) c_zalloc(sizeof(SUB_STORAGE)); - if( curr == NULL ) - return luaL_error( L, "not enough memory" ); + uint8_t temp_buffer[MQTT_BUF_SIZE]; + uint32_t temp_pos = 0; + + while( lua_next( L, stack ) != 0 ) { topic = luaL_checkstring( L, -2 ); qos = luaL_checkinteger( L, -1 ); - mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &mud->mqtt_state.pending_msg_id ); + mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); NODE_DBG("topic: %s - qos: %d, length: %d\n", topic, qos, mud->mqtt_state.outbound_message->length); - curr->data = (uint8_t*) c_zalloc(mud->mqtt_state.outbound_message->length); - if( curr->data == NULL ) - return luaL_error( L, "not enough memory" ); - c_memcpy( curr->data, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); - curr->length = mud->mqtt_state.outbound_message->length; - curr->next = NULL; - last->next = curr; - last = curr; + if (temp_pos + mud->mqtt_state.outbound_message->length > MQTT_BUF_SIZE){ + lua_pop(L, 1); + break; // too long message for the outbuffer. + } + c_memcpy( temp_buffer + temp_pos, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); + temp_pos += mud->mqtt_state.outbound_message->length; + lua_pop( L, 1 ); } - curr = first; - uint32_t ptr = 0; - while( curr != NULL ) { - if( curr->length == 0 ) { - curr = curr->next; - continue; - } - if( ptr + curr->length < mud->mqtt_state.out_buffer_length ) { - c_memcpy( mud->mqtt_state.out_buffer + ptr, curr->data, curr->length ); - ptr += curr->length; - } - c_free(curr->data); - c_free(curr); - curr = curr->next; - } - c_free(first); - if( ptr == 0 ) { - return luaL_error( L, "invalid data" ); - } + if (temp_pos == 0){ + luaL_error( L, "invalid data" ); + lua_pushboolean(L, 0); + return 1; + } + + c_memcpy( mud->mqtt_state.out_buffer, temp_buffer, temp_pos ); mud->mqtt_state.outbound_message->data = mud->mqtt_state.out_buffer; - mud->mqtt_state.outbound_message->length = ptr; + mud->mqtt_state.outbound_message->length = temp_pos; stack++; } else { NODE_DBG("subscribe string\n"); topic = luaL_checklstring( L, stack, &il ); stack++; - if( topic == NULL ) - return luaL_error( L, "need topic name" ); + if( topic == NULL ){ + luaL_error( L, "need topic name" ); + lua_pushboolean(L, 0); + return 1; + } qos = luaL_checkinteger( L, stack ); - mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &mud->mqtt_state.pending_msg_id ); + mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); stack++; } - mud->send_timeout = MQTT_SEND_TIMEOUT; - mud->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_SUBSCRIBE; - mud->mqtt_state.pending_publish_qos = mqtt_get_qos( mud->mqtt_state.outbound_message->data ); + if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { // TODO: this will overwrite the previous one. + lua_pushvalue( L, stack ); // copy argument (func) to the top of stack + if( mud->cb_suback_ref != LUA_NOREF ) + luaL_unref( L, LUA_REGISTRYINDEX, mud->cb_suback_ref ); + mud->cb_suback_ref = luaL_ref( L, LUA_REGISTRYINDEX ); + } - if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { - lua_pushvalue( L, stack ); // copy argument (func) to the top of stack - if( mud->cb_suback_ref != LUA_NOREF ) - luaL_unref( L, LUA_REGISTRYINDEX, mud->cb_suback_ref ); - mud->cb_suback_ref = luaL_ref( L, LUA_REGISTRYINDEX ); - } - NODE_DBG("Sent: %d\n", mud->mqtt_state.outbound_message->length); - if( mud->secure ) - espconn_secure_sent( mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); - else - espconn_sent( mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); + msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_SUBSCRIBE, (int)mqtt_get_qos(mud->mqtt_state.outbound_message->data) ); - return 0; + NODE_DBG("topic: %s - id: %d - qos: %d, length: %d\n", topic, node->msg_id, node->publish_qos, node->msg.length); + + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("Sent: %d\n", node->msg.length); + if( mud->secure ) + espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + else + espconn_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + mud->keep_alive_tick = 0; + } + + if(!node){ + lua_pushboolean(L, 0); + } else { + lua_pushboolean(L, 1); // enqueued succeed. + } + mud->mqtt_state.outbound_message = NULL; + NODE_DBG("leave mqtt_socket_subscribe.\n"); + return 1; } -// Lua: mqtt:publish( topic, payload, qos, retain, function() ) +// Lua: bool = mqtt:publish( topic, payload, qos, retain, function() ) static int mqtt_socket_publish( lua_State* L ) { - // NODE_DBG("mqtt_publish is called.\n"); + NODE_DBG("enter mqtt_socket_publish.\n"); struct espconn *pesp_conn = NULL; lmqtt_userdata *mud; size_t l; uint8_t stack = 1; + uint16_t msg_id = 0; mud = (lmqtt_userdata *)luaL_checkudata(L, stack, "mqtt.socket"); luaL_argcheck(L, mud, stack, "mqtt.socket expected"); stack++; if(mud==NULL){ NODE_DBG("userdata is nil.\n"); - return 0; + lua_pushboolean(L, 0); + return 1; } if(mud->pesp_conn == NULL){ NODE_DBG("mud->pesp_conn is NULL.\n"); - return 0; + lua_pushboolean(L, 0); + return 1; } - if(mud->send_timeout != 0) - return luaL_error( L, "sending in process" ); + pesp_conn = mud->pesp_conn; -#if 0 - char temp[20] = {0}; - c_sprintf(temp, IPSTR, IP2STR( &(pesp_conn->proto.tcp->remote_ip) ) ); - NODE_DBG("remote "); - NODE_DBG(temp); - NODE_DBG(":"); - NODE_DBG("%d",pesp_conn->proto.tcp->remote_port); - NODE_DBG(" sending data.\n"); -#endif const char *topic = luaL_checklstring( L, stack, &l ); stack ++; - if (topic == NULL) - return luaL_error( L, "need topic" ); + if (topic == NULL){ + luaL_error( L, "need topic" ); + lua_pushboolean(L, 0); + return 1; + } const char *payload = luaL_checklstring( L, stack, &l ); stack ++; @@ -1050,14 +1118,11 @@ static int mqtt_socket_publish( lua_State* L ) uint8_t retain = luaL_checkinteger( L, stack); stack ++; - mud->mqtt_state.outbound_message = mqtt_msg_publish(&mud->mqtt_state.mqtt_connection, topic, payload, l, qos, retain, - &mud->mqtt_state.pending_msg_id); - mud->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PUBLISH; - mud->mqtt_state.pending_publish_qos = qos; - mud->send_timeout = MQTT_SEND_TIMEOUT; + &msg_id); + if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack if(mud->cb_puback_ref != LUA_NOREF) @@ -1065,11 +1130,104 @@ static int mqtt_socket_publish( lua_State* L ) mud->cb_puback_ref = luaL_ref(L, LUA_REGISTRYINDEX); } - if(mud->secure) - espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - else - espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + msg_queue_t *node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBLISH, (int)qos ); + + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("Sent: %d\n", node->msg.length); + if( mud->secure ) + espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + else + espconn_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + mud->keep_alive_tick = 0; + } + + if(!node){ + lua_pushboolean(L, 0); + } else { + lua_pushboolean(L, 1); // enqueued succeed. + } mud->mqtt_state.outbound_message = NULL; + NODE_DBG("leave mqtt_socket_publish.\n"); + return 1; +} + +// Lua: mqtt:lwt( topic, message, qos, retain, function(client) ) +static int mqtt_socket_lwt( lua_State* L ) +{ + NODE_DBG("enter mqtt_socket_lwt.\n"); + uint8_t stack = 1; + size_t topicSize, msgSize; + NODE_DBG("mqtt_socket_lwt.\n"); + lmqtt_userdata *mud = NULL; + const char *lwtTopic, *lwtMsg; + uint8_t lwtQoS, lwtRetain; + + mud = (lmqtt_userdata *)luaL_checkudata( L, stack, "mqtt.socket" ); + luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); + + if(mud == NULL) + return 0; + + stack++; + lwtTopic = luaL_checklstring( L, stack, &topicSize ); + if (lwtTopic == NULL) + { + return luaL_error( L, "need lwt topic"); + } + + stack++; + lwtMsg = luaL_checklstring( L, stack, &msgSize ); + if (lwtMsg == NULL) + { + return luaL_error( L, "need lwt message"); + } + + if(mud->connect_info.will_topic){ // free the previous one if there is any + c_free(mud->connect_info.will_topic); + mud->connect_info.will_topic = NULL; + } + if(mud->connect_info.will_message){ + c_free(mud->connect_info.will_message); + mud->connect_info.will_message = NULL; + } + + mud->connect_info.will_topic = (uint8_t*) c_zalloc( topicSize + 1 ); + mud->connect_info.will_message = (uint8_t*) c_zalloc( msgSize + 1 ); + if(!mud->connect_info.will_topic || !mud->connect_info.will_message){ + if(mud->connect_info.will_topic){ + c_free(mud->connect_info.will_topic); + mud->connect_info.will_topic = NULL; + } + if(mud->connect_info.will_message){ + c_free(mud->connect_info.will_message); + mud->connect_info.will_message = NULL; + } + return luaL_error( L, "not enough memory"); + } + c_memcpy(mud->connect_info.will_topic, lwtTopic, topicSize); + mud->connect_info.will_topic[topicSize] = 0; + c_memcpy(mud->connect_info.will_message, lwtMsg, msgSize); + mud->connect_info.will_message[msgSize] = 0; + + if ( lua_isnumber(L, stack) ) + { + mud->connect_info.will_qos = lua_tointeger(L, stack); + stack++; + } + if ( lua_isnumber(L, stack) ) + { + mud->connect_info.will_retain = lua_tointeger(L, stack); + stack++; + } + + NODE_DBG("mqtt_socket_lwt: topic: %s, message: %s, qos: %d, retain: %d\n", + mud->connect_info.will_topic, + mud->connect_info.will_message, + mud->connect_info.will_qos, + mud->connect_info.will_retain); + NODE_DBG("leave mqtt_socket_lwt.\n"); return 0; } @@ -1079,11 +1237,11 @@ static int mqtt_socket_publish( lua_State* L ) static const LUA_REG_TYPE mqtt_socket_map[] = { - { LSTRKEY( "lwt" ), LFUNCVAL ( mqtt_socket_lwt ) }, { LSTRKEY( "connect" ), LFUNCVAL ( mqtt_socket_connect ) }, { LSTRKEY( "close" ), LFUNCVAL ( mqtt_socket_close ) }, { LSTRKEY( "publish" ), LFUNCVAL ( mqtt_socket_publish ) }, { LSTRKEY( "subscribe" ), LFUNCVAL ( mqtt_socket_subscribe ) }, + { LSTRKEY( "lwt" ), LFUNCVAL ( mqtt_socket_lwt ) }, { LSTRKEY( "on" ), LFUNCVAL ( mqtt_socket_on ) }, { LSTRKEY( "__gc" ), LFUNCVAL ( mqtt_delete ) }, #if LUA_OPTIMIZE_MEMORY > 0 diff --git a/app/modules/node.c b/app/modules/node.c index 53d59ae0..5f6ae9bd 100644 --- a/app/modules/node.c +++ b/app/modules/node.c @@ -100,13 +100,15 @@ static int node_chipid( lua_State* L ) lua_pushinteger(L, id); return 1; } + +// deprecated, moved to adc module // Lua: readvdd33() -static int node_readvdd33( lua_State* L ) -{ - uint32_t vdd33 = readvdd33(); - lua_pushinteger(L, vdd33); - return 1; -} +// static int node_readvdd33( lua_State* L ) +// { +// uint32_t vdd33 = readvdd33(); +// lua_pushinteger(L, vdd33); +// return 1; +// } // Lua: flashid() static int node_flashid( lua_State* L ) @@ -430,7 +432,8 @@ const LUA_REG_TYPE node_map[] = #endif { LSTRKEY( "input" ), LFUNCVAL( node_input ) }, { LSTRKEY( "output" ), LFUNCVAL( node_output ) }, - { LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) }, +// Moved to adc module, use adc.readvdd33() +// { LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) }, { LSTRKEY( "compile" ), LFUNCVAL( node_compile) }, { LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) }, { LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) }, diff --git a/app/modules/u8g.c b/app/modules/u8g.c index 59cb20d9..fc39803b 100644 --- a/app/modules/u8g.c +++ b/app/modules/u8g.c @@ -916,7 +916,7 @@ uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, voi case U8G_COM_MSG_WRITE_BYTE: //u8g->pin_list[U8G_PI_SET_A0] = 1; if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 ) - return platform_i2c_stop( ESP_I2C_ID ), 0; + return platform_i2c_send_stop( ESP_I2C_ID ), 0; // ignore return value -> tolerate missing ACK if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 ) ; //return platform_i2c_send_stop( ESP_I2C_ID ), 0; diff --git a/app/mqtt/mqtt_msg.c b/app/mqtt/mqtt_msg.c index a58f6057..9c405a7c 100644 --- a/app/mqtt/mqtt_msg.c +++ b/app/mqtt/mqtt_msg.c @@ -29,7 +29,7 @@ * */ -#include +#include "c_string.h" #include "mqtt_msg.h" #define MQTT_MAX_FIXED_HEADER_SIZE 3 @@ -61,7 +61,7 @@ static int append_string(mqtt_connection_t* connection, const char* string, int connection->buffer[connection->message.length++] = len >> 8; connection->buffer[connection->message.length++] = len & 0xff; - memcpy(connection->buffer + connection->message.length, string, len); + c_memcpy(connection->buffer + connection->message.length, string, len); connection->message.length += len; return len + 2; @@ -121,7 +121,7 @@ static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) { - memset(connection, 0, sizeof(connection)); + c_memset(connection, 0, sizeof(connection)); connection->buffer = buffer; connection->buffer_length = buffer_length; } @@ -294,7 +294,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf variable_header->lengthMsb = 0; variable_header->lengthLsb = 4; - memcpy(variable_header->magic, "MQTT", 4); + c_memcpy(variable_header->magic, "MQTT", 4); variable_header->version = 4; variable_header->flags = 0; variable_header->keepaliveMsb = info->keepalive >> 8; @@ -305,7 +305,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->client_id != NULL && info->client_id[0] != '\0') { - if(append_string(connection, info->client_id, strlen(info->client_id)) < 0) + if(append_string(connection, info->client_id, c_strlen(info->client_id)) < 0) return fail_message(connection); } else @@ -313,10 +313,10 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->will_topic != NULL && info->will_topic[0] != '\0') { - if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) + if(append_string(connection, info->will_topic, c_strlen(info->will_topic)) < 0) return fail_message(connection); - if(append_string(connection, info->will_message, strlen(info->will_message)) < 0) + if(append_string(connection, info->will_message, c_strlen(info->will_message)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_WILL; @@ -327,7 +327,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->username != NULL && info->username[0] != '\0') { - if(append_string(connection, info->username, strlen(info->username)) < 0) + if(append_string(connection, info->username, c_strlen(info->username)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; @@ -335,7 +335,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->password != NULL && info->password[0] != '\0') { - if(append_string(connection, info->password, strlen(info->password)) < 0) + if(append_string(connection, info->password, c_strlen(info->password)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; @@ -351,7 +351,7 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi if(topic == NULL || topic[0] == '\0') return fail_message(connection); - if(append_string(connection, topic, strlen(topic)) < 0) + if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); if(qos > 0) @@ -364,7 +364,7 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi if(connection->message.length + data_length > connection->buffer_length) return fail_message(connection); - memcpy(connection->buffer + connection->message.length, data, data_length); + c_memcpy(connection->buffer + connection->message.length, data, data_length); connection->message.length += data_length; return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); @@ -412,7 +412,7 @@ mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* to if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); - if(append_string(connection, topic, strlen(topic)) < 0) + if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); if(connection->message.length + 1 > connection->buffer_length) @@ -432,7 +432,7 @@ mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); - if(append_string(connection, topic, strlen(topic)) < 0) + if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); diff --git a/app/mqtt/msg_queue.c b/app/mqtt/msg_queue.c new file mode 100644 index 00000000..afa98d41 --- /dev/null +++ b/app/mqtt/msg_queue.c @@ -0,0 +1,60 @@ +#include "c_string.h" +#include "c_stdlib.h" +#include "c_stdio.h" +#include "msg_queue.h" + +msg_queue_t *msg_enqueue(msg_queue_t **head, mqtt_message_t *msg, uint16_t msg_id, int msg_type, int publish_qos){ + if(!head){ + return NULL; + } + if (!msg || !msg->data || msg->length == 0){ + NODE_DBG("empty message\n"); + return NULL; + } + msg_queue_t *node = (msg_queue_t *)c_zalloc(sizeof(msg_queue_t)); + if(!node){ + NODE_DBG("not enough memory\n"); + return NULL; + } + + node->msg.data = (uint8_t *)c_zalloc(msg->length); + if(!node->msg.data){ + NODE_DBG("not enough memory\n"); + c_free(node); + return NULL; + } + c_memcpy(node->msg.data, msg->data, msg->length); + node->msg.length = msg->length; + node->next = NULL; + node->msg_id = msg_id; + node->msg_type = msg_type; + node->publish_qos = publish_qos; + + msg_queue_t *tail = *head; + if(tail){ + while(tail->next!=NULL) tail = tail->next; + tail->next = node; + } else { + *head = node; + } + return node; +} + +void msg_destroy(msg_queue_t *node){ + if(!node) return; + if(node->msg.data){ + c_free(node->msg.data); + node->msg.data = NULL; + } + c_free(node); +} + +msg_queue_t * msg_dequeue(msg_queue_t **head){ + if(!head || !*head){ + return NULL; + } + msg_queue_t *node = *head; // fetch head. + *head = node->next; // update head. + node->next = NULL; + return node; +} diff --git a/app/mqtt/msg_queue.h b/app/mqtt/msg_queue.h new file mode 100644 index 00000000..9da3f6bc --- /dev/null +++ b/app/mqtt/msg_queue.h @@ -0,0 +1,26 @@ +#ifndef _MSG_QUEUE_H +#define _MSG_QUEUE_H 1 +#include "mqtt_msg.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct msg_queue_t; + +typedef struct msg_queue_t { + struct msg_queue_t *next; + mqtt_message_t msg; + uint16_t msg_id; + int msg_type; + int publish_qos; +} msg_queue_t; + +msg_queue_t * msg_enqueue(msg_queue_t **head, mqtt_message_t *msg, uint16_t msg_id, int msg_type, int publish_qos); +void msg_destroy(msg_queue_t *node); +msg_queue_t * msg_dequeue(msg_queue_t **head); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/platform/flash_api.c b/app/platform/flash_api.c index a648d91b..a96619e9 100644 --- a/app/platform/flash_api.c +++ b/app/platform/flash_api.c @@ -321,7 +321,7 @@ bool flash_init_data_written(void) // FLASH SEC - 4 uint32_t data[2] ICACHE_STORE_ATTR; #if defined(FLASH_SAFE_API) - if (SPI_FLASH_RESULT_OK == flash_safe_read((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data))) + if (SPI_FLASH_RESULT_OK == flash_safe_read((flash_safe_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data))) #else if (SPI_FLASH_RESULT_OK == spi_flash_read((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data))) #endif // defined(FLASH_SAFE_API) @@ -369,8 +369,8 @@ bool flash_init_data_blank(void) // It will init system config to blank! bool result = false; #if defined(FLASH_SAFE_API) - if ((SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_rom_get_sec_num() - 2))) && - (SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_rom_get_sec_num() - 1)))) + if ((SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 2))) && + (SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 1)))) #else if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 2))) && (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 1)))) diff --git a/app/smart/smart.c b/app/smart/smart.c index b8114836..c362191a 100644 --- a/app/smart/smart.c +++ b/app/smart/smart.c @@ -127,11 +127,19 @@ int smart_check(uint8_t *nibble, uint16_t len, uint8_t *dst, uint8_t *got){ return res; } -void detect(uint8 *buf, uint16 len){ +void detect(uint8 *arg, uint16 len){ uint16_t seq; int16_t seq_delta = 0; uint16_t byte_num = 0, bit_num = 0; int16_t c = 0; + uint8 *buf = NULL; + if( len == 12 ){ + return; + } else if (len >= 64){ + buf = arg + sizeof(struct RxControl); + } else { + return; + } if( ( (buf[0]) & TYPE_SUBTYPE_MASK) != TYPE_SUBTYPE_QOS_DATA){ return; } diff --git a/app/smart/smart.h b/app/smart/smart.h index a702830a..434aecbe 100644 --- a/app/smart/smart.h +++ b/app/smart/smart.h @@ -59,6 +59,40 @@ extern "C" { #define STATION_CHECK_TIME (2*1000) +struct RxControl{ + signed rssi:8;//表示该包的信号强度 + unsigned rate:4; + unsigned is_group:1; + unsigned:1; + unsigned sig_mode:2;//表示该包是否是11n 的包,0 表示非11n,非0 表示11n + unsigned legacy_length:12;//如果不是11n 的包,它表示包的长度 + unsigned damatch0:1; + unsigned damatch1:1; + unsigned bssidmatch0:1; + unsigned bssidmatch1:1; + unsigned MCS:7;//如果是11n 的包,它表示包的调制编码序列,有效值:0-76 + unsigned CWB:1;//如果是11n 的包,它表示是否为HT40 的包 + unsigned HT_length:16;//如果是11n 的包,它表示包的长度 + unsigned Smoothing:1; + unsigned Not_Sounding:1; + unsigned:1; + unsigned Aggregation:1; + unsigned STBC:2; + unsigned FEC_CODING:1;//如果是11n 的包,它表示是否为LDPC 的包 + unsigned SGI:1; + unsigned rxend_state:8; + unsigned ampdu_cnt:8; + unsigned channel:4;//表示该包所在的信道 + unsigned:12; +}; + +struct sniffer_buf{ + struct RxControl rx_ctrl; // 12-bytes + u8 buf[48];//包含ieee80211 包头 + u16 cnt;//包的个数 + u16 len[1];//包的长度 +}; + struct _my_addr_map { uint8 addr[ADDR_LENGTH*3]; uint8_t addr_len; diff --git a/app/spiffs/spiffs_nucleus.h b/app/spiffs/spiffs_nucleus.h index b4a34bcf..cc414432 100644 --- a/app/spiffs/spiffs_nucleus.h +++ b/app/spiffs/spiffs_nucleus.h @@ -395,13 +395,11 @@ typedef struct __attribute(( packed )) { // common page header spiffs_page_header p_hdr; // alignment - u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)]; + u8_t _align[4 - ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)==0 ? 4 : ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)]; // size of object u32_t size; // type of object spiffs_obj_type type; - // alignment2 - u8_t _align2[4 - (sizeof(spiffs_obj_type)&3)==0 ? 4 : (sizeof(spiffs_obj_type)&3)]; // name of object u8_t name[SPIFFS_OBJ_NAME_LEN]; } spiffs_page_object_ix_header; diff --git a/examples/fragment.lua b/examples/fragment.lua index fc426326..8cc5bd31 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -381,3 +381,72 @@ function TestDNSLeak() tmr.alarm(1, 3000, 0, function() print("hack socket close, MEM: "..node.heap()) c:close() end) -- socket timeout hack print("MEM: "..node.heap()) end + +v="abc%0D%0Adef" +print(string.gsub(v, "%%(%x%x)", function(x) return string.char(tonumber(x, 16)) end)) + +function ex(x) string.find("abc%0Ddef","bc") return 's' end +string.gsub("abc%0Ddef", "%%(%x%x)", ex) + +function ex(x) string.char(35) return 's' end +string.gsub("abc%0Ddef", "%%(%x%x)", ex) print("hello") + +function ex(x) string.lower('Ab') return 's' end +string.gsub("abc%0Ddef", "%%(%x%x)", ex) print("hello") + +v="abc%0D%0Adef" +pcall(function() print(string.gsub(v, "%%(%x%x)", function(x) return string.char(tonumber(x, 16)) end)) end) + +mosca -v | bunyan + +m=mqtt.Client() +m:connect("192.168.18.88",1883) +topic={} +topic["/topic1"]=0 +topic["/topic2"]=0 +m:subscribe(topic,function(m) print("sub done") end) +m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end ) +m:publish("/topic1","hello",0,0) +m:publish("/topic3","hello",0,0) m:publish("/topic4","hello",0,0) + +m=mqtt.Client() +m:connect("192.168.18.88",1883) +m:subscribe("/topic1",0,function(m) print("sub done") end) +m:subscribe("/topic2",0,function(m) print("sub done") end) +m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end ) +m:publish("/topic1","hello",0,0) +m:publish("/topic3","hello",0,0) m:publish("/topic4","hello",0,0) +m:publish("/topic1","hello1",0,0) m:publish("/topic2","hello2",0,0) +m:publish("/topic1","hello",1,0) +m:subscribe("/topic3",2,function(m) print("sub done") end) +m:publish("/topic3","hello3",2,0) + +m=mqtt.Client() +m:connect("192.168.18.88",1883, function(con) print("connected hello") end) + +m=mqtt.Client() +m:on("connect",function(m) print("connection") end ) +m:connect("192.168.18.88",1883) +m:on("offline",function(m) print("disconnection") end ) + +m=mqtt.Client() +m:on("connect",function(m) print("connection "..node.heap()) end ) +m:on("offline", function(conn) + if conn == nil then print("conn is nil") end + print("Reconnect to broker...") + print(node.heap()) + conn:connect("192.168.18.88",1883,0,1) +end) +m:connect("192.168.18.88",1883,0,1) + +m=mqtt.Client() +m:on("connect",function(m) print("connection "..node.heap()) end ) +m:on("offline", function(conn) + if conn == nil then print("conn is nil") end + print("Reconnect to broker...") + print(node.heap()) + conn:connect("192.168.18.88",1883) +end) +m:connect("192.168.18.88",1883) + +m:close() diff --git a/examples/init.lua b/examples/init.lua new file mode 100644 index 00000000..a2b306ce --- /dev/null +++ b/examples/init.lua @@ -0,0 +1,18 @@ +--init.lua, something like this +countdown = 3 +tmr.alarm(0,1000,1,function() + print(countdown) + countdown = countdown-1 + if countdown<1 then + tmr.stop(0) + countdown = nil + local s,err + if file.open("user.lc") then + file.close() + s,err = pcall(function() dofile("user.lc") end) + else + s,err = pcall(function() dofile("user.lua") end) + end + if not s then print(err) end + end +end) diff --git a/examples/user.lua b/examples/user.lua new file mode 100644 index 00000000..7a58cfac --- /dev/null +++ b/examples/user.lua @@ -0,0 +1 @@ +print("hello NodeMCU") diff --git a/ld/eagle.app.v6.ld b/ld/eagle.app.v6.ld index 141cab6d..0dc5bd07 100644 --- a/ld/eagle.app.v6.ld +++ b/ld/eagle.app.v6.ld @@ -5,7 +5,7 @@ MEMORY dport0_0_seg : org = 0x3FF00000, len = 0x10 dram0_0_seg : org = 0x3FFE8000, len = 0x14000 iram1_0_seg : org = 0x40100000, len = 0x8000 - irom0_0_seg : org = 0x40210000, len = 0x5A000 + irom0_0_seg : org = 0x40210000, len = 0x60000 } PHDRS diff --git a/tools/esptool.py b/tools/esptool.py index 130e80f0..88a4b4ed 100755 --- a/tools/esptool.py +++ b/tools/esptool.py @@ -41,7 +41,7 @@ class ESPROM: # Maximum block sized for RAM and Flash writes, respectively. ESP_RAM_BLOCK = 0x1800 - ESP_FLASH_BLOCK = 0x100 + ESP_FLASH_BLOCK = 0x400 # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want. ESP_ROM_BAUD = 115200 @@ -56,6 +56,12 @@ class ESPROM: ESP_OTP_MAC0 = 0x3ff00050 ESP_OTP_MAC1 = 0x3ff00054 + # Sflash stub: an assembly routine to read from spi flash and send to host + SFLASH_STUB = "\x80\x3c\x00\x40\x1c\x4b\x00\x40\x21\x11\x00\x40\x00\x80" \ + "\xfe\x3f\xc1\xfb\xff\xd1\xf8\xff\x2d\x0d\x31\xfd\xff\x41\xf7\xff\x4a" \ + "\xdd\x51\xf9\xff\xc0\x05\x00\x21\xf9\xff\x31\xf3\xff\x41\xf5\xff\xc0" \ + "\x04\x00\x0b\xcc\x56\xec\xfd\x06\xff\xff\x00\x00" + def __init__(self, port = 0, baud = ESP_ROM_BAUD): self._port = serial.Serial(port, baud) @@ -78,15 +84,7 @@ class ESPROM: """ Write bytes to the serial port while performing SLIP escaping """ def write(self, packet): - buf = '\xc0' - for b in packet: - if b == '\xc0': - buf += '\xdb\xdc' - elif b == '\xdb': - buf += '\xdb\xdd' - else: - buf += b - buf += '\xc0' + buf = '\xc0'+(packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc'))+'\xc0' self._port.write(buf) """ Calculate checksum of a blob, as it is defined by the ROM """ @@ -132,11 +130,25 @@ class ESPROM: # RTS = CH_PD (i.e reset) # DTR = GPIO0 + # self._port.setRTS(True) + # self._port.setDTR(True) + # self._port.setRTS(False) + # time.sleep(0.1) + # self._port.setDTR(False) + + # NodeMCU devkit self._port.setRTS(True) self._port.setDTR(True) - self._port.setRTS(False) time.sleep(0.1) + self._port.setRTS(False) self._port.setDTR(False) + time.sleep(0.1) + self._port.setRTS(True) + time.sleep(0.1) + self._port.setDTR(True) + self._port.setRTS(False) + time.sleep(0.3) + self._port.setDTR(True) self._port.timeout = 0.5 for i in xrange(10): @@ -209,16 +221,78 @@ class ESPROM: self.flash_begin(0, 0) self.flash_finish(reboot) + """ Read MAC from OTP ROM """ + def read_mac(self): + mac0 = esp.read_reg(esp.ESP_OTP_MAC0) + mac1 = esp.read_reg(esp.ESP_OTP_MAC1) + if ((mac1 >> 16) & 0xff) == 0: + oui = (0x18, 0xfe, 0x34) + elif ((mac1 >> 16) & 0xff) == 1: + oui = (0xac, 0xd0, 0x74) + else: + raise Exception("Unknown OUI") + return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) + + """ Read SPI flash manufacturer and device id """ + def flash_id(self): + self.flash_begin(0, 0) + self.write_reg(0x60000240, 0x0, 0xffffffff) + self.write_reg(0x60000200, 0x10000000, 0xffffffff) + flash_id = esp.read_reg(0x60000240) + self.flash_finish(False) + return flash_id + + """ Read SPI flash """ + def flash_read(self, offset, size, count = 1): + # Create a custom stub + stub = struct.pack(' 16: @@ -246,7 +320,8 @@ class ESPFirmwareImage: def save(self, filename): f = file(filename, 'wb') - f.write(struct.pack('> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) + mac = esp.read_mac() + print 'MAC: %s' % ':'.join(map(lambda x: '%02x'%x, mac)) + + elif args.operation == 'flash_id': + flash_id = esp.flash_id() + print 'Manufacturer: %02x' % (flash_id & 0xff) + print 'Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff) + + elif args.operation == 'read_flash': + print 'Please wait...' + file(args.filename, 'wb').write(esp.flash_read(args.address, 1024, int(math.ceil(args.size / 1024.)))[:args.size]) + + elif args.operation == 'erase_flash': + esp.flash_erase()