diff --git a/README.md b/README.md
index 299841c6..75bdcc7f 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,12 @@ Tencent QQ group: 309957875
- cross compiler (done)
# Change log
+2015-03-31
+polish mqtt module, add queue for mqtt module.
+add reconnect option to mqtt.connect api, :connect( host, port, secure, auto_reconnect, function(client) )
+move node.readvdd33 to adc.readvdd33.
+tools/esptool.py supported NodeMCU devkit automatic flash.
+
2015-03-18
update u8glib.
merge everything to master.
@@ -225,8 +231,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 +243,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 disable auto-reconnect and then disconnect from host.
-- 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..e9357259 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 20150405"
#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/lua/luaconf.h b/app/lua/luaconf.h
index 1a1760c7..7e0b182c 100644
--- a/app/lua/luaconf.h
+++ b/app/lua/luaconf.h
@@ -541,8 +541,12 @@ extern int readline4lua(const char *prompt, char *buffer, int length);
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+** Attention: This value should probably not be set higher than 1K.
+** The size has direct impact on the C stack size needed be auxlib functions.
+** For example: If set to 4K a call to string.gsub will need more than
+** 5k C stack space.
*/
-#define LUAL_BUFFERSIZE ((BUFSIZ)*4)
+#define LUAL_BUFFERSIZE BUFSIZ
/* }================================================================== */
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/auxmods.h b/app/modules/auxmods.h
index 149b1af3..ece3ff56 100644
--- a/app/modules/auxmods.h
+++ b/app/modules/auxmods.h
@@ -80,7 +80,7 @@ LUALIB_API int ( luaopen_file )( lua_State *L );
LUALIB_API int ( luaopen_ow )( lua_State *L );
#define AUXLIB_CJSON "cjson"
-LUALIB_API int ( luaopen_ow )( lua_State *L );
+LUALIB_API int ( luaopen_cjson )( lua_State *L );
// Helper macros
#define MOD_CHECK_ID( mod, id )\
diff --git a/app/modules/gpio.c b/app/modules/gpio.c
index 551dca8a..79e4e850 100644
--- a/app/modules/gpio.c
+++ b/app/modules/gpio.c
@@ -146,6 +146,82 @@ static int lgpio_write( lua_State* L )
return 0;
}
+#define DELAY_TABLE_MAX_LEN 256
+#define noInterrupts os_intr_lock
+#define interrupts os_intr_unlock
+#define delayMicroseconds os_delay_us
+#define DIRECT_WRITE(pin, level) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level))
+// Lua: serout( pin, firstLevel, delay_table, [repeatNum] )
+// -- serout( pin, firstLevel, delay_table, [repeatNum] )
+// gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
+// gpio.serout(1,1,{30,30,60,60,30,30}) -- serial one byte, b10110010
+// gpio.serout(1,1,{30,70},8) -- serial 30% pwm 10k, lasts 8 cycles
+// gpio.serout(1,1,{3,7},8) -- serial 30% pwm 100k, lasts 8 cycles
+// gpio.serout(1,1,{0,0},8) -- serial 50% pwm as fast as possible, lasts 8 cycles
+// gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
+// gpio.serout(1,0,{20,10,10,20,10,10,10,100}) -- sim uart one byte 0x5A at about 100kbps
+// gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
+static int lgpio_serout( lua_State* L )
+{
+ unsigned level;
+ unsigned pin;
+ unsigned table_len = 0;
+ unsigned repeat = 0;
+ int delay_table[DELAY_TABLE_MAX_LEN];
+
+ pin = luaL_checkinteger( L, 1 );
+ MOD_CHECK_ID( gpio, pin );
+ level = luaL_checkinteger( L, 2 );
+ if ( level!=HIGH && level!=LOW )
+ return luaL_error( L, "wrong arg type" );
+ if( lua_istable( L, 3 ) )
+ {
+ table_len = lua_objlen( L, 3 );
+ if (table_len <= 0 || table_len>DELAY_TABLE_MAX_LEN)
+ return luaL_error( L, "wrong arg range" );
+ int i;
+ for( i = 0; i < table_len; i ++ )
+ {
+ lua_rawgeti( L, 3, i + 1 );
+ delay_table[i] = ( int )luaL_checkinteger( L, -1 );
+ lua_pop( L, 1 );
+ if( delay_table[i] < 0 || delay_table[i] > 1000000 ) // can not delay more than 1000000 us
+ return luaL_error( L, "delay must < 1000000 us" );
+ }
+ } else {
+ return luaL_error( L, "wrong arg range" );
+ }
+
+ if(lua_isnumber(L, 4))
+ repeat = lua_tointeger( L, 4 );
+ if( repeat < 0 || repeat > DELAY_TABLE_MAX_LEN )
+ return luaL_error( L, "delay must < 256" );
+
+ if(repeat==0)
+ repeat = 1;
+ int j;
+ bool skip_loop = true;
+ do
+ {
+ if(skip_loop){ // skip the first loop.
+ skip_loop = false;
+ continue;
+ }
+ for(j=0;j0);
+
+ return 0;
+}
+#undef DELAY_TABLE_MAX_LEN
+
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
@@ -154,6 +230,7 @@ const LUA_REG_TYPE gpio_map[] =
{ LSTRKEY( "mode" ), LFUNCVAL( lgpio_mode ) },
{ LSTRKEY( "read" ), LFUNCVAL( lgpio_read ) },
{ LSTRKEY( "write" ), LFUNCVAL( lgpio_write ) },
+ { LSTRKEY( "serout" ), LFUNCVAL( lgpio_serout ) },
#ifdef GPIO_INTERRUPT_ENABLE
{ LSTRKEY( "trig" ), LFUNCVAL( lgpio_trig ) },
#endif
diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c
index 018e034e..c7afd0ff 100644
--- a/app/modules/mqtt.c
+++ b/app/modules/mqtt.c
@@ -15,8 +15,7 @@
#include "espconn.h"
#include "mqtt_msg.h"
-
-static lua_State *gL = NULL;
+#include "msg_queue.h"
#define MQTT_BUF_SIZE 1024
#define MQTT_DEFAULT_KEEPALIVE 60
@@ -24,10 +23,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;
@@ -47,22 +47,15 @@ typedef struct mqtt_state_t
uint16_t port;
int auto_reconnect;
mqtt_connect_info_t* connect_info;
- uint8_t* in_buffer;
- uint8_t* out_buffer;
- int in_buffer_length;
- int out_buffer_length;
uint16_t message_length;
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
{
+ lua_State *L;
struct espconn *pesp_conn;
int self_ref;
int cb_connect_ref;
@@ -73,54 +66,104 @@ 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_reconnected(void *arg, sint8_t err);
+static void mqtt_socket_connected(void *arg);
+
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->connected){ // call back only called when socket is from connection to disconnection.
+ mud->connected = false;
+ if((mud->L != NULL) && (mud->cb_disconnect_ref != LUA_NOREF) && (mud->self_ref != LUA_NOREF)) {
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_disconnect_ref);
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua
+ call_back = true;
+ }
+ }
+
+ if(mud->mqtt_state.auto_reconnect){
+ mud->pesp_conn->reverse = mud;
+ mud->pesp_conn->type = ESPCONN_TCP;
+ mud->pesp_conn->state = ESPCONN_NONE;
+ mud->connected = false;
+ mud->pesp_conn->proto.tcp->remote_port = mud->mqtt_state.port;
+ mud->pesp_conn->proto.tcp->local_port = espconn_port();
+ espconn_regist_connectcb(mud->pesp_conn, mqtt_socket_connected);
+ espconn_regist_reconcb(mud->pesp_conn, mqtt_socket_reconnected);
+ socket_connect(pesp_conn);
+ } else {
+ 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->L == NULL)
+ return;
+ lua_gc(mud->L, LUA_GCSTOP, 0);
+ if(mud->self_ref != LUA_NOREF){ // TODO: should we unref the client and delete it?
+ luaL_unref(mud->L, LUA_REGISTRYINDEX, mud->self_ref);
+ mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self
+ }
+ lua_gc(mud->L, LUA_GCRESTART, 0);
+ }
+
+ if((mud->L != NULL) && call_back){
+ lua_call(mud->L, 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;
+
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->mqtt_state.auto_reconnect){
+ pesp_conn->proto.tcp->remote_port = mud->mqtt_state.port;
+ pesp_conn->proto.tcp->local_port = espconn_port();
+ 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)
{
- const char comma[] = ",";
+ NODE_DBG("enter deliver_publish.\n");
+ if(mud == NULL)
+ return;
mqtt_event_data_t event_data;
event_data.topic_length = length;
@@ -133,28 +176,36 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length)
return;
if(mud->self_ref == LUA_NOREF)
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);
- lua_call(gL, 3, 0);
+ if(mud->L == NULL)
+ return;
+ if(event_data.topic && (event_data.topic_length > 0)){
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_message_ref);
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
+ lua_pushlstring(mud->L, event_data.topic, event_data.topic_length);
} else {
- lua_call(gL, 2, 0);
+ NODE_DBG("get wrong packet.\n");
+ return;
}
+ if(event_data.data && (event_data.data_length > 0)){
+ lua_pushlstring(mud->L, event_data.data, event_data.data_length);
+ lua_call(mud->L, 3, 0);
+ } else {
+ lua_call(mud->L, 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;
+ int length = (int)len;
+ // uint8_t in_buffer[MQTT_BUF_SIZE];
+ uint8_t *in_buffer = (uint8_t *)pdata;
struct espconn *pesp_conn = arg;
if(pesp_conn == NULL)
@@ -164,111 +215,152 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len)
return;
READPACKET:
- if(len > MQTT_BUF_SIZE && len <= 0)
+ if(length > MQTT_BUF_SIZE || length <= 0)
return;
- c_memcpy(mud->mqtt_state.in_buffer, pdata, len);
- mud->mqtt_state.outbound_message = NULL;
+ // c_memcpy(in_buffer, pdata, length);
+ uint8_t temp_buffer[MQTT_BUF_SIZE];
+ mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
+ mqtt_message_t *temp_msg = NULL;
switch(mud->connState){
case MQTT_CONNECT_SENDING:
- if(mqtt_get_type(mud->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK){
+ case MQTT_CONNECT_SENT:
+ if(mqtt_get_type(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");
if(mud->cb_connect_ref == LUA_NOREF)
- return;
+ break;
if(mud->self_ref == LUA_NOREF)
- return;
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_connect_ref);
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua
- lua_call(gL, 1, 0);
- return;
+ break;
+ if(mud->L == NULL)
+ break;
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_connect_ref);
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua
+ lua_call(mud->L, 1, 0);
+ break;
}
break;
case MQTT_DATA:
- mud->mqtt_state.message_length_read = len;
- mud->mqtt_state.message_length = mqtt_get_total_length(mud->mqtt_state.in_buffer, mud->mqtt_state.message_length_read);
- msg_type = mqtt_get_type(mud->mqtt_state.in_buffer);
- 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);
+ mud->mqtt_state.message_length_read = length;
+ mud->mqtt_state.message_length = mqtt_get_total_length(in_buffer, mud->mqtt_state.message_length_read);
+ msg_type = mqtt_get_type(in_buffer);
+ msg_qos = mqtt_get_qos(in_buffer);
+ msg_id = mqtt_get_id(in_buffer, mud->mqtt_state.message_length);
+
+ msg_queue_t *pending_msg = msg_peek(&(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;
+ if(mud->L == NULL)
+ break;
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_suback_ref);
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref);
+ lua_call(mud->L, 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)
- mud->mqtt_state.outbound_message = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id);
- else if(msg_qos == 2)
- mud->mqtt_state.outbound_message = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id);
-
- deliver_publish(mud, mud->mqtt_state.in_buffer, mud->mqtt_state.message_length_read);
+ if(msg_qos == 1){
+ temp_msg = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id);
+ node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
+ msg_id, MQTT_MSG_TYPE_PUBACK, (int)mqtt_get_qos(temp_msg->data) );
+ }
+ else if(msg_qos == 2){
+ temp_msg = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id);
+ node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
+ msg_id, MQTT_MSG_TYPE_PUBREC, (int)mqtt_get_qos(temp_msg->data) );
+ }
+ if(msg_qos == 1 || msg_qos == 2){
+ NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos);
+ }
+ deliver_publish(mud, in_buffer, mud->mqtt_state.message_length);
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)
break;
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_puback_ref);
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
- lua_call(gL, 1, 0);
+ if(mud->L == NULL)
+ break;
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
+ lua_call(mud->L, 1, 0);
}
break;
case MQTT_MSG_TYPE_PUBREC:
- mud->mqtt_state.outbound_message = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, 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 Received PUBREC\r\n");
+ // Note: actrually, should not destroy the msg until PUBCOMP is received.
+ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
+ temp_msg = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id);
+ node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
+ msg_id, MQTT_MSG_TYPE_PUBREL, (int)mqtt_get_qos(temp_msg->data) );
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);
+ if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBREC && pending_msg->msg_id == msg_id){
+ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
+ temp_msg = mqtt_msg_pubcomp(&mud->mqtt_state.mqtt_connection, msg_id);
+ node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
+ msg_id, MQTT_MSG_TYPE_PUBCOMP, (int)mqtt_get_qos(temp_msg->data) );
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_PUBREL && 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)
break;
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_puback_ref);
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
- lua_call(gL, 1, 0);
+ if(mud->L == NULL)
+ break;
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
+ lua_call(mud->L, 1, 0);
}
break;
case MQTT_MSG_TYPE_PINGREQ:
- mud->mqtt_state.outbound_message = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection);
+ temp_msg = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection);
+ node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
+ msg_id, MQTT_MSG_TYPE_PINGRESP, (int)mqtt_get_qos(temp_msg->data) );
+ 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
@@ -277,11 +369,11 @@ READPACKET:
if(msg_type == MQTT_MSG_TYPE_PUBLISH)
{
- len = mud->mqtt_state.message_length_read;
+ length = mud->mqtt_state.message_length_read;
if(mud->mqtt_state.message_length < mud->mqtt_state.message_length_read)
{
- len -= mud->mqtt_state.message_length;
+ length -= mud->mqtt_state.message_length;
pdata += mud->mqtt_state.message_length;
NODE_DBG("Get another published message\r\n");
@@ -291,19 +383,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 && (1==msg_size(&(mud->mqtt_state.pending_msg_q))) && 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);
- mud->mqtt_state.outbound_message = NULL;
+ espconn_sent( pesp_conn, node->msg.data, node->msg.length );
}
+ mud->keep_alive_tick = 0;
+ NODE_DBG("receive, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
+ 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,24 +407,44 @@ static void mqtt_socket_sent(void *arg)
if(mud == NULL)
return;
if(!mud->connected)
- return;
+ return;
// 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;
+ mud->keep_alive_tick = 0;
+
+ if(mud->connState == MQTT_CONNECT_SENDING){
+ mud->connState = MQTT_CONNECT_SENT;
+ // MQTT_CONNECT not queued.
+ return;
+ }
+ NODE_DBG("sent1, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
+ // qos = 0, publish and forgot.
+ msg_queue_t *node = msg_peek(&(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)
return;
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_puback_ref);
- lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
- lua_call(gL, 1, 0);
+ if(mud->L == NULL)
+ return;
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+ lua_rawgeti(mud->L, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua
+ lua_call(mud->L, 1, 0);
+ } else if(node && node->msg_type == MQTT_MSG_TYPE_PUBACK && node->publish_qos == 1) {
+ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
+ } else if(node && node->msg_type == MQTT_MSG_TYPE_PUBCOMP) {
+ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
+ } else if(node && node->msg_type == MQTT_MSG_TYPE_PINGREQ) {
+ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
}
+ NODE_DBG("sent2, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
+ 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;
@@ -340,57 +456,113 @@ static void mqtt_socket_connected(void *arg)
espconn_regist_sentcb(pesp_conn, mqtt_socket_sent);
espconn_regist_disconcb(pesp_conn, mqtt_socket_disconnected);
+ uint8_t temp_buffer[MQTT_BUF_SIZE];
// call mqtt_connect() to start a mqtt connect stage.
- 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){
- espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
- }
+ mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
+ mqtt_message_t* temp_msg = 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", temp_msg->length, temp_msg->data[0]);
+ mud->event_timeout = MQTT_SEND_TIMEOUT;
+ // not queue this message. should send right now. or should enqueue this before head.
+ if(mud->secure)
+ espconn_secure_sent(pesp_conn, temp_msg->data, temp_msg->length);
else
- {
- espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
- }
- mud->mqtt_state.outbound_message = NULL;
+ espconn_sent(pesp_conn, temp_msg->data, temp_msg->length);
+ mud->keep_alive_tick = 0;
+
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 == NULL)
+ return;
+ if(mud->pesp_conn == NULL){
+ NODE_DBG("mud->pesp_conn is NULL.\n");
+ os_timer_disarm(&mud->mqttTimer);
+ return;
+ }
- 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("timer, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
+ if(mud->event_timeout > 0){
+ NODE_DBG("event_timeout: %d.\n", mud->event_timeout);
+ mud->event_timeout --;
+ if(mud->event_timeout > 0){
+ return;
+ } else {
+ NODE_DBG("event timeout. \n");
+ if(mud->connState == MQTT_DATA)
+ msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q)));
+ // should remove the head of the queue and re-send with DUP = 1
+ // Not implemented yet.
}
}
- if(mud->send_timeout > 0)
- mud->send_timeout --;
+
+ if(mud->connState == MQTT_INIT){ // socket connect time out.
+ NODE_DBG("Can not connect to broker.\n");
+ // Never goes here.
+ } else if(mud->connState == MQTT_CONNECT_SENDING){ // MQTT_CONNECT send time out.
+ NODE_DBG("sSend MQTT_CONNECT failed.\n");
+ 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 = msg_peek(&(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;
+ uint8_t temp_buffer[MQTT_BUF_SIZE];
+ mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
+ NODE_DBG("\r\nMQTT: Send keepalive packet\r\n");
+ mqtt_message_t* temp_msg = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection);
+ msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), temp_msg,
+ 0, MQTT_MSG_TYPE_PINGREQ, (int)mqtt_get_qos(temp_msg->data) );
+ // only one message in queue, send immediately.
+ if(mud->secure)
+ espconn_secure_sent(mud->pesp_conn, temp_msg->data, temp_msg->length);
+ else
+ espconn_sent(mud->pesp_conn, temp_msg->data, temp_msg->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);
@@ -398,6 +570,7 @@ static int mqtt_socket_client( lua_State* L )
// create a object
mud = (lmqtt_userdata *)lua_newuserdata(L, sizeof(lmqtt_userdata));
// pre-initialize it, in case of errors
+ mud->L = NULL;
mud->self_ref = LUA_NOREF;
mud->cb_connect_ref = LUA_NOREF;
mud->cb_disconnect_ref = LUA_NOREF;
@@ -409,8 +582,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 +593,80 @@ static int mqtt_socket_client( lua_State* L )
luaL_getmetatable(L, "mqtt.socket");
lua_setmetatable(L, -2);
+ mud->L = L; // 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);
+ if(!mud->connect_info.client_id || !mud->connect_info.username || !mud->connect_info.password){
+ 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;
+ }
+ 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.pending_msg_q = NULL;
+ mud->mqtt_state.auto_reconnect = 0;
+ mud->mqtt_state.port = 1883;
+ mud->mqtt_state.connect_info = &mud->connect_info;
+
+ NODE_DBG("leave mqtt_socket_client.\n");
return 1;
}
@@ -508,7 +675,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 +685,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 +697,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;
@@ -550,14 +722,7 @@ static int mqtt_delete( lua_State* L )
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;
- }
+ // -------
// free (unref) callback ref
if(LUA_NOREF!=mud->cb_connect_ref){
@@ -580,32 +745,35 @@ static int mqtt_delete( lua_State* L )
luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
mud->cb_puback_ref = LUA_NOREF;
}
- lua_gc(gL, LUA_GCSTOP, 0);
+ lua_gc(L, LUA_GCSTOP, 0);
if(LUA_NOREF!=mud->self_ref){
luaL_unref(L, LUA_REGISTRYINDEX, mud->self_ref);
mud->self_ref = LUA_NOREF;
}
- lua_gc(gL, LUA_GCRESTART, 0);
+ lua_gc(L, 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){
+ mud->event_timeout = MQTT_CONNECT_TIMEOUT;
+ mud->connState = MQTT_INIT;
+ 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 +781,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 +813,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 +835,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 +864,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 +890,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 +904,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 +933,10 @@ 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()
+
if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0))
{
host_ip.addr = 0;
@@ -819,10 +950,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 +958,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;
@@ -843,6 +971,7 @@ static int mqtt_socket_close( lua_State* L )
return 0;
// call mqtt_disconnect()
+ mud->mqtt_state.auto_reconnect = 0; // stop auto reconnect.
if(mud->secure){
if(mud->pesp_conn->proto.tcp->remote_port || mud->pesp_conn->proto.tcp->local_port)
@@ -853,13 +982,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 +1023,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 +1041,145 @@ 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==NULL){
+ NODE_DBG("userdata is nil.\n");
+ lua_pushboolean(L, 0);
+ return 1;
+ }
- if( !mud->connected )
- return luaL_error( L, "not connected" );
+ if(mud->pesp_conn == NULL){
+ NODE_DBG("mud->pesp_conn is NULL.\n");
+ lua_pushboolean(L, 0);
+ return 1;
+ }
+
+ if(!mud->connected){
+ luaL_error( L, "not connected" );
+ lua_pushboolean(L, 0);
+ return 1;
+ }
+
+ uint8_t temp_buffer[MQTT_BUF_SIZE];
+ mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
+ mqtt_message_t *temp_msg = NULL;
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_buf[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 );
- 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 );
+ temp_msg = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id );
+ NODE_DBG("topic: %s - qos: %d, length: %d\n", topic, qos, temp_msg->length);
+
+ if (temp_pos + temp_msg->length > MQTT_BUF_SIZE){
+ lua_pop(L, 1);
+ break; // too long message for the outbuffer.
+ }
+ c_memcpy( temp_buf + temp_pos, temp_msg->data, temp_msg->length );
+ temp_pos += temp_msg->length;
- curr->length = mud->mqtt_state.outbound_message->length;
- curr->next = NULL;
- last->next = curr;
- last = curr;
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" );
- }
- mud->mqtt_state.outbound_message->data = mud->mqtt_state.out_buffer;
- mud->mqtt_state.outbound_message->length = ptr;
+ if (temp_pos == 0){
+ luaL_error( L, "invalid data" );
+ lua_pushboolean(L, 0);
+ return 1;
+ }
+
+ c_memcpy( temp_buffer, temp_buf, temp_pos );
+ temp_msg->data = temp_buffer;
+ temp_msg->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 );
+ temp_msg = 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), temp_msg,
+ msg_id, MQTT_MSG_TYPE_SUBSCRIBE, (int)mqtt_get_qos(temp_msg->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 && (1==msg_size(&(mud->mqtt_state.pending_msg_q))) && 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.
+ }
+ NODE_DBG("subscribe, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
+ 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->connected){
+ luaL_error( L, "not connected" );
+ 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 +1188,13 @@ 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,
+ uint8_t temp_buffer[MQTT_BUF_SIZE];
+ mqtt_msg_init(&mud->mqtt_state.mqtt_connection, temp_buffer, MQTT_BUF_SIZE);
+ mqtt_message_t *temp_msg = 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 +1202,105 @@ 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);
- mud->mqtt_state.outbound_message = NULL;
+ msg_queue_t *node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), temp_msg,
+ msg_id, MQTT_MSG_TYPE_PUBLISH, (int)qos );
+
+ if(node && (1==msg_size(&(mud->mqtt_state.pending_msg_q))) && 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.
+ }
+
+ NODE_DBG("publish, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q)));
+ 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 +1310,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/wifi.c b/app/modules/wifi.c
index 635625c6..d2b2d2e5 100644
--- a/app/modules/wifi.c
+++ b/app/modules/wifi.c
@@ -8,6 +8,7 @@
#include "lrotable.h"
#include "c_string.h"
+#include "c_stdlib.h"
#include "c_types.h"
#include "user_interface.h"
@@ -327,8 +328,8 @@ static int wifi_station_config( lua_State* L )
if (sl>32 || ssid == NULL)
return luaL_error( L, "ssid:<32" );
const char *password = luaL_checklstring( L, 2, &pl );
- if (pl>64 || password == NULL)
- return luaL_error( L, "pwd:<64" );
+ if (pl<8 || pl>64 || password == NULL)
+ return luaL_error( L, "pwd:8~64" );
c_memset(sta_conf.ssid, 0, 32);
c_memset(sta_conf.password, 0, 64);
@@ -380,6 +381,7 @@ static int wifi_station_setauto( lua_State* L )
return 0;
}
+// Lua: table = wifi.sta.getap()
static int wifi_station_listap( lua_State* L )
{
if(wifi_get_opmode() == SOFTAP_MODE)
@@ -437,44 +439,46 @@ static int wifi_ap_getbroadcast( lua_State* L ){
// Lua: wifi.ap.config(table)
static int wifi_ap_config( lua_State* L )
{
- struct softap_config config;
- size_t len;
- wifi_softap_get_config(&config);
if (!lua_istable(L, 1))
return luaL_error( L, "wrong arg type" );
+ struct softap_config config;
+ wifi_softap_get_config(&config);
+
+ size_t len;
+
lua_getfield(L, 1, "ssid");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the ssid string
{
const char *ssid = luaL_checklstring( L, -1, &len );
- if(len>32)
- return luaL_error( L, "ssid:<32" );
+ if(len<1 || len>32 || ssid == NULL)
+ return luaL_error( L, "ssid:1~32" );
c_memset(config.ssid, 0, 32);
c_memcpy(config.ssid, ssid, len);
- config.ssid_len = len;
- config.ssid_hidden = 0;
NODE_DBG(config.ssid);
NODE_DBG("\n");
+ config.ssid_len = len;
+ config.ssid_hidden = 0;
}
else
return luaL_error( L, "wrong arg type" );
}
else
- return luaL_error( L, "wrong arg type" );
+ return luaL_error( L, "ssid required" );
lua_getfield(L, 1, "pwd");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the password string
{
const char *pwd = luaL_checklstring( L, -1, &len );
- if(len>64)
- return luaL_error( L, "pwd:<64" );
+ if(len<8 || len>64 || pwd == NULL)
+ return luaL_error( L, "pwd:8~64" );
c_memset(config.password, 0, 64);
c_memcpy(config.password, pwd, len);
- config.authmode = AUTH_WPA_WPA2_PSK;
NODE_DBG(config.password);
NODE_DBG("\n");
+ config.authmode = AUTH_WPA_WPA2_PSK;
}
else
return luaL_error( L, "wrong arg type" );
@@ -483,11 +487,162 @@ static int wifi_ap_config( lua_State* L )
config.authmode = AUTH_OPEN;
}
- config.max_connection = 4;
+ lua_getfield(L, 1, "auth");
+ if (!lua_isnil(L, -1))
+ {
+ config.authmode = (uint8_t)luaL_checkinteger(L, -1);
+ NODE_DBG(config.authmode);
+ NODE_DBG("\n");
+ }
+ else
+ {
+ // keep whatever value resulted from "pwd" logic above
+ }
+
+ lua_getfield(L, 1, "channel");
+ if (!lua_isnil(L, -1))
+ {
+ unsigned channel = luaL_checkinteger(L, -1);
+ if (channel < 1 || channel > 13)
+ return luaL_error( L, "channel:1~13" );
+
+ config.channel = (uint8_t)channel;
+ NODE_DBG(config.channel);
+ NODE_DBG("\n");
+ }
+ else
+ {
+ config.channel = 6;
+ }
+
+ lua_getfield(L, 1, "hidden");
+ if (!lua_isnil(L, -1))
+ {
+ config.ssid_hidden = (uint8_t)luaL_checkinteger(L, -1);
+ NODE_DBG(config.ssid_hidden);
+ NODE_DBG("\n");
+ }
+ else
+ {
+ config.ssid_hidden = 0;
+ }
+
+ lua_getfield(L, 1, "max");
+ if (!lua_isnil(L, -1))
+ {
+ unsigned max = luaL_checkinteger(L, -1);
+ if (max < 1 || max > 4)
+ return luaL_error( L, "max:1~4" );
+
+ config.max_connection = (uint8_t)max;
+ NODE_DBG(config.max_connection);
+ NODE_DBG("\n");
+ }
+ else
+ {
+ config.max_connection = 4;
+ }
+
+ lua_getfield(L, 1, "beacon");
+ if (!lua_isnil(L, -1))
+ {
+ unsigned beacon = luaL_checkinteger(L, -1);
+ if (beacon < 100 || beacon > 60000)
+ return luaL_error( L, "beacon:100~60000" );
+
+ config.beacon_interval = (uint16_t)beacon;
+ NODE_DBG(config.beacon_interval);
+ NODE_DBG("\n");
+ }
+ else
+ {
+ config.beacon_interval = 100;
+ }
wifi_softap_set_config(&config);
// system_restart();
- return 0;
+ return 0;
+}
+
+// Lua: table = wifi.ap.getclient()
+static int wifi_ap_listclient( lua_State* L )
+{
+ if (wifi_get_opmode() == STATION_MODE)
+ {
+ return luaL_error( L, "Can't list client in STATION_MODE mode" );
+ }
+
+ char temp[64];
+
+ lua_newtable(L);
+
+ struct station_info * station = wifi_softap_get_station_info();
+ struct station_info * next_station;
+ while (station != NULL)
+ {
+ c_sprintf(temp, IPSTR, IP2STR(&station->ip));
+ lua_pushstring(L, temp);
+
+ c_sprintf(temp, MACSTR, MAC2STR(station->bssid));
+ lua_setfield(L, -2, temp);
+
+ next_station = STAILQ_NEXT(station, next);
+ c_free(station);
+ station = next_station;
+ }
+
+ return 1;
+}
+
+// Lua: ip = wifi.ap.dhcp.config()
+static int wifi_ap_dhcp_config( lua_State* L )
+{
+ if (!lua_istable(L, 1))
+ return luaL_error( L, "wrong arg type" );
+
+ struct dhcps_lease lease;
+ uint32_t ip;
+
+ ip = parse_key(L, "start");
+ if (ip == 0)
+ return luaL_error( L, "wrong arg type" );
+
+ lease.start_ip = ip;
+ NODE_DBG(IPSTR, IP2STR(&lease.start_ip));
+ NODE_DBG("\n");
+
+ // use configured max_connection to determine end
+ struct softap_config config;
+ wifi_softap_get_config(&config);
+ lease.end_ip = lease.start_ip;
+ ip4_addr4(&lease.end_ip) += config.max_connection - 1;
+
+ char temp[64];
+ c_sprintf(temp, IPSTR, IP2STR(&lease.start_ip));
+ lua_pushstring(L, temp);
+ c_sprintf(temp, IPSTR, IP2STR(&lease.end_ip));
+ lua_pushstring(L, temp);
+
+ // note: DHCP max range = 101 from start_ip to end_ip
+ wifi_softap_dhcps_stop();
+ wifi_softap_set_dhcps_lease(&lease);
+ wifi_softap_dhcps_start();
+
+ return 2;
+}
+
+// Lua: wifi.ap.dhcp.start()
+static int wifi_ap_dhcp_start( lua_State* L )
+{
+ lua_pushboolean(L, wifi_softap_dhcps_start());
+ return 1;
+}
+
+// Lua: wifi.ap.dhcp.stop()
+static int wifi_ap_dhcp_stop( lua_State* L )
+{
+ lua_pushboolean(L, wifi_softap_dhcps_stop());
+ return 1;
}
// Module function map
@@ -509,6 +664,14 @@ static const LUA_REG_TYPE wifi_station_map[] =
{ LNILKEY, LNILVAL }
};
+static const LUA_REG_TYPE wifi_ap_dhcp_map[] =
+{
+ { LSTRKEY( "config" ), LFUNCVAL( wifi_ap_dhcp_config ) },
+ { LSTRKEY( "start" ), LFUNCVAL( wifi_ap_dhcp_start ) },
+ { LSTRKEY( "stop" ), LFUNCVAL( wifi_ap_dhcp_stop ) },
+ { LNILKEY, LNILVAL }
+};
+
static const LUA_REG_TYPE wifi_ap_map[] =
{
{ LSTRKEY( "config" ), LFUNCVAL( wifi_ap_config ) },
@@ -517,6 +680,12 @@ static const LUA_REG_TYPE wifi_ap_map[] =
{ LSTRKEY( "getbroadcast" ), LFUNCVAL ( wifi_ap_getbroadcast) },
{ LSTRKEY( "getmac" ), LFUNCVAL ( wifi_ap_getmac ) },
{ LSTRKEY( "setmac" ), LFUNCVAL ( wifi_ap_setmac ) },
+ { LSTRKEY( "getclient" ), LFUNCVAL ( wifi_ap_listclient ) },
+#if LUA_OPTIMIZE_MEMORY > 0
+ { LSTRKEY( "dhcp" ), LROVAL( wifi_ap_dhcp_map ) },
+
+// { LSTRKEY( "__metatable" ), LROVAL( wifi_ap_map ) },
+#endif
{ LNILKEY, LNILVAL }
};
@@ -540,6 +709,12 @@ const LUA_REG_TYPE wifi_map[] =
{ LSTRKEY( "LIGHT_SLEEP" ), LNUMVAL( LIGHT_SLEEP_T ) },
{ LSTRKEY( "MODEM_SLEEP" ), LNUMVAL( MODEM_SLEEP_T ) },
+ { LSTRKEY( "OPEN" ), LNUMVAL( AUTH_OPEN ) },
+ // { LSTRKEY( "WEP" ), LNUMVAL( AUTH_WEP ) },
+ { LSTRKEY( "WPA_PSK" ), LNUMVAL( AUTH_WPA_PSK ) },
+ { LSTRKEY( "WPA2_PSK" ), LNUMVAL( AUTH_WPA2_PSK ) },
+ { LSTRKEY( "WPA_WPA2_PSK" ), LNUMVAL( AUTH_WPA_WPA2_PSK ) },
+
// { LSTRKEY( "STA_IDLE" ), LNUMVAL( STATION_IDLE ) },
// { LSTRKEY( "STA_CONNECTING" ), LNUMVAL( STATION_CONNECTING ) },
// { LSTRKEY( "STA_WRONGPWD" ), LNUMVAL( STATION_WRONG_PASSWORD ) },
@@ -573,6 +748,12 @@ LUALIB_API int luaopen_wifi( lua_State *L )
MOD_REG_NUMBER( L, "LIGHT_SLEEP", LIGHT_SLEEP_T );
MOD_REG_NUMBER( L, "MODEM_SLEEP", MODEM_SLEEP_T );
+ MOD_REG_NUMBER( L, "OPEN", AUTH_OPEN );
+ // MOD_REG_NUMBER( L, "WEP", AUTH_WEP );
+ MOD_REG_NUMBER( L, "WPA_PSK", AUTH_WPA_PSK );
+ MOD_REG_NUMBER( L, "WPA2_PSK", AUTH_WPA2_PSK );
+ MOD_REG_NUMBER( L, "WPA_WPA2_PSK", AUTH_WPA_WPA2_PSK );
+
// MOD_REG_NUMBER( L, "STA_IDLE", STATION_IDLE );
// MOD_REG_NUMBER( L, "STA_CONNECTING", STATION_CONNECTING );
// MOD_REG_NUMBER( L, "STA_WRONGPWD", STATION_WRONG_PASSWORD );
@@ -589,6 +770,11 @@ LUALIB_API int luaopen_wifi( lua_State *L )
luaL_register( L, NULL, wifi_ap_map );
lua_setfield( L, -2, "ap" );
+ // Setup the new table (dhcp) inside ap
+ lua_newtable( L );
+ luaL_register( L, NULL, wifi_ap_dhcp_map );
+ lua_setfield( L, -1, "dhcp" );
+
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}
diff --git a/app/modules/ws2812.c b/app/modules/ws2812.c
index b9419181..b0975201 100644
--- a/app/modules/ws2812.c
+++ b/app/modules/ws2812.c
@@ -3,6 +3,8 @@
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
+#include "c_stdlib.h"
+#include "c_string.h"
/**
* All this code is mostly from http://www.esp8266.com/viewtopic.php?f=21&t=1143&sid=a620a377672cfe9f666d672398415fcb
* from user Markus Gritsch.
@@ -35,7 +37,10 @@ static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
{
const uint8_t pin = luaL_checkinteger(L, 1);
size_t length;
- char *buffer = (char *)luaL_checklstring(L, 2, &length); // Cast away the constness.
+ const char *rgb = luaL_checklstring(L, 2, &length);
+ // dont modify lua-internal lstring - make a copy instead
+ char *buffer = (char *)c_malloc(length);
+ c_memcpy(buffer, rgb, length);
// Initialize the output pin:
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
@@ -59,17 +64,17 @@ static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
// Send the buffer:
os_intr_lock();
- const char * const end = buffer + length;
- while (buffer != end) {
+ for (i = 0; i < length; i++) {
uint8_t mask = 0x80;
while (mask) {
- (*buffer & mask) ? send_ws_1(pin_num[pin]) : send_ws_0(pin_num[pin]);
+ (buffer[i] & mask) ? send_ws_1(pin_num[pin]) : send_ws_0(pin_num[pin]);
mask >>= 1;
}
- ++buffer;
}
os_intr_unlock();
+ c_free(buffer);
+
return 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..1258ad6e
--- /dev/null
+++ b/app/mqtt/msg_queue.c
@@ -0,0 +1,82 @@
+#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;
+}
+
+msg_queue_t * msg_peek(msg_queue_t **head){
+ if(!head || !*head){
+ return NULL;
+ }
+ return *head; // fetch head.
+}
+
+int msg_size(msg_queue_t **head){
+ if(!head || !*head){
+ return 0;
+ }
+ int i = 1;
+ msg_queue_t *tail = *head;
+ if(tail){
+ while(tail->next!=NULL){
+ tail = tail->next;
+ i++;
+ }
+ }
+ return i;
+}
diff --git a/app/mqtt/msg_queue.h b/app/mqtt/msg_queue.h
new file mode 100644
index 00000000..05b910ae
--- /dev/null
+++ b/app/mqtt/msg_queue.h
@@ -0,0 +1,28 @@
+#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);
+msg_queue_t * msg_peek(msg_queue_t **head);
+int msg_size(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/platform/flash_fs.h b/app/platform/flash_fs.h
index 9d9da7c7..66538b90 100644
--- a/app/platform/flash_fs.h
+++ b/app/platform/flash_fs.h
@@ -71,6 +71,9 @@
#define fs_rename myspiffs_rename
#define fs_size myspiffs_size
+#define fs_mount myspiffs_mount
+#define fs_unmount myspiffs_unmount
+
#define FS_NAME_MAX_LENGTH SPIFFS_OBJ_NAME_LEN
#endif
diff --git a/app/spiffs/spiffs.c b/app/spiffs/spiffs.c
index e96e15a0..bcb11d5c 100644
--- a/app/spiffs/spiffs.c
+++ b/app/spiffs/spiffs.c
@@ -42,7 +42,7 @@ The small 4KB sectors allow for greater flexibility in applications th
********************/
-void spiffs_mount() {
+void myspiffs_mount() {
spiffs_config cfg;
cfg.phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL );
cfg.phys_addr += 0x3000;
@@ -69,6 +69,10 @@ void spiffs_mount() {
NODE_DBG("mount res: %i\n", res);
}
+void myspiffs_unmount() {
+ SPIFFS_unmount(&fs);
+}
+
// FS formatting function
// Returns 1 if OK, 0 for error
int myspiffs_format( void )
@@ -85,7 +89,7 @@ int myspiffs_format( void )
while( sect_first <= sect_last )
if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )
return 0;
- spiffs_mount();
+ myspiffs_mount();
return 1;
}
diff --git a/app/spiffs/spiffs.h b/app/spiffs/spiffs.h
index c5a2c1d2..7132b92d 100644
--- a/app/spiffs/spiffs.h
+++ b/app/spiffs/spiffs.h
@@ -477,6 +477,8 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
#if SPIFFS_CACHE
#endif
+void myspiffs_mount();
+void myspiffs_unmount();
int myspiffs_open(const char *name, int flags);
int myspiffs_close( int fd );
size_t myspiffs_write( int fd, const void* ptr, size_t len );
diff --git a/app/user/Makefile b/app/user/Makefile
index 0dd1afe6..80c303ee 100644
--- a/app/user/Makefile
+++ b/app/user/Makefile
@@ -44,6 +44,7 @@ INCLUDES += -I ../libc
INCLUDES += -I ../platform
INCLUDES += -I ../lua
INCLUDES += -I ../wofs
+INCLUDES += -I ../spiffs
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
diff --git a/app/user/user_main.c b/app/user/user_main.c
index dee11754..88938da8 100644
--- a/app/user/user_main.c
+++ b/app/user/user_main.c
@@ -14,8 +14,7 @@
#include "c_stdlib.h"
#include "c_stdio.h"
-#include "romfs.h"
-
+#include "flash_fs.h"
#include "user_interface.h"
#include "ets_sys.h"
@@ -44,7 +43,6 @@ void task_init(void){
system_os_task(task_lua, USER_TASK_PRIO_0, taskQueue, TASK_QUEUE_LEN);
}
-extern void spiffs_mount();
// extern void test_spiffs();
// extern int test_romfs();
@@ -69,7 +67,16 @@ void nodemcu_init(void)
// Flash init data at FLASHSIZE - 0x04000 Byte.
flash_init_data_default();
// Flash blank data at FLASHSIZE - 0x02000 Byte.
- flash_init_data_blank();
+ flash_init_data_blank();
+ if( !fs_format() )
+ {
+ NODE_ERR( "\ni*** ERROR ***: unable to format. FS might be compromised.\n" );
+ NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
+ }
+ else{
+ NODE_ERR( "format done.\n" );
+ }
+ fs_unmount(); // mounted by format.
}
#endif // defined(FLASH_SAFE_API)
@@ -94,7 +101,7 @@ void nodemcu_init(void)
// test_romfs();
#elif defined ( BUILD_SPIFFS )
- spiffs_mount();
+ fs_mount();
// test_spiffs();
#endif
// endpoint_setup();
diff --git a/examples/fragment.lua b/examples/fragment.lua
index 67aa2c37..11b28721 100644
--- a/examples/fragment.lua
+++ b/examples/fragment.lua
@@ -14,7 +14,7 @@ sk:connect(80,"115.239.210.27")
sk:send("GET / HTTP/1.1\r\nHost: 115.239.210.27\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
sk:connect(80,"192.168.0.66")
-sk:send("GET / HTTP/1.1\r\nHost: 1192.168.0.66\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
+sk:send("GET / HTTP/1.1\r\nHost: 192.168.0.66\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
i2c.setup(0,1,0,i2c.SLOW)
function read_bmp(addr) i2c.start(0) i2c.address(0,119,i2c.RECEIVER) c=i2c.read(0,1) i2c.stop(0) print(string.byte(c)) end
@@ -381,3 +381,141 @@ 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",0,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()
+
+m=mqtt.Client()
+m:connect("192.168.18.88",1883)
+m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end )
+m:subscribe("/topic1",0,function(m) print("sub done") end)
+m:publish("/topic1","hello3",2,0) m:publish("/topic1","hello2",2,0)
+m:publish("/topic1","hello3",0,0) m:publish("/topic1","hello2",2,0)
+
+m:subscribe("/topic2",2,function(m) print("sub done") end)
+m:publish("/topic2","hello3",0,0) m:publish("/topic2","hello2",2,0)
+
+m=mqtt.Client()
+m:on("connect",function(m)
+ print("connection "..node.heap())
+ m:subscribe("/topic1",0,function(m) print("sub done") end)
+ m:publish("/topic1","hello3",0,0) m:publish("/topic1","hello2",2,0)
+ end )
+m:on("offline", function(conn)
+ print("disconnect to broker...")
+ print(node.heap())
+end)
+m:connect("192.168.18.88",1883,0,1)
+
+-- serout( pin, firstLevel, delay_table, [repeatNum] )
+gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
+gpio.serout(1,1,{30,30,60,60,30,30}) -- serial one byte, b10110010
+gpio.serout(1,1,{30,70},8) -- serial 30% pwm 10k, lasts 8 cycles
+gpio.serout(1,1,{3,7},8) -- serial 30% pwm 100k, lasts 8 cycles
+gpio.serout(1,1,{0,0},8) -- serial 50% pwm as fast as possible, lasts 8 cycles
+
+gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
+gpio.serout(1,0,{20,10,10,20,10,10,10,100}) -- sim uart one byte 0x5A at about 100kbps
+
+gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
+
+-- Lua: mqtt.Client(clientid, keepalive, user, pass)
+-- test with cloudmqtt.com
+m_dis={}
+function dispatch(m,t,pl)
+ if pl~=nil and m_dis[t] then
+ m_dis[t](pl)
+ end
+end
+function topic1func(pl)
+ print("get1: "..pl)
+end
+function topic2func(pl)
+ print("get2: "..pl)
+end
+m_dis["/topic1"]=topic1func
+m_dis["/topic2"]=topic2func
+m=mqtt.Client("nodemcu1",60,"test","test123")
+m:on("connect",function(m)
+ print("connection "..node.heap())
+ m:subscribe("/topic1",0,function(m) print("sub done") end)
+ m:subscribe("/topic2",0,function(m) print("sub done") end)
+ m:publish("/topic1","hello",0,0) m:publish("/topic2","world",0,0)
+ end )
+m:on("offline", function(conn)
+ print("disconnect to broker...")
+ print(node.heap())
+end)
+m:on("message",dispatch )
+m:connect("m11.cloudmqtt.com",11214,0,1)
+-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) )
+
+tmr.alarm(0,10000,1,function() local pl = "time: "..tmr.time()
+ m:publish("/topic1",pl,0,0)
+ end)
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/lua_examples/make_phone_call.lua b/lua_examples/make_phone_call.lua
new file mode 100644
index 00000000..16295fdf
--- /dev/null
+++ b/lua_examples/make_phone_call.lua
@@ -0,0 +1,98 @@
+--[[
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+]]--
+
+-- Your access point's SSID and password
+local SSID = "xxxxxx"
+local SSID_PASSWORD = "xxxxxx"
+
+-- configure ESP as a station
+wifi.setmode(wifi.STATION)
+wifi.sta.config(SSID,SSID_PASSWORD)
+wifi.sta.autoconnect(1)
+
+local TWILIO_ACCOUNT_SID = "xxxxxx"
+local TWILIO_TOKEN = "xxxxxx"
+
+local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service
+ -- Please be sure to understand the security issues of using this relay app and use at your own risk.
+local URI = "/twilio/Calls.json"
+
+function build_post_request(host, uri, data_table)
+
+ local data = ""
+
+ for param,value in pairs(data_table) do
+ data = data .. param.."="..value.."&"
+ end
+
+ request = "POST "..uri.." HTTP/1.1\r\n"..
+ "Host: "..host.."\r\n"..
+ "Connection: close\r\n"..
+ "Content-Type: application/x-www-form-urlencoded\r\n"..
+ "Content-Length: "..string.len(data).."\r\n"..
+ "\r\n"..
+ data
+
+ print(request)
+
+ return request
+end
+
+local function display(sck,response)
+ print(response)
+end
+
+-- When using send_sms: the "from" number HAS to be your twilio number.
+-- If you have a free twilio account the "to" number HAS to be your twilio verified number.
+local function make_call(from,to,body)
+
+ local data = {
+ sid = TWILIO_ACCOUNT_SID,
+ token = TWILIO_TOKEN,
+ Body = string.gsub(body," ","+"),
+ From = from,
+ To = to
+ }
+
+ socket = net.createConnection(net.TCP,0)
+ socket:on("receive",display)
+ socket:connect(80,HOST)
+
+ socket:on("connection",function(sck)
+
+ local post_request = build_post_request(HOST,URI,data)
+ sck:send(post_request)
+ end)
+end
+
+function check_wifi()
+ local ip = wifi.sta.getip()
+
+ if(ip==nil) then
+ print("Connecting...")
+ else
+ tmr.stop(0)
+ print("Connected to AP!")
+ print(ip)
+ -- make a call with a voice message "your house is on fire"
+ make_call("15558976687","1334856679","Your house is on fire!")
+ end
+
+end
+
+tmr.alarm(0,2000,1,check_wifi)
diff --git a/lua_examples/mqtt/mqtt2cloud.lua b/lua_examples/mqtt/mqtt2cloud.lua
new file mode 100644
index 00000000..b6b2893a
--- /dev/null
+++ b/lua_examples/mqtt/mqtt2cloud.lua
@@ -0,0 +1,33 @@
+-- test with cloudmqtt.com
+m_dis={}
+function dispatch(m,t,pl)
+ if pl~=nil and m_dis[t] then
+ m_dis[t](m,pl)
+ end
+end
+function topic1func(m,pl)
+ print("get1: "..pl)
+end
+function topic2func(m,pl)
+ print("get2: "..pl)
+end
+m_dis["/topic1"]=topic1func
+m_dis["/topic2"]=topic2func
+-- Lua: mqtt.Client(clientid, keepalive, user, pass)
+m=mqtt.Client("nodemcu1",60,"test","test123")
+m:on("connect",function(m)
+ print("connection "..node.heap())
+ m:subscribe("/topic1",0,function(m) print("sub done") end)
+ m:subscribe("/topic2",0,function(m) print("sub done") end)
+ m:publish("/topic1","hello",0,0) m:publish("/topic2","world",0,0)
+ end )
+m:on("offline", function(conn)
+ print("disconnect to broker...")
+ print(node.heap())
+end)
+m:on("message",dispatch )
+-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) )
+m:connect("m11.cloudmqtt.com",11214,0,1)
+tmr.alarm(0,10000,1,function() local pl = "time: "..tmr.time()
+ m:publish("/topic1",pl,0,0)
+ end)
diff --git a/lua_examples/mqtt/mqtt_file.lua b/lua_examples/mqtt/mqtt_file.lua
new file mode 100644
index 00000000..b491177c
--- /dev/null
+++ b/lua_examples/mqtt/mqtt_file.lua
@@ -0,0 +1,56 @@
+-- test transfer files over mqtt.
+m_dis={}
+function dispatch(m,t,pl)
+ if pl~=nil and m_dis[t] then
+ m_dis[t](m,pl)
+ end
+end
+
+function pubfile(m,filename)
+ file.close()
+ file.open(filename)
+ repeat
+ local pl=file.read(1024)
+ if pl then m:publish("/topic2",pl,0,0) end
+ until not pl
+ file.close()
+end
+-- payload(json): {"cmd":xxx,"content":xxx}
+function topic1func(m,pl)
+ print("get1: "..pl)
+ local pack = cjson.decode(pl)
+ if pack.content then
+ if pack.cmd == "open" then file.open(pack.content,"w+")
+ elseif pack.cmd == "write" then file.write(pack.content)
+ elseif pack.cmd == "close" then file.close()
+ elseif pack.cmd == "remove" then file.remove(pack.content)
+ elseif pack.cmd == "run" then dofile(pack.content)
+ elseif pack.cmd == "read" then pubfile(m, pack.content)
+ end
+ end
+end
+
+m_dis["/topic1"]=topic1func
+-- Lua: mqtt.Client(clientid, keepalive, user, pass)
+m=mqtt.Client()
+m:on("connect",function(m)
+ print("connection "..node.heap())
+ m:subscribe("/topic1",0,function(m) print("sub done") end)
+ end )
+m:on("offline", function(conn)
+ print("disconnect to broker...")
+ print(node.heap())
+end)
+m:on("message",dispatch )
+-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) )
+m:connect(192.168.18.88,1883,0,1)
+
+-- usage:
+-- another client(pc) subscribe to /topic2, will receive the test.lua content.
+-- and publish below message to /topic1
+-- {"cmd":"open","content":"test.lua"}
+-- {"cmd":"write","content":"print([[hello world]])\n"}
+-- {"cmd":"write","content":"print(\"hello2 world2\")\n"}
+-- {"cmd":"write","content":"test.lua"}
+-- {"cmd":"run","content":"test.lua"}
+-- {"cmd":"read","content":"test.lua"}
diff --git a/lua_examples/send_text_message.lua b/lua_examples/send_text_message.lua
new file mode 100644
index 00000000..abd1908f
--- /dev/null
+++ b/lua_examples/send_text_message.lua
@@ -0,0 +1,98 @@
+--[[
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+]]--
+
+-- Your access point's SSID and password
+local SSID = "xxxxxx"
+local SSID_PASSWORD = "xxxxxx"
+
+-- configure ESP as a station
+wifi.setmode(wifi.STATION)
+wifi.sta.config(SSID,SSID_PASSWORD)
+wifi.sta.autoconnect(1)
+
+local TWILIO_ACCOUNT_SID = "xxxxxx"
+local TWILIO_TOKEN = "xxxxxx"
+
+local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service
+ -- Please be sure to understand the security issues of using this relay app and use at your own risk.
+local URI = "/twilio/Messages.json"
+
+function build_post_request(host, uri, data_table)
+
+ local data = ""
+
+ for param,value in pairs(data_table) do
+ data = data .. param.."="..value.."&"
+ end
+
+ request = "POST "..uri.." HTTP/1.1\r\n"..
+ "Host: "..host.."\r\n"..
+ "Connection: close\r\n"..
+ "Content-Type: application/x-www-form-urlencoded\r\n"..
+ "Content-Length: "..string.len(data).."\r\n"..
+ "\r\n"..
+ data
+
+ print(request)
+
+ return request
+end
+
+local function display(sck,response)
+ print(response)
+end
+
+-- When using send_sms: the "from" number HAS to be your twilio number.
+-- If you have a free twilio account the "to" number HAS to be your twilio verified number.
+local function send_sms(from,to,body)
+
+ local data = {
+ sid = TWILIO_ACCOUNT_SID,
+ token = TWILIO_TOKEN,
+ Body = string.gsub(body," ","+"),
+ From = from,
+ To = to
+ }
+
+ socket = net.createConnection(net.TCP,0)
+ socket:on("receive",display)
+ socket:connect(80,HOST)
+
+ socket:on("connection",function(sck)
+
+ local post_request = build_post_request(HOST,URI,data)
+ sck:send(post_request)
+ end)
+end
+
+function check_wifi()
+ local ip = wifi.sta.getip()
+
+ if(ip==nil) then
+ print("Connecting...")
+ else
+ tmr.stop(0)
+ print("Connected to AP!")
+ print(ip)
+ -- send a text message with the text "Hello from your esp8266"
+ send_sms("15558889944","15559998845","Hello from your ESP8266")
+ end
+
+end
+
+tmr.alarm(0,7000,1,check_wifi)
diff --git a/lua_modules/dht22/README.md b/lua_modules/dht22/README.md
deleted file mode 100644
index b68a3278..00000000
--- a/lua_modules/dht22/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# DHT22 module
-
-This module is compatible with DHT22 and DHT21.
-Supports nodemcu with or without floating point.
-No need to use a resistor to connect the pin data of DHT22 to ESP8266.
-
-## Example
-```lua
-PIN = 4 -- data pin, GPIO2
-
-dht22 = require("dht22")
-dht22.read(PIN)
-t = dht22.getTemperature()
-h = dht22.getHumidity()
-
-if h == nil then
- print("Error reading from DHT22")
-else
- -- temperature in degrees Celsius and Farenheit
- -- floating point and integer version:
- print("Temperature: "..((t-(t % 10)) / 10).."."..(t % 10).." deg C")
- -- only integer version:
- print("Temperature: "..(9 * t / 50 + 32).."."..(9 * t / 5 % 10).." deg F")
- -- only float point version:
- print("Temperature: "..(9 * t / 50 + 32).." deg F")
-
- -- humidity
- -- floating point and integer version
- print("Humidity: "..((h - (h % 10)) / 10).."."..(h % 10).."%")
-end
-
--- release module
-dht22 = nil
-package.loaded["dht22"]=nil
-```
-## Functions
-### read
-read(pin)
-Read humidity and temperature from DHT22.
-
-**Parameters:**
-
-* pin - ESP8266 pin connect to data pin in DHT22
-
-### getHumidity
-getHumidity()
-Returns the humidity of the last reading.
-
-**Returns:**
-* last humidity reading in per thousand
-
-### getTemperature
-getTemperature()
-Returns the temperature of the last reading.
-
-**Returns:**
-* last temperature reading in 0.1ºC
-
diff --git a/lua_modules/dht22/dht22.lua b/lua_modules/dht22/dht22.lua
deleted file mode 100644
index a80a1bd6..00000000
--- a/lua_modules/dht22/dht22.lua
+++ /dev/null
@@ -1,102 +0,0 @@
--- ***************************************************************************
--- DHT22 module for ESP8266 with nodeMCU
---
--- Written by Javier Yanez
--- but based on a script of Pigs Fly from ESP8266.com forum
---
--- MIT license, http://opensource.org/licenses/MIT
--- ***************************************************************************
-
-local moduleName = ...
-local M = {}
-_G[moduleName] = M
-
-local humidity
-local temperature
-
-function M.read(pin)
- local checksum
- local checksumTest
- humidity = 0
- temperature = 0
- checksum = 0
-
- -- Use Markus Gritsch trick to speed up read/write on GPIO
- local gpio_read = gpio.read
-
- local bitStream = {}
- for j = 1, 40, 1 do
- bitStream[j] = 0
- end
- local bitlength = 0
-
- -- Step 1: send out start signal to DHT22
- gpio.mode(pin, gpio.OUTPUT)
- gpio.write(pin, gpio.HIGH)
- tmr.delay(100)
- gpio.write(pin, gpio.LOW)
- tmr.delay(20000)
- gpio.write(pin, gpio.HIGH)
- gpio.mode(pin, gpio.INPUT)
-
- -- Step 2: DHT22 send response signal
- -- bus will always let up eventually, don't bother with timeout
- while (gpio_read(pin) == 0 ) do end
- local c=0
- while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
- -- bus will always let up eventually, don't bother with timeout
- while (gpio_read(pin) == 0 ) do end
- c=0
- while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
-
- -- Step 3: DHT22 send data
- for j = 1, 40, 1 do
- while (gpio_read(pin) == 1 and bitlength < 10 ) do
- bitlength = bitlength + 1
- end
- bitStream[j] = bitlength
- bitlength = 0
- -- bus will always let up eventually, don't bother with timeout
- while (gpio_read(pin) == 0) do end
- end
-
- --DHT data acquired, process.
- for i = 1, 16, 1 do
- if (bitStream[i] > 3) then
- humidity = humidity + 2 ^ (16 - i)
- end
- end
- for i = 1, 16, 1 do
- if (bitStream[i + 16] > 3) then
- temperature = temperature + 2 ^ (16 - i)
- end
- end
- for i = 1, 8, 1 do
- if (bitStream[i + 32] > 3) then
- checksum = checksum + 2 ^ (8 - i)
- end
- end
-
- checksumTest = (bit.band(humidity, 0xFF) + bit.rshift(humidity, 8) + bit.band(temperature, 0xFF) + bit.rshift(temperature, 8))
- checksumTest = bit.band(checksumTest, 0xFF)
-
- if temperature > 0x8000 then
- -- convert to negative format
- temperature = -(temperature - 0x8000)
- end
-
- -- conditions compatible con float point and integer
- if (checksumTest - checksum >= 1) or (checksum - checksumTest >= 1) then
- humidity = nil
- end
-end
-
-function M.getTemperature()
- return temperature
-end
-
-function M.getHumidity()
- return humidity
-end
-
-return M
diff --git a/lua_modules/dht_lib/README.md b/lua_modules/dht_lib/README.md
new file mode 100644
index 00000000..7b36f76c
--- /dev/null
+++ b/lua_modules/dht_lib/README.md
@@ -0,0 +1,89 @@
+# DHTxx module
+
+This module is compatible with DHT11, DHT21 and DHT22.
+And is able to auto-select wheather you are using DHT11 or DHT2x
+
+No need to use a resistor to connect the pin data of DHT22 to ESP8266.
+
+##Integer Verison[When using DHT11, Float version is useless...]
+### Example
+```lua
+PIN = 4 -- data pin, GPIO2
+
+DHT= require("dht_lib")
+
+DHT.read(PIN)
+
+t = DHT.getTemperature()
+h = DHT.getHumidity()
+
+if h == nil then
+ print("Error reading from DHTxx")
+else
+ -- temperature in degrees Celsius and Farenheit
+
+ print("Temperature: "..((t-(t % 10)) / 10).."."..(t % 10).." deg C")
+
+ print("Temperature: "..(9 * t / 50 + 32).."."..(9 * t / 5 % 10).." deg F")
+
+ -- humidity
+
+ print("Humidity: "..((h - (h % 10)) / 10).."."..(h % 10).."%")
+end
+
+-- release module
+DHT = nil
+package.loaded["dht_lib"]=nil
+```
+##Float Verison
+###Example
+```lua
+PIN = 4 -- data pin, GPIO2
+
+DHT= require("dht_lib")
+
+DHT.read(PIN)
+
+t = DHT.getTemperature()
+h = DHT.getHumidity()
+
+if h == nil then
+ print("Error reading from DHT11/22")
+else
+ -- temperature in degrees Celsius and Farenheit
+ -- floating point and integer version:
+
+ print("Temperature: "..(t/10).." deg C")
+ print("Temperature: "..(9 * t / 50 + 32).." deg F")
+
+ -- humidity
+ print("Humidity: "..(h/10).."%")
+end
+
+-- release module
+DHT = nil
+package.loaded["dht_lib"]=nil
+```
+## Functions
+
+###read
+read(pin)
+Read humidity and temperature from DHTxx(11,21,22...).
+**Parameters:**
+
+* pin - ESP8266 pin connect to data pin
+
+### getHumidity
+getHumidity()
+Returns the humidity of the last reading.
+
+**Returns:**
+* last humidity reading in per thousand
+
+### getTemperature
+getTemperature()
+Returns the temperature of the last reading.
+
+**Returns:**
+* last temperature reading in(dht22) 0.1ºC (dht11)1ºC
+*
diff --git a/lua_modules/dht_lib/dht_lib.lua b/lua_modules/dht_lib/dht_lib.lua
new file mode 100644
index 00000000..97823455
--- /dev/null
+++ b/lua_modules/dht_lib/dht_lib.lua
@@ -0,0 +1,178 @@
+-- ***************************************************************************
+-- DHTxx(11,21,22) module for ESP8266 with nodeMCU
+--
+-- Written by Javier Yanez mod by Martin
+-- but based on a script of Pigs Fly from ESP8266.com forum
+--
+-- MIT license, http://opensource.org/licenses/MIT
+-- ***************************************************************************
+
+--Support list:
+
+--DHT11 Tested
+--DHT21 Not Test yet
+--DHT22(AM2302) Tested
+--AM2320 Not Test yet
+
+--Output format-> Real temperature times 10(or DHT22 will miss it float part in Int Version)
+--==========================Module Part======================
+local moduleName = ...
+local M = {}
+_G[moduleName] = M
+--==========================Local the UMI and TEMP===========
+local humidity
+local temperature
+--==========================Local the bitStream==============
+local bitStream = {}
+
+---------------------------Read bitStream from DHTXX--------------------------
+local function read(pin)
+
+ local bitlength = 0
+ humidity = 0
+ temperature = 0
+
+ -- Use Markus Gritsch trick to speed up read/write on GPIO
+ local gpio_read = gpio.read
+
+
+ for j = 1, 40, 1 do
+ bitStream[j] = 0
+ end
+
+ -- Step 1: send out start signal to DHT22
+ gpio.mode(pin, gpio.OUTPUT)
+ gpio.write(pin, gpio.HIGH)
+ tmr.delay(100)
+ gpio.write(pin, gpio.LOW)
+ tmr.delay(20000)
+ gpio.write(pin, gpio.HIGH)
+ gpio.mode(pin, gpio.INPUT)
+
+ -- Step 2: Receive bitStream from DHT11/22
+ -- bus will always let up eventually, don't bother with timeout
+ while (gpio_read(pin) == 0 ) do end
+ local c=0
+ while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
+ -- bus will always let up eventually, don't bother with timeout
+ while (gpio_read(pin) == 0 ) do end
+ c=0
+ while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
+
+ -- Step 3: DHT22 send data
+ for j = 1, 40, 1 do
+ while (gpio_read(pin) == 1 and bitlength < 10 ) do
+ bitlength = bitlength + 1
+ end
+ bitStream[j] = bitlength
+ bitlength = 0
+ -- bus will always let up eventually, don't bother with timeout
+ while (gpio_read(pin) == 0) do end
+ end
+end
+
+---------------------------Check out the data--------------------------
+----Auto Select the DHT11/DHT22 By check the byte[1] && byte[3] -------
+---------------Which is empty when using DHT11-------------------------
+function M.read(pin)
+ read(pin)
+
+ local byte_0 = 0
+ local byte_1 = 0
+ local byte_2 = 0
+ local byte_3 = 0
+ local byte_4 = 0
+
+ for i = 1, 8, 1 do -- Byte[0]
+ if (bitStream[i] > 3) then
+ byte_0 = byte_0 + 2 ^ (8 - i)
+ end
+ end
+
+ for i = 1, 8, 1 do -- Byte[1]
+ if (bitStream[i+8] > 3) then
+ byte_1 = byte_1 + 2 ^ (8 - i)
+ end
+ end
+
+ for i = 1, 8, 1 do -- Byte[2]
+ if (bitStream[i+16] > 3) then
+ byte_2 = byte_2 + 2 ^ (8 - i)
+ end
+ end
+
+ for i = 1, 8, 1 do -- Byte[3]
+ if (bitStream[i+24] > 3) then
+ byte_2 = byte_2 + 2 ^ (8 - i)
+ end
+ end
+
+ for i = 1, 8, 1 do -- Byte[4]
+ if (bitStream[i+32] > 3) then
+ byte_4 = byte_4 + 2 ^ (8 - i)
+ end
+ end
+
+
+ if byte_1==0 and byte_3 == 0 then
+ ---------------------------Convert the bitStream into Number through DHT11's Way--------------------------
+ --As for DHT11 40Bit is consisit of 5Bytes
+ --First byte->Humidity Data's Int part
+ --Sencond byte->Humidity Data's Float Part(Which should be empty)
+ --Third byte->Temp Data;s Intpart
+ --Forth byte->Temp Data's Float Part(Which should be empty)
+ --Fifth byte->SUM Byte, Humi+Temp
+
+ if(byte_4 ~= byte_0+byte_2) then
+ humidity = nil
+ temperature = nil
+ else
+ humidity = byte_0 *10 -- In order to universe with the DHT22
+ temperature = byte_2 *10
+ end
+
+ else ---------------------------Convert the bitStream into Number through DHT22's Way--------------------------
+ --As for DHT22 40Bit is consisit of 5Bytes
+ --First byte->Humidity Data's High Bit
+ --Sencond byte->Humidity Data's Low Bit(And if over 0x8000, use complement)
+ --Third byte->Temp Data's High Bit
+ --Forth byte->Temp Data's Low Bit
+ --Fifth byte->SUM Byte
+
+ humidity = byte_0 * 256 + byte_1
+ temperature = byte_2 * 256 + byte_3
+ checksum = byte_4
+
+ checksumTest = (bit.band(humidity, 0xFF) + bit.rshift(humidity, 8) + bit.band(temperature, 0xFF) + bit.rshift(temperature, 8))
+ checksumTest = bit.band(checksumTest, 0xFF)
+
+ if temperature > 0x8000 then
+ -- convert to negative format
+ temperature = -(temperature - 0x8000)
+ end
+
+ -- conditions compatible con float point and integer
+ if (checksumTest - checksum >= 1) or (checksum - checksumTest >= 1) then
+ humidity = nil
+ end
+
+ end
+
+ byte_0 = nil
+ byte_1 = nil
+ byte_2 = nil
+ byte_3 = nil
+ byte_4 = nil
+
+end
+--------------API for geting the data out------------------
+
+function M.getTemperature()
+ return temperature
+end
+
+function M.getHumidity()
+ return humidity
+end
+-------------Return Index------------------------------------
+return M
diff --git a/lua_modules/yeelink/yeelink_lib.lua b/lua_modules/yeelink/yeelink_lib.lua
new file mode 100644
index 00000000..39f2b129
--- /dev/null
+++ b/lua_modules/yeelink/yeelink_lib.lua
@@ -0,0 +1,105 @@
+
+-- ***************************************************************************
+-- Yeelink Updata Libiary
+--
+-- Written by Martin
+-- but based on a script of zhouxu_o from bbs.nodemcu.com
+--
+-- MIT license, http://opensource.org/licenses/MIT
+-- ***************************************************************************
+
+if wifi.sta.getip() == nil then
+ print("Please Connect WIFI First")
+ return nil
+end
+--==========================Module Part======================
+
+local moduleName = ...
+local M = {}
+_G[moduleName] = M
+--=========================Local Args=======================
+local dns = "0.0.0.0"
+
+local device = ""
+local sensor = ""
+local apikey = ""
+
+--================================
+local debug = true --<<<<<<<<<<<<< Don't forget to "false" it before using
+--================================
+local sk=net.createConnection(net.TCP, 0)
+
+local datapoint = 0
+--====DNS the yeelink ip advance(in order to save RAM)=====
+sk:dns("api.yeelink.net",function(conn,ip)
+
+dns=ip
+
+print("DNS YEELINK OK... IP: "..dns)
+
+end)
+
+--========Set the init function===========
+--device->number
+--sensor->number
+-- apikey must be -> string <-
+-- e.g. xxx.init(00000,00000,"123j12b3jkb12k4b23bv54i2b5b3o4")
+--========================================
+function M.init(_device, _sensor, _apikey)
+ device = tostring(_device)
+ sensor = tostring(_sensor)
+ apikey = _apikey
+ if dns == "0.0.0.0" then
+ return false
+ else
+ return dns
+ end
+
+end
+
+
+--=====Update to Yeelink Sever(At least 10s per sencods))=====
+-- datapoint->number
+--
+--e.g. xxx.update(233.333)
+--============================================================
+function M.update(_datapoint)
+
+ datapoint = tostring(_datapoint)
+
+ sk:on("connection", function(conn)
+
+ print("connect OK...")
+
+
+ local a=[[{"value":]]
+ local b=[[}]]
+
+ local st=a..datapoint..b
+
+ sk:send("POST /v1.0/device/"..device.."/sensor/"..sensor.."/datapoints HTTP/1.1\r\n"
+.."Host: www.yeelink.net\r\n"
+.."Content-Length: "..string.len(st).."\r\n"--the length of json is important
+.."Content-Type: application/x-www-form-urlencoded\r\n"
+.."U-ApiKey:"..apikey.."\r\n"
+.."Cache-Control: no-cache\r\n\r\n"
+..st.."\r\n" )
+
+ end)
+
+ sk:on("receive", function(sck, content)
+
+ if debug then
+ print("\r\n"..content.."\r\n")
+ else
+ print("Date Receive")
+ end
+
+ end)
+
+ sk:connect(80,dns)
+
+
+end
+--================end==========================
+return M
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()