From 52ca40b8ea1ddcb67ffd2a2d9bedeb500c6c641e Mon Sep 17 00:00:00 2001 From: funshine Date: Sun, 22 Mar 2015 21:09:37 +0800 Subject: [PATCH 01/25] add init.lua examples --- app/platform/flash_api.c | 4 ++-- examples/init.lua | 18 ++++++++++++++++++ examples/user.lua | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 examples/init.lua create mode 100644 examples/user.lua diff --git a/app/platform/flash_api.c b/app/platform/flash_api.c index a648d91b..97c6f20c 100644 --- a/app/platform/flash_api.c +++ b/app/platform/flash_api.c @@ -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/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") From 1c267dfac7c5fc406929df63799280646095e93c Mon Sep 17 00:00:00 2001 From: AllAboutEE Date: Mon, 23 Mar 2015 21:57:54 -0500 Subject: [PATCH 02/25] Added phone calls and sms example. --- lua_examples/make_phone_call.lua | 98 ++++++++++++++++++++++++++++++ lua_examples/send_text_message.lua | 98 ++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 lua_examples/make_phone_call.lua create mode 100644 lua_examples/send_text_message.lua 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/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) From e1f8b604a09410823f6129dd43e4e8a80963eca1 Mon Sep 17 00:00:00 2001 From: funshine Date: Tue, 24 Mar 2015 23:21:40 +0800 Subject: [PATCH 03/25] fix init_data detect flash api --- app/platform/flash_api.c | 2 +- examples/fragment.lua | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/platform/flash_api.c b/app/platform/flash_api.c index 97c6f20c..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) diff --git a/examples/fragment.lua b/examples/fragment.lua index 67aa2c37..d3d0f7da 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -381,3 +381,18 @@ 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) \ No newline at end of file From f4223f0bf289c1e648ac159a29dd37e96655ef04 Mon Sep 17 00:00:00 2001 From: HuangRui Date: Wed, 25 Mar 2015 10:37:25 +0800 Subject: [PATCH 04/25] Update esptool.py supported NodeMCU devkit automatic flash. --- tools/esptool.py | 162 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 17 deletions(-) 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() From 3dd1ac37390371272210c3d9a48b4ba995aa94b7 Mon Sep 17 00:00:00 2001 From: HuangRui Date: Fri, 27 Mar 2015 00:52:55 +0800 Subject: [PATCH 05/25] Move node.readvdd33 to adc.readvdd33, fix #162. --- app/modules/adc.c | 22 ++++++++++++++++++++++ app/modules/node.c | 17 ++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) 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/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 ) }, From f5a7448d3974fe039f6a26c6e6f97f5696fc99da Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Mar 2015 20:48:09 +0100 Subject: [PATCH 06/25] corr typo wrong ip in example --- examples/fragment.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fragment.lua b/examples/fragment.lua index 67aa2c37..fc426326 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 From 09750b5653a9a5ffb434f46f44b1b6fdbc66c106 Mon Sep 17 00:00:00 2001 From: funshine Date: Mon, 30 Mar 2015 00:24:09 +0800 Subject: [PATCH 07/25] add queue to mqtt module --- app/cjson/strbuf.c | 4 +- app/include/user_version.h | 2 +- app/libc/c_stdio.h | 6 +- app/libc/c_stdlib.h | 12 +- app/modules/mqtt.c | 541 +++++++++++++++++++++---------------- app/mqtt/mqtt_msg.c | 26 +- app/mqtt/msg_queue.c | 60 ++++ app/mqtt/msg_queue.h | 26 ++ examples/fragment.lua | 32 ++- ld/eagle.app.v6.ld | 2 +- 10 files changed, 458 insertions(+), 253 deletions(-) create mode 100644 app/mqtt/msg_queue.c create mode 100644 app/mqtt/msg_queue.h 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..89a63fc3 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 20150330" #endif /* __USER_VERSION_H__ */ diff --git a/app/libc/c_stdio.h b/app/libc/c_stdio.h index 88c368f6..c652f0bf 100644 --- a/app/libc/c_stdio.h +++ b/app/libc/c_stdio.h @@ -47,9 +47,9 @@ extern int c_stderr; #define SEEK_END 2 /* set file offset to EOF plus offset */ #endif -#define c_malloc os_malloc -#define c_zalloc os_zalloc -#define c_free os_free +// #define c_malloc os_malloc +// #define c_zalloc os_zalloc +// #define c_free os_free extern void output_redirect(const char *str); #define c_puts output_redirect diff --git a/app/libc/c_stdlib.h b/app/libc/c_stdlib.h index 3757c135..f0a6f265 100644 --- a/app/libc/c_stdlib.h +++ b/app/libc/c_stdlib.h @@ -29,9 +29,9 @@ #define os_realloc(p, s) mem_realloc((p), (s)) #endif -// #define c_free os_free -// #define c_malloc os_malloc -// #define c_zalloc os_zalloc +#define c_free os_free +#define c_malloc os_malloc +#define c_zalloc os_zalloc #define c_realloc os_realloc #define c_abs abs @@ -47,9 +47,9 @@ // c_getenv() get env "LUA_INIT" string for lua initialization. const char *c_getenv(const char *__string); -void *c_malloc(size_t __size); -void *c_zalloc(size_t __size); -void c_free(void *); +// void *c_malloc(size_t __size); +// void *c_zalloc(size_t __size); +// void c_free(void *); // int c_rand(void); // void c_srand(unsigned int __seed); diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index 018e034e..db9990c5 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -15,6 +15,7 @@ #include "espconn.h" #include "mqtt_msg.h" +#include "msg_queue.h" static lua_State *gL = NULL; @@ -27,7 +28,7 @@ static lua_State *gL = NULL; typedef enum { MQTT_INIT, - MQTT_CONNECT_SEND, + MQTT_CONNECT_SENT, MQTT_CONNECT_SENDING, MQTT_DATA } tConnState; @@ -55,10 +56,7 @@ typedef struct mqtt_state_t uint16_t message_length_read; mqtt_message_t* outbound_message; mqtt_connection_t mqtt_connection; - - uint16_t pending_msg_id; - int pending_msg_type; - int pending_publish_qos; + msg_queue_t* pending_msg_q; } mqtt_state_t; typedef struct lmqtt_userdata @@ -75,7 +73,7 @@ typedef struct lmqtt_userdata uint32_t keep_alive_tick; uint32_t send_timeout; uint8_t secure; - uint8_t connected; + bool connected; // indicate socket connected, not mqtt prot connected. ETSTimer mqttTimer; tConnState connState; }lmqtt_userdata; @@ -89,27 +87,35 @@ static void mqtt_socket_disconnected(void *arg) // tcp only 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); + + if(mud->connected){ + mud->connected = false; + if(mud->pesp_conn && mud->pesp_conn->proto.tcp) + c_free(mud->pesp_conn->proto.tcp); + mud->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){ // TODO: should we unref the client and delete it? + luaL_unref(gL, LUA_REGISTRYINDEX, mud->self_ref); + mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self + } + lua_gc(gL, LUA_GCRESTART, 0); } - mud->connected = 0; + + mud->connected = false; 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->cb_disconnect_ref != LUA_NOREF) + { + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_disconnect_ref); + if( mud->self_ref != LUA_NOREF) + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua + else + lua_pushnil(gL); + lua_call(gL, 1, 0); } - lua_gc(gL, LUA_GCRESTART, 0); } static void mqtt_socket_reconnected(void *arg, sint8_t err) @@ -135,10 +141,7 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) return; lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_message_ref); lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua - // expose_array(gL, pdata, len); - // *(pdata+len) = 0; - // NODE_DBG(pdata); - // NODE_DBG("\n"); + lua_pushlstring(gL, event_data.topic, event_data.topic_length); if(event_data.data_length > 0){ lua_pushlstring(gL, event_data.data, event_data.data_length); @@ -155,6 +158,7 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) uint8_t msg_type; uint8_t msg_qos; uint16_t msg_id; + msg_queue_t *node = NULL; struct espconn *pesp_conn = arg; if(pesp_conn == NULL) @@ -171,6 +175,7 @@ READPACKET: mud->mqtt_state.outbound_message = NULL; switch(mud->connState){ case MQTT_CONNECT_SENDING: + case MQTT_CONNECT_SENT: if(mqtt_get_type(mud->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK){ NODE_DBG("MQTT: Invalid packet\r\n"); mud->connState = MQTT_INIT; @@ -201,39 +206,54 @@ READPACKET: msg_qos = mqtt_get_qos(mud->mqtt_state.in_buffer); msg_id = mqtt_get_id(mud->mqtt_state.in_buffer, mud->mqtt_state.in_buffer_length); + msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; + NODE_DBG("MQTT_DATA: type: %d, qos: %d, msg_id: %d, pending_id: %d\r\n", msg_type, msg_qos, msg_id, - mud->mqtt_state.pending_msg_id); + (pending_msg)?pending_msg->msg_id:0); switch(msg_type) { case MQTT_MSG_TYPE_SUBACK: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && mud->mqtt_state.pending_msg_id == msg_id) + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Subscribe successful\r\n"); - if (mud->cb_suback_ref == LUA_NOREF) - break; - if (mud->self_ref == LUA_NOREF) - break; - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_suback_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); - lua_call(gL, 1, 0); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); + if (mud->cb_suback_ref == LUA_NOREF) + break; + if (mud->self_ref == LUA_NOREF) + break; + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_suback_ref); + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); + lua_call(gL, 1, 0); + } break; case MQTT_MSG_TYPE_UNSUBACK: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && mud->mqtt_state.pending_msg_id == msg_id) + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: UnSubscribe successful\r\n"); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); + } break; case MQTT_MSG_TYPE_PUBLISH: - if(msg_qos == 1) + if(msg_qos == 1){ mud->mqtt_state.outbound_message = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id); - else if(msg_qos == 2) + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBACK, (int)msg_qos ); + } + else if(msg_qos == 2){ mud->mqtt_state.outbound_message = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id); - + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBREC, (int)msg_qos ); + } + if(msg_qos == 1 || msg_qos == 2){ + NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos); + } deliver_publish(mud, mud->mqtt_state.in_buffer, mud->mqtt_state.message_length_read); break; case MQTT_MSG_TYPE_PUBACK: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && mud->mqtt_state.pending_msg_id == msg_id){ + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Publish with QoS = 1 successful\r\n"); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) @@ -246,15 +266,20 @@ READPACKET: break; case MQTT_MSG_TYPE_PUBREC: mud->mqtt_state.outbound_message = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id); + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBREL, (int)msg_qos ); NODE_DBG("MQTT: Response PUBREL\r\n"); break; case MQTT_MSG_TYPE_PUBREL: mud->mqtt_state.outbound_message = mqtt_msg_pubcomp(&mud->mqtt_state.mqtt_connection, msg_id); + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBCOMP, (int)msg_qos ); NODE_DBG("MQTT: Response PUBCOMP\r\n"); break; case MQTT_MSG_TYPE_PUBCOMP: - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && mud->mqtt_state.pending_msg_id == msg_id){ + if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){ NODE_DBG("MQTT: Publish with QoS = 2 successful\r\n"); + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) break; if(mud->self_ref == LUA_NOREF) @@ -266,9 +291,13 @@ READPACKET: break; case MQTT_MSG_TYPE_PINGREQ: mud->mqtt_state.outbound_message = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection); + node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PINGRESP, (int)msg_qos ); + NODE_DBG("MQTT: Response PINGRESP\r\n"); break; case MQTT_MSG_TYPE_PINGRESP: // Ignore + NODE_DBG("MQTT: PINGRESP received\r\n"); break; } // NOTE: this is done down here and not in the switch case above @@ -291,13 +320,17 @@ READPACKET: break; } - if(mud->mqtt_state.outbound_message != NULL){ - if(mud->secure) - espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->send_timeout == 0){ + mud->send_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("Sent: %d\n", node->msg.length); + if( mud->secure ) + espconn_secure_sent( pesp_conn, node->msg.data, node->msg.length ); else - espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + espconn_sent( pesp_conn, node->msg.data, node->msg.length ); + mud->keep_alive_tick = 0; mud->mqtt_state.outbound_message = NULL; } + return; } @@ -311,10 +344,18 @@ static void mqtt_socket_sent(void *arg) if(mud == NULL) return; if(!mud->connected) - return; + return; + if(mud->connState == MQTT_CONNECT_SENDING){ + mud->connState = MQTT_CONNECT_SENT; + } + // call mqtt_sent() mud->send_timeout = 0; - if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && mud->mqtt_state.pending_publish_qos == 0) { + + // qos = 0, publish and forgot. + msg_queue_t *node = mud->mqtt_state.pending_msg_q; + if(node && node->msg_type == MQTT_MSG_TYPE_PUBLISH && node->publish_qos == 0) { + msg_destroy(msg_dequeue(&(mud->mqtt_state.pending_msg_q))); if(mud->cb_puback_ref == LUA_NOREF) return; if(mud->self_ref == LUA_NOREF) @@ -360,14 +401,48 @@ void mqtt_socket_timer(void *arg) { lmqtt_userdata *mud = (lmqtt_userdata*) arg; + if(mud == NULL) + return; + if(mud->send_timeout > 0){ + mud->send_timeout --; + } + + if(mud->pesp_conn == NULL){ + NODE_DBG("mud->pesp_conn is NULL.\n"); + return; + } + + if(mud->send_timeout == 0){ // switch to next queued event. + if(mud->connState == MQTT_CONNECT_SENDING){ // MQTT_CONNECT time out. + mud->connState = MQTT_INIT; + if(mud->secure){ + espconn_secure_disconnect(mud->pesp_conn); + } + else { + espconn_disconnect(mud->pesp_conn); + } + mud->keep_alive_tick = 0; // not need count anymore + } else if(mud->connState == MQTT_DATA){ + msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; + if(pending_msg){ + mud->send_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); + } + // no queued event. + } + } + if(mud->connState == MQTT_DATA){ mud->keep_alive_tick ++; if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ - mud->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ; mud->send_timeout = MQTT_SEND_TIMEOUT; NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); mud->mqtt_state.outbound_message = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); - if(mud->secure) espconn_secure_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); else @@ -375,8 +450,6 @@ void mqtt_socket_timer(void *arg) mud->keep_alive_tick = 0; } } - if(mud->send_timeout > 0) - mud->send_timeout --; } // Lua: mqtt.Client(clientid, keepalive, user, pass) @@ -389,8 +462,11 @@ static int mqtt_socket_client( lua_State* L ) 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); @@ -419,87 +495,89 @@ static int mqtt_socket_client( lua_State* L ) luaL_getmetatable(L, "mqtt.socket"); lua_setmetatable(L, -2); + gL = L; // global L for mqtt module. + if( lua_isstring(L,stack) ) // deal with the clientid string { - clientId = luaL_checklstring( L, stack, &il ); + clientId = luaL_checklstring( L, stack, &idl ); stack++; } - // TODO: check the zalloc result. - mud->connect_info.client_id = (uint8_t *)c_zalloc(il+1); - if(!mud->connect_info.client_id){ - return luaL_error(L, "not enough memory"); - } - c_memcpy(mud->connect_info.client_id, clientId, il); - mud->connect_info.client_id[il] = 0; - - mud->mqtt_state.in_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); - if(!mud->mqtt_state.in_buffer){ - return luaL_error(L, "not enough memory"); - } - - mud->mqtt_state.out_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); - if(!mud->mqtt_state.out_buffer){ - return luaL_error(L, "not enough memory"); - } - - mud->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; - mud->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; - - mud->connState = MQTT_INIT; - mud->connect_info.clean_session = 1; - mud->connect_info.will_qos = 0; - mud->connect_info.will_retain = 0; - mud->keep_alive_tick = 0; - mud->connect_info.keepalive = 0; - mud->mqtt_state.connect_info = &mud->connect_info; - - gL = L; // global L for mqtt module. - if(lua_isnumber( L, stack )) { - mud->connect_info.keepalive = luaL_checkinteger( L, stack); + keepalive = luaL_checkinteger( L, stack); stack++; } - if(mud->connect_info.keepalive == 0){ - mud->connect_info.keepalive = MQTT_DEFAULT_KEEPALIVE; - return 1; + if(keepalive == 0){ + keepalive = MQTT_DEFAULT_KEEPALIVE; } if(lua_isstring( L, stack )){ - username = luaL_checklstring( L, stack, &il ); + username = luaL_checklstring( L, stack, &unl ); stack++; } if(username == NULL) - il = 0; - NODE_DBG("lengh username: %d\r\n", il); - mud->connect_info.username = (uint8_t *)c_zalloc(il + 1); - if(!mud->connect_info.username){ - return luaL_error(L, "not enough memory"); - } + unl = 0; + NODE_DBG("lengh username: %d\r\n", unl); - c_memcpy(mud->connect_info.username, username, il); - mud->connect_info.username[il] = 0; - if(lua_isstring( L, stack )){ - password = luaL_checklstring( L, stack, &il ); + password = luaL_checklstring( L, stack, &pwl ); stack++; } if(password == NULL) - il = 0; - NODE_DBG("lengh password: %d\r\n", il); + pwl = 0; + NODE_DBG("lengh password: %d\r\n", pwl); - mud->connect_info.password = (uint8_t *)c_zalloc(il + 1); - if(!mud->connect_info.password){ - return luaL_error(L, "not enough memory"); - } + // TODO: check the zalloc result. + mud->connect_info.client_id = (uint8_t *)c_zalloc(idl+1); + mud->connect_info.username = (uint8_t *)c_zalloc(unl + 1); + mud->connect_info.password = (uint8_t *)c_zalloc(pwl + 1); + mud->mqtt_state.in_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); + mud->mqtt_state.out_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); + if(!mud->connect_info.client_id || !mud->connect_info.username || !mud->connect_info.password || !mud->mqtt_state.in_buffer || !mud->mqtt_state.out_buffer){ + if(mud->connect_info.client_id) { + c_free(mud->connect_info.client_id); + mud->connect_info.client_id = NULL; + } + if(mud->connect_info.username) { + c_free(mud->connect_info.username); + mud->connect_info.username = NULL; + } + if(mud->connect_info.password) { + c_free(mud->connect_info.password); + mud->connect_info.password = NULL; + } + if(mud->mqtt_state.in_buffer) { + c_free(mud->mqtt_state.in_buffer); + mud->mqtt_state.in_buffer = NULL; + } + if(mud->mqtt_state.out_buffer) { + c_free(mud->mqtt_state.out_buffer); + mud->mqtt_state.out_buffer = NULL; + } + return luaL_error(L, "not enough memory"); + } - c_memcpy(mud->connect_info.password, password, il); - mud->connect_info.password[il] = 0; + c_memcpy(mud->connect_info.client_id, clientId, idl); + mud->connect_info.client_id[idl] = 0; + c_memcpy(mud->connect_info.username, username, unl); + mud->connect_info.username[unl] = 0; + c_memcpy(mud->connect_info.password, password, pwl); + mud->connect_info.password[pwl] = 0; NODE_DBG("MQTT: Init info: %s, %s, %s\r\n", mud->connect_info.client_id, mud->connect_info.username, mud->connect_info.password); + mud->connect_info.clean_session = 1; + mud->connect_info.will_qos = 0; + mud->connect_info.will_retain = 0; + mud->connect_info.keepalive = keepalive; + + mud->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; + mud->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; + mud->mqtt_state.pending_msg_q = NULL; + mud->mqtt_state.connect_info = &mud->connect_info; + return 1; } @@ -518,7 +596,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 +608,19 @@ static int mqtt_delete( lua_State* L ) mud->pesp_conn = NULL; // for socket, it will free this when disconnected } + // ---- alloc-ed in mqtt_socket_lwt() if(mud->connect_info.will_topic){ c_free(mud->connect_info.will_topic); mud->connect_info.will_topic = NULL; } if(mud->connect_info.will_message){ - c_free(mud->connect_info.will_message); - mud->connect_info.will_message = NULL; - } + c_free(mud->connect_info.will_message); + mud->connect_info.will_message = NULL; + } + // ---- + //--------- alloc-ed in mqtt_socket_client() if(mud->connect_info.client_id){ c_free(mud->connect_info.client_id); mud->connect_info.client_id = NULL; @@ -558,6 +641,7 @@ static int mqtt_delete( lua_State* L ) c_free(mud->mqtt_state.out_buffer); mud->mqtt_state.out_buffer = NULL; } + // ------- // free (unref) callback ref if(LUA_NOREF!=mud->cb_connect_ref){ @@ -647,11 +731,11 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) } } -// Lua: mqtt:connect( host, port, secure, function(client) ) +// Lua: mqtt:lwt( topic, message, qos, retain, function(client) ) static int mqtt_socket_lwt( lua_State* L ) { uint8_t stack = 1; - size_t topicSize, il; + size_t topicSize, msgSize; NODE_DBG("mqtt_socket_lwt.\n"); lmqtt_userdata *mud = NULL; const char *lwtTopic, *lwtMsg; @@ -671,32 +755,40 @@ static int mqtt_socket_lwt( lua_State* L ) } stack++; - lwtMsg = luaL_checklstring( L, stack, &il ); + lwtMsg = luaL_checklstring( L, stack, &msgSize ); 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){ + 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; - 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 ); + 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, @@ -750,7 +842,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 { @@ -822,7 +914,6 @@ static int mqtt_socket_connect( lua_State* L ) 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); - return 0; } @@ -897,16 +988,12 @@ static int mqtt_socket_on( lua_State* L ) 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; uint8_t stack = 1, qos = 0; + uint16_t msg_id = 0; const char *topic; size_t il; lmqtt_userdata *mud; @@ -915,97 +1002,92 @@ static int mqtt_socket_subscribe( lua_State* L ) { luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); stack++; - if( mud->send_timeout != 0 ) - return luaL_error( L, "sending in process" ); - - if( !mud->connected ) - return luaL_error( L, "not connected" ); + if(!mud->connected){ + luaL_error( L, "not connected" ); + lua_pushboolean(L, 0); + return 1; + } if( lua_istable( L, stack ) ) { NODE_DBG("subscribe table\n"); lua_pushnil( L ); /* first key */ - SUB_STORAGE *first, *last, *curr; - first = (SUB_STORAGE*) c_zalloc(sizeof(SUB_STORAGE)); - if( first == NULL ) - return luaL_error( L, "not enough memory" ); - first->length = 0; - last = first; - first->next = NULL; - while( lua_next( L, stack ) != 0 ) { - curr = (SUB_STORAGE*) c_zalloc(sizeof(SUB_STORAGE)); - if( curr == NULL ) - return luaL_error( L, "not enough memory" ); + uint8_t temp_buffer[MQTT_BUF_SIZE]; + uint32_t temp_pos = 0; + + while( lua_next( L, stack ) != 0 ) { topic = luaL_checkstring( L, -2 ); qos = luaL_checkinteger( L, -1 ); - mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &mud->mqtt_state.pending_msg_id ); + mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); NODE_DBG("topic: %s - qos: %d, length: %d\n", topic, qos, mud->mqtt_state.outbound_message->length); - curr->data = (uint8_t*) c_zalloc(mud->mqtt_state.outbound_message->length); - if( curr->data == NULL ) - return luaL_error( L, "not enough memory" ); - c_memcpy( curr->data, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); - curr->length = mud->mqtt_state.outbound_message->length; - curr->next = NULL; - last->next = curr; - last = curr; + if (temp_pos + mud->mqtt_state.outbound_message->length > MQTT_BUF_SIZE){ + lua_pop(L, 1); + break; // too long message for the outbuffer. + } + c_memcpy( temp_buffer + temp_pos, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); + temp_pos += mud->mqtt_state.outbound_message->length; + lua_pop( L, 1 ); } - curr = first; - uint32_t ptr = 0; - while( curr != NULL ) { - if( curr->length == 0 ) { - curr = curr->next; - continue; - } - if( ptr + curr->length < mud->mqtt_state.out_buffer_length ) { - c_memcpy( mud->mqtt_state.out_buffer + ptr, curr->data, curr->length ); - ptr += curr->length; - } - c_free(curr->data); - c_free(curr); - curr = curr->next; - } - c_free(first); - if( ptr == 0 ) { - return luaL_error( L, "invalid data" ); - } + if (temp_pos == 0){ + luaL_error( L, "invalid data" ); + lua_pushboolean(L, 0); + return 1; + } + + c_memcpy( mud->mqtt_state.out_buffer, temp_buffer, temp_pos ); mud->mqtt_state.outbound_message->data = mud->mqtt_state.out_buffer; - mud->mqtt_state.outbound_message->length = ptr; + mud->mqtt_state.outbound_message->length = temp_pos; stack++; } else { NODE_DBG("subscribe string\n"); topic = luaL_checklstring( L, stack, &il ); stack++; - if( topic == NULL ) - return luaL_error( L, "need topic name" ); + if( topic == NULL ){ + luaL_error( L, "need topic name" ); + lua_pushboolean(L, 0); + return 1; + } qos = luaL_checkinteger( L, stack ); - mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &mud->mqtt_state.pending_msg_id ); + mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); stack++; } - mud->send_timeout = MQTT_SEND_TIMEOUT; - mud->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_SUBSCRIBE; - mud->mqtt_state.pending_publish_qos = mqtt_get_qos( mud->mqtt_state.outbound_message->data ); + if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { // TODO: this will overwrite the previous one. + lua_pushvalue( L, stack ); // copy argument (func) to the top of stack + if( mud->cb_suback_ref != LUA_NOREF ) + luaL_unref( L, LUA_REGISTRYINDEX, mud->cb_suback_ref ); + mud->cb_suback_ref = luaL_ref( L, LUA_REGISTRYINDEX ); + } - if( lua_type( L, stack ) == LUA_TFUNCTION || lua_type( L, stack ) == LUA_TLIGHTFUNCTION ) { - lua_pushvalue( L, stack ); // copy argument (func) to the top of stack - if( mud->cb_suback_ref != LUA_NOREF ) - luaL_unref( L, LUA_REGISTRYINDEX, mud->cb_suback_ref ); - mud->cb_suback_ref = luaL_ref( L, LUA_REGISTRYINDEX ); - } - NODE_DBG("Sent: %d\n", mud->mqtt_state.outbound_message->length); - if( mud->secure ) - espconn_secure_sent( mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); - else - espconn_sent( mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); + msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_SUBSCRIBE, (int)mqtt_get_qos(mud->mqtt_state.outbound_message->data) ); - return 0; + NODE_DBG("topic: %s - id: %d - qos: %d, length: %d\n", topic, node->msg_id, node->publish_qos, node->msg.length); + + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->send_timeout == 0){ + mud->send_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("Sent: %d\n", node->msg.length); + if( mud->secure ) + espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + else + espconn_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + mud->keep_alive_tick = 0; + } + + if(!node){ + lua_pushboolean(L, 0); + } else { + lua_pushboolean(L, 1); // enqueued succeed. + } + mud->mqtt_state.outbound_message = NULL; + 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"); @@ -1013,35 +1095,31 @@ static int mqtt_socket_publish( lua_State* L ) lmqtt_userdata *mud; size_t l; uint8_t stack = 1; + uint16_t msg_id = 0; mud = (lmqtt_userdata *)luaL_checkudata(L, stack, "mqtt.socket"); luaL_argcheck(L, mud, stack, "mqtt.socket expected"); stack++; if(mud==NULL){ NODE_DBG("userdata is nil.\n"); - return 0; + lua_pushboolean(L, 0); + return 1; } if(mud->pesp_conn == NULL){ NODE_DBG("mud->pesp_conn is NULL.\n"); - return 0; + lua_pushboolean(L, 0); + return 1; } - if(mud->send_timeout != 0) - return luaL_error( L, "sending in process" ); + pesp_conn = mud->pesp_conn; -#if 0 - char temp[20] = {0}; - c_sprintf(temp, IPSTR, IP2STR( &(pesp_conn->proto.tcp->remote_ip) ) ); - NODE_DBG("remote "); - NODE_DBG(temp); - NODE_DBG(":"); - NODE_DBG("%d",pesp_conn->proto.tcp->remote_port); - NODE_DBG(" sending data.\n"); -#endif const char *topic = luaL_checklstring( L, stack, &l ); stack ++; - if (topic == NULL) - return luaL_error( L, "need topic" ); + if (topic == NULL){ + luaL_error( L, "need topic" ); + lua_pushboolean(L, 0); + return 1; + } const char *payload = luaL_checklstring( L, stack, &l ); stack ++; @@ -1050,14 +1128,11 @@ static int mqtt_socket_publish( lua_State* L ) uint8_t retain = luaL_checkinteger( L, stack); stack ++; - mud->mqtt_state.outbound_message = mqtt_msg_publish(&mud->mqtt_state.mqtt_connection, topic, payload, l, qos, retain, - &mud->mqtt_state.pending_msg_id); - mud->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PUBLISH; - mud->mqtt_state.pending_publish_qos = qos; - mud->send_timeout = MQTT_SEND_TIMEOUT; + &msg_id); + if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack if(mud->cb_puback_ref != LUA_NOREF) @@ -1065,12 +1140,26 @@ static int mqtt_socket_publish( lua_State* L ) mud->cb_puback_ref = luaL_ref(L, LUA_REGISTRYINDEX); } - if(mud->secure) - espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - else - espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + msg_queue_t *node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + msg_id, MQTT_MSG_TYPE_PUBLISH, (int)qos ); + + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->send_timeout == 0){ + mud->send_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("Sent: %d\n", node->msg.length); + if( mud->secure ) + espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + else + espconn_sent( mud->pesp_conn, node->msg.data, node->msg.length ); + mud->keep_alive_tick = 0; + } + + if(!node){ + lua_pushboolean(L, 0); + } else { + lua_pushboolean(L, 1); // enqueued succeed. + } mud->mqtt_state.outbound_message = NULL; - return 0; + return 1; } // Module function map diff --git a/app/mqtt/mqtt_msg.c b/app/mqtt/mqtt_msg.c index a58f6057..9c405a7c 100644 --- a/app/mqtt/mqtt_msg.c +++ b/app/mqtt/mqtt_msg.c @@ -29,7 +29,7 @@ * */ -#include +#include "c_string.h" #include "mqtt_msg.h" #define MQTT_MAX_FIXED_HEADER_SIZE 3 @@ -61,7 +61,7 @@ static int append_string(mqtt_connection_t* connection, const char* string, int connection->buffer[connection->message.length++] = len >> 8; connection->buffer[connection->message.length++] = len & 0xff; - memcpy(connection->buffer + connection->message.length, string, len); + c_memcpy(connection->buffer + connection->message.length, string, len); connection->message.length += len; return len + 2; @@ -121,7 +121,7 @@ static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) { - memset(connection, 0, sizeof(connection)); + c_memset(connection, 0, sizeof(connection)); connection->buffer = buffer; connection->buffer_length = buffer_length; } @@ -294,7 +294,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf variable_header->lengthMsb = 0; variable_header->lengthLsb = 4; - memcpy(variable_header->magic, "MQTT", 4); + c_memcpy(variable_header->magic, "MQTT", 4); variable_header->version = 4; variable_header->flags = 0; variable_header->keepaliveMsb = info->keepalive >> 8; @@ -305,7 +305,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->client_id != NULL && info->client_id[0] != '\0') { - if(append_string(connection, info->client_id, strlen(info->client_id)) < 0) + if(append_string(connection, info->client_id, c_strlen(info->client_id)) < 0) return fail_message(connection); } else @@ -313,10 +313,10 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->will_topic != NULL && info->will_topic[0] != '\0') { - if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0) + if(append_string(connection, info->will_topic, c_strlen(info->will_topic)) < 0) return fail_message(connection); - if(append_string(connection, info->will_message, strlen(info->will_message)) < 0) + if(append_string(connection, info->will_message, c_strlen(info->will_message)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_WILL; @@ -327,7 +327,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->username != NULL && info->username[0] != '\0') { - if(append_string(connection, info->username, strlen(info->username)) < 0) + if(append_string(connection, info->username, c_strlen(info->username)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; @@ -335,7 +335,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf if(info->password != NULL && info->password[0] != '\0') { - if(append_string(connection, info->password, strlen(info->password)) < 0) + if(append_string(connection, info->password, c_strlen(info->password)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; @@ -351,7 +351,7 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi if(topic == NULL || topic[0] == '\0') return fail_message(connection); - if(append_string(connection, topic, strlen(topic)) < 0) + if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); if(qos > 0) @@ -364,7 +364,7 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi if(connection->message.length + data_length > connection->buffer_length) return fail_message(connection); - memcpy(connection->buffer + connection->message.length, data, data_length); + c_memcpy(connection->buffer + connection->message.length, data, data_length); connection->message.length += data_length; return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); @@ -412,7 +412,7 @@ mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* to if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); - if(append_string(connection, topic, strlen(topic)) < 0) + if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); if(connection->message.length + 1 > connection->buffer_length) @@ -432,7 +432,7 @@ mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); - if(append_string(connection, topic, strlen(topic)) < 0) + if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); diff --git a/app/mqtt/msg_queue.c b/app/mqtt/msg_queue.c new file mode 100644 index 00000000..afa98d41 --- /dev/null +++ b/app/mqtt/msg_queue.c @@ -0,0 +1,60 @@ +#include "c_string.h" +#include "c_stdlib.h" +#include "c_stdio.h" +#include "msg_queue.h" + +msg_queue_t *msg_enqueue(msg_queue_t **head, mqtt_message_t *msg, uint16_t msg_id, int msg_type, int publish_qos){ + if(!head){ + return NULL; + } + if (!msg || !msg->data || msg->length == 0){ + NODE_DBG("empty message\n"); + return NULL; + } + msg_queue_t *node = (msg_queue_t *)c_zalloc(sizeof(msg_queue_t)); + if(!node){ + NODE_DBG("not enough memory\n"); + return NULL; + } + + node->msg.data = (uint8_t *)c_zalloc(msg->length); + if(!node->msg.data){ + NODE_DBG("not enough memory\n"); + c_free(node); + return NULL; + } + c_memcpy(node->msg.data, msg->data, msg->length); + node->msg.length = msg->length; + node->next = NULL; + node->msg_id = msg_id; + node->msg_type = msg_type; + node->publish_qos = publish_qos; + + msg_queue_t *tail = *head; + if(tail){ + while(tail->next!=NULL) tail = tail->next; + tail->next = node; + } else { + *head = node; + } + return node; +} + +void msg_destroy(msg_queue_t *node){ + if(!node) return; + if(node->msg.data){ + c_free(node->msg.data); + node->msg.data = NULL; + } + c_free(node); +} + +msg_queue_t * msg_dequeue(msg_queue_t **head){ + if(!head || !*head){ + return NULL; + } + msg_queue_t *node = *head; // fetch head. + *head = node->next; // update head. + node->next = NULL; + return node; +} diff --git a/app/mqtt/msg_queue.h b/app/mqtt/msg_queue.h new file mode 100644 index 00000000..9da3f6bc --- /dev/null +++ b/app/mqtt/msg_queue.h @@ -0,0 +1,26 @@ +#ifndef _MSG_QUEUE_H +#define _MSG_QUEUE_H 1 +#include "mqtt_msg.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct msg_queue_t; + +typedef struct msg_queue_t { + struct msg_queue_t *next; + mqtt_message_t msg; + uint16_t msg_id; + int msg_type; + int publish_qos; +} msg_queue_t; + +msg_queue_t * msg_enqueue(msg_queue_t **head, mqtt_message_t *msg, uint16_t msg_id, int msg_type, int publish_qos); +void msg_destroy(msg_queue_t *node); +msg_queue_t * msg_dequeue(msg_queue_t **head); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/fragment.lua b/examples/fragment.lua index d3d0f7da..f24729de 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -395,4 +395,34 @@ 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) \ No newline at end of file +pcall(function() print(string.gsub(v, "%%(%x%x)", function(x) return string.char(tonumber(x, 16)) end)) end) + +m=mqtt.Client() +m:connect("192.168.18.88",1883) +topic={} +topic["/topic1"]=0 +topic["/topic2"]=0 +m:subscribe(topic,function(m) print("sub done") end) +m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end ) +m:publish("/topic1","hello",0,0) +m:publish("/topic3","hello",0,0) m:publish("/topic4","hello",0,0) + +m=mqtt.Client() +m:connect("192.168.18.88",1883) +m:subscribe("/topic1",0,function(m) print("sub done") end) +m:subscribe("/topic2",0,function(m) print("sub done") end) +m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end ) +m:publish("/topic1","hello",0,0) +m:publish("/topic3","hello",0,0) m:publish("/topic4","hello",0,0) +m:publish("/topic1","hello1",0,0) m:publish("/topic2","hello2",0,0) +m:publish("/topic1","hello",1,0) +m:subscribe("/topic3",2,function(m) print("sub done") end) +m:publish("/topic3","hello3",2,0) + +m=mqtt.Client() +m:connect("192.168.18.88",1883, function(con) print("connected hello") end) + +m=mqtt.Client() +m:on("connect",function(m) print("connection") end ) +m:connect("192.168.18.88",1883) +m:on("offline",function(m) print("disconnection") end ) 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 From dcb6e53af7b534b1d679339949922cc09bffa286 Mon Sep 17 00:00:00 2001 From: funshine Date: Tue, 31 Mar 2015 00:36:44 +0800 Subject: [PATCH 08/25] add auto-reconnect option to mqtt:connect api --- README.md | 8 +- app/include/user_version.h | 2 +- app/modules/mqtt.c | 421 +++++++++++++++++++++---------------- examples/fragment.lua | 24 +++ 4 files changed, 275 insertions(+), 180 deletions(-) diff --git a/README.md b/README.md index 90ec76e3..13a817da 100644 --- a/README.md +++ b/README.md @@ -225,8 +225,10 @@ m:on("message", function(conn, topic, data) end end) --- for secure: m:connect("192.168.11.118", 1880, 1) -m:connect("192.168.11.118", 1880, 0, function(conn) print("connected") end) +-- m:connect( host, port, secure, auto_reconnect, function(client) ) +-- for secure: m:connect("192.168.11.118", 1880, 1, 0) +-- for auto-reconnect: m:connect("192.168.11.118", 1880, 0, 1) +m:connect("192.168.11.118", 1880, 0, 0, function(conn) print("connected") end) -- subscribe topic with qos = 0 m:subscribe("/topic",0, function(conn) print("subscribe success") end) @@ -235,7 +237,7 @@ m:subscribe("/topic",0, function(conn) print("subscribe success") end) -- publish a message with data = hello, QoS = 0, retain = 0 m:publish("/topic","hello",0,0, function(conn) print("sent") end) -m:close(); +m:close(); -- if auto-reconnect = 1, will reconnect. -- you can call m:connect again ``` diff --git a/app/include/user_version.h b/app/include/user_version.h index 89a63fc3..79d104c5 100644 --- a/app/include/user_version.h +++ b/app/include/user_version.h @@ -7,6 +7,6 @@ #define NODE_VERSION_INTERNAL 0U #define NODE_VERSION "NodeMCU 0.9.5" -#define BUILD_DATE "build 20150330" +#define BUILD_DATE "build 20150331" #endif /* __USER_VERSION_H__ */ diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index db9990c5..2cc3ad6d 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -25,6 +25,7 @@ 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, @@ -71,16 +72,64 @@ 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; bool connected; // indicate socket connected, not mqtt prot connected. ETSTimer mqttTimer; tConnState connState; }lmqtt_userdata; +static void socket_connect(struct espconn *pesp_conn); + static void mqtt_socket_disconnected(void *arg) // tcp only { - NODE_DBG("mqtt_socket_disconnected is called.\n"); + NODE_DBG("enter mqtt_socket_disconnected.\n"); + struct espconn *pesp_conn = arg; + bool call_back = false; + if(pesp_conn == NULL) + return; + lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; + if(mud == NULL) + return; + + os_timer_disarm(&mud->mqttTimer); + + if(mud->pesp_conn){ + mud->pesp_conn->reverse = NULL; + if(mud->pesp_conn->proto.tcp) + c_free(mud->pesp_conn->proto.tcp); + mud->pesp_conn->proto.tcp = NULL; + c_free(mud->pesp_conn); + mud->pesp_conn = NULL; + } + + if(mud->connected){ // call back only called when socket is from connection to disconnection. + mud->connected = false; + if((mud->cb_disconnect_ref != LUA_NOREF) && (mud->self_ref != LUA_NOREF)) { + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_disconnect_ref); + lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua + call_back = true; + } + } + + lua_gc(gL, LUA_GCSTOP, 0); + if(mud->self_ref != LUA_NOREF){ // TODO: should we unref the client and delete it? + luaL_unref(gL, LUA_REGISTRYINDEX, mud->self_ref); + mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self + } + lua_gc(gL, LUA_GCRESTART, 0); + + if(call_back){ + lua_call(gL, 1, 0); + } + + NODE_DBG("leave mqtt_socket_disconnected.\n"); +} + +static void mqtt_socket_reconnected(void *arg, sint8_t err) +{ + NODE_DBG("enter mqtt_socket_reconnected.\n"); + // mqtt_socket_disconnected(arg); struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; @@ -88,44 +137,21 @@ static void mqtt_socket_disconnected(void *arg) // tcp only if(mud == NULL) return; - if(mud->connected){ - mud->connected = false; - if(mud->pesp_conn && mud->pesp_conn->proto.tcp) - c_free(mud->pesp_conn->proto.tcp); - mud->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){ // TODO: should we unref the client and delete it? - luaL_unref(gL, LUA_REGISTRYINDEX, mud->self_ref); - mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self - } - lua_gc(gL, LUA_GCRESTART, 0); - } + pesp_conn->proto.tcp->remote_port = mud->mqtt_state.port; + pesp_conn->proto.tcp->local_port = espconn_port(); - mud->connected = false; os_timer_disarm(&mud->mqttTimer); - - if(mud->cb_disconnect_ref != LUA_NOREF) - { - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_disconnect_ref); - if( mud->self_ref != LUA_NOREF) - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua - else - lua_pushnil(gL); - lua_call(gL, 1, 0); + if( (mud->event_timeout != 0) || mud->mqtt_state.auto_reconnect ){ + socket_connect(pesp_conn); + } else { + mqtt_socket_disconnected(arg); } -} - -static void mqtt_socket_reconnected(void *arg, sint8_t err) -{ - NODE_DBG("mqtt_socket_reconnected is called.\n"); - mqtt_socket_disconnected(arg); + NODE_DBG("leave mqtt_socket_reconnected.\n"); } static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) { + NODE_DBG("enter deliver_publish.\n"); const char comma[] = ","; mqtt_event_data_t event_data; @@ -149,11 +175,12 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) } else { lua_call(gL, 2, 0); } + NODE_DBG("leave deliver_publish.\n"); } static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) { - NODE_DBG("mqtt_socket_received is called.\n"); + NODE_DBG("enter mqtt_socket_received.\n"); uint8_t msg_type; uint8_t msg_qos; @@ -179,12 +206,10 @@ READPACKET: if(mqtt_get_type(mud->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK){ NODE_DBG("MQTT: Invalid packet\r\n"); mud->connState = MQTT_INIT; - if(mud->secure){ + if(mud->secure) espconn_secure_disconnect(pesp_conn); - } - else { + else espconn_disconnect(pesp_conn); - } } else { mud->connState = MQTT_DATA; NODE_DBG("MQTT: Connected\r\n"); @@ -320,8 +345,8 @@ READPACKET: break; } - if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->send_timeout == 0){ - mud->send_timeout = MQTT_SEND_TIMEOUT; + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + mud->event_timeout = MQTT_SEND_TIMEOUT; NODE_DBG("Sent: %d\n", node->msg.length); if( mud->secure ) espconn_secure_sent( pesp_conn, node->msg.data, node->msg.length ); @@ -330,13 +355,13 @@ READPACKET: mud->keep_alive_tick = 0; mud->mqtt_state.outbound_message = NULL; } - + NODE_DBG("leave mqtt_socket_received.\n"); return; } static void mqtt_socket_sent(void *arg) { - // NODE_DBG("mqtt_socket_sent is called.\n"); + NODE_DBG("enter mqtt_socket_sent.\n"); struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; @@ -350,7 +375,7 @@ static void mqtt_socket_sent(void *arg) } // call mqtt_sent() - mud->send_timeout = 0; + mud->event_timeout = 0; // qos = 0, publish and forgot. msg_queue_t *node = mud->mqtt_state.pending_msg_q; @@ -364,12 +389,12 @@ static void mqtt_socket_sent(void *arg) lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata to callback func in lua lua_call(gL, 1, 0); } + NODE_DBG("leave mqtt_socket_sent.\n"); } -static int mqtt_socket_client( lua_State* L ); static void mqtt_socket_connected(void *arg) { - NODE_DBG("mqtt_socket_connected is called.\n"); + NODE_DBG("enter mqtt_socket_connected.\n"); struct espconn *pesp_conn = arg; if(pesp_conn == NULL) return; @@ -385,26 +410,30 @@ static void mqtt_socket_connected(void *arg) mqtt_msg_init(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.out_buffer, mud->mqtt_state.out_buffer_length); mud->mqtt_state.outbound_message = mqtt_msg_connect(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.connect_info); NODE_DBG("Send MQTT connection infomation, data len: %d, d[0]=%d \r\n", mud->mqtt_state.outbound_message->length, mud->mqtt_state.outbound_message->data[0]); - if(mud->secure){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + if(mud->secure) espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - } else - { espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); - } mud->mqtt_state.outbound_message = NULL; mud->connState = MQTT_CONNECT_SENDING; + NODE_DBG("leave mqtt_socket_connected.\n"); return; } void mqtt_socket_timer(void *arg) { + // NODE_DBG("enter mqtt_socket_timer.\n"); lmqtt_userdata *mud = (lmqtt_userdata*) arg; if(mud == NULL) return; - if(mud->send_timeout > 0){ - mud->send_timeout --; + if(mud->event_timeout > 0){ + NODE_DBG("event_timeout: %d.\n", mud->event_timeout); + mud->event_timeout --; + if(mud->event_timeout > 0){ + return; + } } if(mud->pesp_conn == NULL){ @@ -412,50 +441,49 @@ void mqtt_socket_timer(void *arg) return; } - if(mud->send_timeout == 0){ // switch to next queued event. - if(mud->connState == MQTT_CONNECT_SENDING){ // MQTT_CONNECT time out. - mud->connState = MQTT_INIT; - if(mud->secure){ - espconn_secure_disconnect(mud->pesp_conn); - } - else { - espconn_disconnect(mud->pesp_conn); - } - mud->keep_alive_tick = 0; // not need count anymore - } else if(mud->connState == MQTT_DATA){ - msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; - if(pending_msg){ - mud->send_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); - } - // no queued event. - } - } - - if(mud->connState == MQTT_DATA){ - mud->keep_alive_tick ++; - if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ - 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->connState == MQTT_INIT){ // socket connect time out. + NODE_DBG("Can not connect to broker.\n"); + } else if(mud->connState == MQTT_CONNECT_SENDING){ // MQTT_CONNECT send time out. + mud->connState = MQTT_INIT; + if(mud->secure) + espconn_secure_disconnect(mud->pesp_conn); + else + espconn_disconnect(mud->pesp_conn); + mud->keep_alive_tick = 0; // not need count anymore + } else if(mud->connState == MQTT_CONNECT_SENT){ // wait for CONACK time out. + NODE_DBG("MQTT_CONNECT failed.\n"); + } else if(mud->connState == MQTT_DATA){ + msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; + if(pending_msg){ + mud->event_timeout = MQTT_SEND_TIMEOUT; if(mud->secure) - espconn_secure_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + espconn_secure_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); else - espconn_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + espconn_sent(mud->pesp_conn, pending_msg->msg.data, pending_msg->msg.length); mud->keep_alive_tick = 0; + NODE_DBG("id: %d - qos: %d, length: %d\n", pending_msg->msg_id, pending_msg->publish_qos, pending_msg->msg.length); + } else { + // no queued event. + mud->keep_alive_tick ++; + if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){ + mud->event_timeout = MQTT_SEND_TIMEOUT; + NODE_DBG("\r\nMQTT: Send keepalive packet\r\n"); + mud->mqtt_state.outbound_message = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); + if(mud->secure) + espconn_secure_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + else + espconn_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + mud->keep_alive_tick = 0; + } } } + // NODE_DBG("leave mqtt_socket_timer.\n"); } // Lua: mqtt.Client(clientid, keepalive, user, pass) static int mqtt_socket_client( lua_State* L ) { - NODE_DBG("mqtt_socket_client is called.\n"); + NODE_DBG("enter mqtt_socket_client.\n"); lmqtt_userdata *mud; char tempid[20] = {0}; @@ -485,8 +513,9 @@ static int mqtt_socket_client( lua_State* L ) mud->secure = 0; mud->keep_alive_tick = 0; - mud->send_timeout = 0; + mud->event_timeout = 0; mud->connState = MQTT_INIT; + mud->connected = false; c_memset(&mud->mqttTimer, 0, sizeof(ETSTimer)); c_memset(&mud->mqtt_state, 0, sizeof(mqtt_state_t)); c_memset(&mud->connect_info, 0, sizeof(mqtt_connect_info_t)); @@ -576,8 +605,11 @@ static int mqtt_socket_client( lua_State* L ) mud->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; mud->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; mud->mqtt_state.pending_msg_q = NULL; + mud->mqtt_state.auto_reconnect = 1; + mud->mqtt_state.port = 1883; mud->mqtt_state.connect_info = &mud->connect_info; + NODE_DBG("leave mqtt_socket_client.\n"); return 1; } @@ -586,7 +618,7 @@ static int mqtt_socket_client( lua_State* L ) // socket: unref everything static int mqtt_delete( lua_State* L ) { - NODE_DBG("mqtt_delete is called.\n"); + NODE_DBG("enter mqtt_delete.\n"); lmqtt_userdata *mud = (lmqtt_userdata *)luaL_checkudata(L, 1, "mqtt.socket"); luaL_argcheck(L, mud, 1, "mqtt.socket expected"); @@ -670,26 +702,27 @@ static int mqtt_delete( lua_State* L ) mud->self_ref = LUA_NOREF; } lua_gc(gL, LUA_GCRESTART, 0); + NODE_DBG("leave mqtt_delete.\n"); return 0; } static void socket_connect(struct espconn *pesp_conn) { + NODE_DBG("enter socket_connect.\n"); if(pesp_conn == NULL) return; lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse; if(mud == NULL) return; - if(mud->secure){ + if(mud->secure) espconn_secure_connect(pesp_conn); - } else - { espconn_connect(pesp_conn); - } + + os_timer_arm(&mud->mqttTimer, 1000, 1); - NODE_DBG("socket_connect is called.\n"); + NODE_DBG("leave socket_connect.\n"); } static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg); @@ -697,7 +730,7 @@ static dns_reconn_count = 0; static ip_addr_t host_ip; // for dns static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { - NODE_DBG("socket_dns_found is called.\n"); + NODE_DBG("enter socket_dns_found.\n"); struct espconn *pesp_conn = arg; if(pesp_conn == NULL){ NODE_DBG("pesp_conn null.\n"); @@ -729,86 +762,20 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) NODE_DBG("\n"); socket_connect(pesp_conn); } + NODE_DBG("leave socket_dns_found.\n"); } -// Lua: mqtt:lwt( topic, message, qos, retain, function(client) ) -static int mqtt_socket_lwt( lua_State* L ) -{ - 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"); - } - - 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); - 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"); @@ -817,6 +784,10 @@ static int mqtt_socket_connect( lua_State* L ) if(mud == NULL) return 0; + if(mud->connected){ + return luaL_error(L, "already connected"); + } + if(mud->pesp_conn){ //TODO: should I free tcp struct directly or ask user to call close()??? mud->pesp_conn->reverse = NULL; if(mud->pesp_conn->proto.tcp) @@ -868,6 +839,7 @@ static int mqtt_socket_connect( lua_State* L ) } pesp_conn->proto.tcp->remote_port = port; pesp_conn->proto.tcp->local_port = espconn_port(); + mud->mqtt_state.port = port; if ( (stack<=top) && lua_isnumber(L, stack) ) { @@ -881,6 +853,18 @@ static int mqtt_socket_connect( lua_State* L ) } mud->secure = secure; // save + if ( (stack<=top) && lua_isnumber(L, stack) ) + { + auto_reconnect = lua_tointeger(L, stack); + stack++; + if ( auto_reconnect != 0 && auto_reconnect != 1 ){ + auto_reconnect = 0; // default to 0 + } + } else { + auto_reconnect = 0; // default to 0 + } + mud->mqtt_state.auto_reconnect = auto_reconnect; + // call back function when a connection is obtained, tcp only if ((stack<=top) && (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)){ lua_pushvalue(L, stack); // copy argument (func) to the top of stack @@ -898,6 +882,12 @@ static int mqtt_socket_connect( lua_State* L ) espconn_regist_connectcb(pesp_conn, mqtt_socket_connected); espconn_regist_reconcb(pesp_conn, mqtt_socket_reconnected); + os_timer_disarm(&mud->mqttTimer); + os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); + // timer started in socket_connect() + mud->event_timeout = MQTT_CONNECT_TIMEOUT; + mud->connState = MQTT_INIT; + if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0)) { host_ip.addr = 0; @@ -911,9 +901,7 @@ static int mqtt_socket_connect( lua_State* L ) socket_connect(pesp_conn); } - os_timer_disarm(&mud->mqttTimer); - os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); - os_timer_arm(&mud->mqttTimer, 1000, 1); + NODE_DBG("leave mqtt_socket_connect.\n"); return 0; } @@ -921,7 +909,7 @@ static int mqtt_socket_connect( lua_State* L ) // client disconnect and unref itself static int mqtt_socket_close( lua_State* L ) { - NODE_DBG("mqtt_socket_close is called.\n"); + NODE_DBG("enter mqtt_socket_close.\n"); int i = 0; lmqtt_userdata *mud = NULL; @@ -944,13 +932,14 @@ static int mqtt_socket_close( lua_State* L ) if(mud->pesp_conn->proto.tcp->remote_port || mud->pesp_conn->proto.tcp->local_port) espconn_disconnect(mud->pesp_conn); } + NODE_DBG("leave mqtt_socket_close.\n"); return 0; } // Lua: mqtt:on( "method", function() ) static int mqtt_socket_on( lua_State* L ) { - NODE_DBG("mqtt_on is called.\n"); + NODE_DBG("enter mqtt_socket_on.\n"); lmqtt_userdata *mud; size_t sl; @@ -984,13 +973,13 @@ 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: bool = mqtt:subscribe(topic, qos, function()) static int mqtt_socket_subscribe( lua_State* L ) { - NODE_DBG("mqtt_socket_subscribe is called.\n"); + NODE_DBG("enter mqtt_socket_subscribe.\n"); uint8_t stack = 1, qos = 0; uint16_t msg_id = 0; @@ -1068,8 +1057,8 @@ static int mqtt_socket_subscribe( lua_State* L ) { NODE_DBG("topic: %s - id: %d - qos: %d, length: %d\n", topic, node->msg_id, node->publish_qos, node->msg.length); - if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->send_timeout == 0){ - mud->send_timeout = MQTT_SEND_TIMEOUT; + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + mud->event_timeout = MQTT_SEND_TIMEOUT; NODE_DBG("Sent: %d\n", node->msg.length); if( mud->secure ) espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); @@ -1084,13 +1073,14 @@ static int mqtt_socket_subscribe( lua_State* L ) { lua_pushboolean(L, 1); // enqueued succeed. } mud->mqtt_state.outbound_message = NULL; + NODE_DBG("leave mqtt_socket_subscribe.\n"); return 1; } // 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; @@ -1143,8 +1133,8 @@ static int mqtt_socket_publish( lua_State* L ) msg_queue_t *node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, msg_id, MQTT_MSG_TYPE_PUBLISH, (int)qos ); - if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->send_timeout == 0){ - mud->send_timeout = MQTT_SEND_TIMEOUT; + if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + mud->event_timeout = MQTT_SEND_TIMEOUT; NODE_DBG("Sent: %d\n", node->msg.length); if( mud->secure ) espconn_secure_sent( mud->pesp_conn, node->msg.data, node->msg.length ); @@ -1159,20 +1149,99 @@ static int mqtt_socket_publish( lua_State* L ) lua_pushboolean(L, 1); // enqueued succeed. } mud->mqtt_state.outbound_message = NULL; + NODE_DBG("leave mqtt_socket_publish.\n"); return 1; } +// Lua: mqtt:lwt( topic, message, qos, retain, function(client) ) +static int mqtt_socket_lwt( lua_State* L ) +{ + NODE_DBG("enter mqtt_socket_lwt.\n"); + uint8_t stack = 1; + size_t topicSize, msgSize; + NODE_DBG("mqtt_socket_lwt.\n"); + lmqtt_userdata *mud = NULL; + const char *lwtTopic, *lwtMsg; + uint8_t lwtQoS, lwtRetain; + + mud = (lmqtt_userdata *)luaL_checkudata( L, stack, "mqtt.socket" ); + luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); + + if(mud == NULL) + return 0; + + stack++; + lwtTopic = luaL_checklstring( L, stack, &topicSize ); + if (lwtTopic == NULL) + { + return luaL_error( L, "need lwt topic"); + } + + stack++; + lwtMsg = luaL_checklstring( L, stack, &msgSize ); + if (lwtMsg == NULL) + { + return luaL_error( L, "need lwt message"); + } + + if(mud->connect_info.will_topic){ // free the previous one if there is any + c_free(mud->connect_info.will_topic); + mud->connect_info.will_topic = NULL; + } + if(mud->connect_info.will_message){ + c_free(mud->connect_info.will_message); + mud->connect_info.will_message = NULL; + } + + mud->connect_info.will_topic = (uint8_t*) c_zalloc( topicSize + 1 ); + mud->connect_info.will_message = (uint8_t*) c_zalloc( msgSize + 1 ); + if(!mud->connect_info.will_topic || !mud->connect_info.will_message){ + if(mud->connect_info.will_topic){ + c_free(mud->connect_info.will_topic); + mud->connect_info.will_topic = NULL; + } + if(mud->connect_info.will_message){ + c_free(mud->connect_info.will_message); + mud->connect_info.will_message = NULL; + } + return luaL_error( L, "not enough memory"); + } + c_memcpy(mud->connect_info.will_topic, lwtTopic, topicSize); + mud->connect_info.will_topic[topicSize] = 0; + c_memcpy(mud->connect_info.will_message, lwtMsg, msgSize); + mud->connect_info.will_message[msgSize] = 0; + + if ( lua_isnumber(L, stack) ) + { + mud->connect_info.will_qos = lua_tointeger(L, stack); + stack++; + } + if ( lua_isnumber(L, stack) ) + { + mud->connect_info.will_retain = lua_tointeger(L, stack); + stack++; + } + + NODE_DBG("mqtt_socket_lwt: topic: %s, message: %s, qos: %d, retain: %d\n", + mud->connect_info.will_topic, + mud->connect_info.will_message, + mud->connect_info.will_qos, + mud->connect_info.will_retain); + NODE_DBG("leave mqtt_socket_lwt.\n"); + return 0; +} + // Module function map #define MIN_OPT_LEVEL 2 #include "lrodefs.h" 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/examples/fragment.lua b/examples/fragment.lua index f24729de..fb938191 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -397,6 +397,8 @@ 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={} @@ -426,3 +428,25 @@ 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() From 32e062f52333541d27ab44c105b81b92baa24c5e Mon Sep 17 00:00:00 2001 From: funshine Date: Tue, 31 Mar 2015 23:38:28 +0800 Subject: [PATCH 09/25] polish mqtt module --- README.md | 6 +++++ app/modules/mqtt.c | 53 +++++++++++++++++++++++++++++++------------ app/mqtt/msg_queue.c | 22 ++++++++++++++++++ app/mqtt/msg_queue.h | 2 ++ examples/fragment.lua | 12 +++++++++- 5 files changed, 79 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 13a817da..1e71a8fe 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. diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index 2cc3ad6d..d64a831b 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -231,7 +231,7 @@ READPACKET: msg_qos = mqtt_get_qos(mud->mqtt_state.in_buffer); msg_id = mqtt_get_id(mud->mqtt_state.in_buffer, mud->mqtt_state.in_buffer_length); - msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; + 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, @@ -263,12 +263,12 @@ READPACKET: if(msg_qos == 1){ mud->mqtt_state.outbound_message = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBACK, (int)msg_qos ); + msg_id, MQTT_MSG_TYPE_PUBACK, 0 ); } else if(msg_qos == 2){ mud->mqtt_state.outbound_message = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBREC, (int)msg_qos ); + msg_id, MQTT_MSG_TYPE_PUBREC, 0 ); } if(msg_qos == 1 || msg_qos == 2){ NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos); @@ -290,19 +290,27 @@ READPACKET: break; case MQTT_MSG_TYPE_PUBREC: + 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))); mud->mqtt_state.outbound_message = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBREL, (int)msg_qos ); + msg_id, MQTT_MSG_TYPE_PUBREL, 1 ); NODE_DBG("MQTT: Response PUBREL\r\n"); + } break; case MQTT_MSG_TYPE_PUBREL: + 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))); mud->mqtt_state.outbound_message = mqtt_msg_pubcomp(&mud->mqtt_state.mqtt_connection, msg_id); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBCOMP, (int)msg_qos ); + msg_id, MQTT_MSG_TYPE_PUBCOMP, 0 ); NODE_DBG("MQTT: Response PUBCOMP\r\n"); + } break; case MQTT_MSG_TYPE_PUBCOMP: - if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->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) @@ -317,7 +325,7 @@ READPACKET: case MQTT_MSG_TYPE_PINGREQ: mud->mqtt_state.outbound_message = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection); node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PINGRESP, (int)msg_qos ); + msg_id, MQTT_MSG_TYPE_PINGRESP, 1 ); NODE_DBG("MQTT: Response PINGRESP\r\n"); break; case MQTT_MSG_TYPE_PINGRESP: @@ -345,7 +353,7 @@ READPACKET: break; } - if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + 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 ) @@ -355,6 +363,7 @@ READPACKET: mud->keep_alive_tick = 0; mud->mqtt_state.outbound_message = NULL; } + NODE_DBG("receive, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_received.\n"); return; } @@ -376,9 +385,9 @@ static void mqtt_socket_sent(void *arg) // call mqtt_sent() mud->event_timeout = 0; - + NODE_DBG("sent1, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); // qos = 0, publish and forgot. - msg_queue_t *node = mud->mqtt_state.pending_msg_q; + 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) @@ -388,7 +397,14 @@ static void mqtt_socket_sent(void *arg) 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); + } 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_PINGRESP) { + 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"); } @@ -423,16 +439,21 @@ static void mqtt_socket_connected(void *arg) void mqtt_socket_timer(void *arg) { - // NODE_DBG("enter mqtt_socket_timer.\n"); + NODE_DBG("enter mqtt_socket_timer.\n"); lmqtt_userdata *mud = (lmqtt_userdata*) arg; if(mud == NULL) return; + 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"); + // should remove the head of the queue and re-send with DUP = 1 + // Not implemented yet. } } @@ -453,7 +474,7 @@ void mqtt_socket_timer(void *arg) } else if(mud->connState == MQTT_CONNECT_SENT){ // wait for CONACK time out. NODE_DBG("MQTT_CONNECT failed.\n"); } else if(mud->connState == MQTT_DATA){ - msg_queue_t *pending_msg = mud->mqtt_state.pending_msg_q; + 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) @@ -477,7 +498,7 @@ void mqtt_socket_timer(void *arg) } } } - // NODE_DBG("leave mqtt_socket_timer.\n"); + NODE_DBG("leave mqtt_socket_timer.\n"); } // Lua: mqtt.Client(clientid, keepalive, user, pass) @@ -1057,7 +1078,7 @@ static int mqtt_socket_subscribe( lua_State* L ) { NODE_DBG("topic: %s - id: %d - qos: %d, length: %d\n", topic, node->msg_id, node->publish_qos, node->msg.length); - if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + 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 ) @@ -1073,6 +1094,7 @@ static int mqtt_socket_subscribe( lua_State* L ) { lua_pushboolean(L, 1); // enqueued succeed. } mud->mqtt_state.outbound_message = NULL; + NODE_DBG("subscribe, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_subscribe.\n"); return 1; } @@ -1133,7 +1155,7 @@ static int mqtt_socket_publish( lua_State* L ) msg_queue_t *node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, msg_id, MQTT_MSG_TYPE_PUBLISH, (int)qos ); - if(node && (mud->mqtt_state.pending_msg_q->next == NULL) && mud->event_timeout == 0){ + 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 ) @@ -1149,6 +1171,7 @@ static int mqtt_socket_publish( lua_State* L ) lua_pushboolean(L, 1); // enqueued succeed. } mud->mqtt_state.outbound_message = NULL; + NODE_DBG("publish, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_publish.\n"); return 1; } diff --git a/app/mqtt/msg_queue.c b/app/mqtt/msg_queue.c index afa98d41..1258ad6e 100644 --- a/app/mqtt/msg_queue.c +++ b/app/mqtt/msg_queue.c @@ -58,3 +58,25 @@ msg_queue_t * msg_dequeue(msg_queue_t **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 index 9da3f6bc..05b910ae 100644 --- a/app/mqtt/msg_queue.h +++ b/app/mqtt/msg_queue.h @@ -18,6 +18,8 @@ typedef struct 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 } diff --git a/examples/fragment.lua b/examples/fragment.lua index fb938191..2e2e752a 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -418,7 +418,7 @@ m:publish("/topic1","hello",0,0) m:publish("/topic3","hello",0,0) m:publish("/topic4","hello",0,0) m:publish("/topic1","hello1",0,0) m:publish("/topic2","hello2",0,0) m:publish("/topic1","hello",1,0) -m:subscribe("/topic3",2,function(m) print("sub done") end) +m:subscribe("/topic3",0,function(m) print("sub done") end) m:publish("/topic3","hello3",2,0) m=mqtt.Client() @@ -450,3 +450,13 @@ 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) From 1c2ee75a008085378529ed076f89d03658d46e6c Mon Sep 17 00:00:00 2001 From: funshine Date: Fri, 3 Apr 2015 00:51:02 +0800 Subject: [PATCH 10/25] fix mqtt, do a format when wrong flash size is detected --- README.md | 2 +- app/include/user_version.h | 2 +- app/modules/mqtt.c | 298 ++++++++++++++++++++++--------------- app/platform/flash_fs.h | 3 + app/spiffs/spiffs.c | 8 +- app/spiffs/spiffs.h | 2 + app/user/Makefile | 1 + app/user/user_main.c | 17 ++- examples/fragment.lua | 12 ++ 9 files changed, 214 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index 1e71a8fe..b1d8ebd0 100644 --- a/README.md +++ b/README.md @@ -243,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(); -- if auto-reconnect = 1, will reconnect. +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/include/user_version.h b/app/include/user_version.h index 79d104c5..06bce33b 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 20150331" +#define BUILD_DATE "build 20150403" #endif /* __USER_VERSION_H__ */ diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index d64a831b..ce303af2 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -17,8 +17,6 @@ #include "mqtt_msg.h" #include "msg_queue.h" -static lua_State *gL = NULL; - #define MQTT_BUF_SIZE 1024 #define MQTT_DEFAULT_KEEPALIVE 60 #define MQTT_MAX_CLIENT_LEN 64 @@ -50,18 +48,16 @@ typedef struct mqtt_state_t 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; 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; @@ -80,6 +76,8 @@ typedef struct lmqtt_userdata }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 { @@ -94,33 +92,47 @@ static void mqtt_socket_disconnected(void *arg) // tcp only os_timer_disarm(&mud->mqttTimer); - if(mud->pesp_conn){ - mud->pesp_conn->reverse = NULL; - if(mud->pesp_conn->proto.tcp) - c_free(mud->pesp_conn->proto.tcp); - mud->pesp_conn->proto.tcp = NULL; - c_free(mud->pesp_conn); - mud->pesp_conn = NULL; - } - if(mud->connected){ // call back only called when socket is from connection to disconnection. mud->connected = false; - if((mud->cb_disconnect_ref != LUA_NOREF) && (mud->self_ref != LUA_NOREF)) { - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_disconnect_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref); // pass the userdata(client) to callback func in lua + 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; } } - lua_gc(gL, LUA_GCSTOP, 0); - if(mud->self_ref != LUA_NOREF){ // TODO: should we unref the client and delete it? - luaL_unref(gL, LUA_REGISTRYINDEX, mud->self_ref); - mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self - } - lua_gc(gL, LUA_GCRESTART, 0); + if(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(call_back){ - lua_call(gL, 1, 0); + 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"); @@ -137,11 +149,11 @@ static void mqtt_socket_reconnected(void *arg, sint8_t err) if(mud == NULL) return; - pesp_conn->proto.tcp->remote_port = mud->mqtt_state.port; - pesp_conn->proto.tcp->local_port = espconn_port(); - os_timer_disarm(&mud->mqttTimer); - if( (mud->event_timeout != 0) || mud->mqtt_state.auto_reconnect ){ + + 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); @@ -152,6 +164,8 @@ static void mqtt_socket_reconnected(void *arg, sint8_t err) static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) { NODE_DBG("enter deliver_publish.\n"); + if(mud == NULL) + return; const char comma[] = ","; mqtt_event_data_t event_data; @@ -165,15 +179,17 @@ 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 + if(mud->L == NULL) + return; + 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(gL, event_data.topic, event_data.topic_length); + lua_pushlstring(mud->L, 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); + lua_pushlstring(mud->L, event_data.data, event_data.data_length); + lua_call(mud->L, 3, 0); } else { - lua_call(gL, 2, 0); + lua_call(mud->L, 2, 0); } NODE_DBG("leave deliver_publish.\n"); } @@ -199,7 +215,9 @@ READPACKET: return; c_memcpy(mud->mqtt_state.in_buffer, pdata, len); - mud->mqtt_state.outbound_message = NULL; + 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: case MQTT_CONNECT_SENT: @@ -214,13 +232,15 @@ READPACKET: 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; @@ -248,9 +268,11 @@ READPACKET: 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); + 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: @@ -261,14 +283,14 @@ READPACKET: 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); - node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBACK, 0 ); + 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){ - mud->mqtt_state.outbound_message = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id); - node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBREC, 0 ); + 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); @@ -283,9 +305,11 @@ READPACKET: 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; @@ -294,18 +318,18 @@ READPACKET: 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))); - mud->mqtt_state.outbound_message = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id); - node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBREL, 1 ); + 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: 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))); - mud->mqtt_state.outbound_message = mqtt_msg_pubcomp(&mud->mqtt_state.mqtt_connection, msg_id); - node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PUBCOMP, 0 ); + 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; @@ -317,15 +341,17 @@ READPACKET: 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); - node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_PINGRESP, 1 ); + 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: @@ -361,7 +387,6 @@ READPACKET: else espconn_sent( pesp_conn, node->msg.data, node->msg.length ); mud->keep_alive_tick = 0; - mud->mqtt_state.outbound_message = NULL; } NODE_DBG("receive, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_received.\n"); @@ -379,12 +404,14 @@ static void mqtt_socket_sent(void *arg) return; if(!mud->connected) return; - if(mud->connState == MQTT_CONNECT_SENDING){ - mud->connState = MQTT_CONNECT_SENT; - } - // call mqtt_sent() mud->event_timeout = 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)); @@ -394,9 +421,11 @@ static void mqtt_socket_sent(void *arg) 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) { @@ -422,16 +451,18 @@ 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]); + 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, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + 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->connState = MQTT_CONNECT_SENDING; NODE_DBG("leave mqtt_socket_connected.\n"); return; @@ -444,6 +475,12 @@ void mqtt_socket_timer(void *arg) if(mud == NULL) return; + if(mud->pesp_conn == NULL){ + NODE_DBG("mud->pesp_conn is NULL.\n"); + os_timer_disarm(&mud->mqttTimer); + return; + } + 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); @@ -451,20 +488,19 @@ void mqtt_socket_timer(void *arg) if(mud->event_timeout > 0){ return; } else { - NODE_DBG("event timeout. \n"); + 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->pesp_conn == NULL){ - NODE_DBG("mud->pesp_conn is NULL.\n"); - return; - } - if(mud->connState == MQTT_INIT){ // socket connect time out. NODE_DBG("Can not connect to broker.\n"); + // 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); @@ -488,12 +524,17 @@ void mqtt_socket_timer(void *arg) 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"); - mud->mqtt_state.outbound_message = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection); + 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, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + espconn_secure_sent(mud->pesp_conn, temp_msg->data, temp_msg->length); else - espconn_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length); + espconn_sent(mud->pesp_conn, temp_msg->data, temp_msg->length); mud->keep_alive_tick = 0; } } @@ -523,6 +564,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; @@ -545,7 +587,7 @@ static int mqtt_socket_client( lua_State* L ) luaL_getmetatable(L, "mqtt.socket"); lua_setmetatable(L, -2); - gL = L; // global L for mqtt module. + mud->L = L; // L for mqtt module. if( lua_isstring(L,stack) ) // deal with the clientid string { @@ -584,8 +626,7 @@ static int mqtt_socket_client( lua_State* L ) mud->connect_info.username = (uint8_t *)c_zalloc(unl + 1); mud->connect_info.password = (uint8_t *)c_zalloc(pwl + 1); mud->mqtt_state.in_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); - mud->mqtt_state.out_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); - if(!mud->connect_info.client_id || !mud->connect_info.username || !mud->connect_info.password || !mud->mqtt_state.in_buffer || !mud->mqtt_state.out_buffer){ + if(!mud->connect_info.client_id || !mud->connect_info.username || !mud->connect_info.password || !mud->mqtt_state.in_buffer){ if(mud->connect_info.client_id) { c_free(mud->connect_info.client_id); mud->connect_info.client_id = NULL; @@ -601,10 +642,6 @@ static int mqtt_socket_client( lua_State* L ) if(mud->mqtt_state.in_buffer) { c_free(mud->mqtt_state.in_buffer); mud->mqtt_state.in_buffer = NULL; - } - if(mud->mqtt_state.out_buffer) { - c_free(mud->mqtt_state.out_buffer); - mud->mqtt_state.out_buffer = NULL; } return luaL_error(L, "not enough memory"); } @@ -624,7 +661,6 @@ static int mqtt_socket_client( lua_State* L ) mud->connect_info.keepalive = keepalive; mud->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; - mud->mqtt_state.out_buffer_length = MQTT_BUF_SIZE; mud->mqtt_state.pending_msg_q = NULL; mud->mqtt_state.auto_reconnect = 1; mud->mqtt_state.port = 1883; @@ -690,10 +726,6 @@ static int mqtt_delete( lua_State* L ) 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 @@ -717,12 +749,12 @@ 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; } @@ -736,6 +768,8 @@ static void socket_connect(struct espconn *pesp_conn) if(mud == NULL) return; + mud->event_timeout = MQTT_CONNECT_TIMEOUT; + mud->connState = MQTT_INIT; if(mud->secure) espconn_secure_connect(pesp_conn); else @@ -906,8 +940,6 @@ static int mqtt_socket_connect( lua_State* L ) os_timer_disarm(&mud->mqttTimer); os_timer_setfn(&mud->mqttTimer, (os_timer_func_t *)mqtt_socket_timer, mud); // timer started in socket_connect() - mud->event_timeout = MQTT_CONNECT_TIMEOUT; - mud->connState = MQTT_INIT; if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0)) { @@ -943,6 +975,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) @@ -1012,32 +1045,48 @@ static int mqtt_socket_subscribe( lua_State* L ) { luaL_argcheck( L, mud, stack, "mqtt.socket expected" ); stack++; + if(mud==NULL){ + NODE_DBG("userdata is nil.\n"); + lua_pushboolean(L, 0); + return 1; + } + + 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 */ - uint8_t temp_buffer[MQTT_BUF_SIZE]; + 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, &msg_id ); - NODE_DBG("topic: %s - qos: %d, length: %d\n", topic, qos, 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 + mud->mqtt_state.outbound_message->length > MQTT_BUF_SIZE){ + if (temp_pos + temp_msg->length > MQTT_BUF_SIZE){ lua_pop(L, 1); break; // too long message for the outbuffer. } - c_memcpy( temp_buffer + temp_pos, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length ); - temp_pos += mud->mqtt_state.outbound_message->length; + c_memcpy( temp_buf + temp_pos, temp_msg->data, temp_msg->length ); + temp_pos += temp_msg->length; lua_pop( L, 1 ); } @@ -1048,9 +1097,9 @@ static int mqtt_socket_subscribe( lua_State* L ) { return 1; } - c_memcpy( mud->mqtt_state.out_buffer, temp_buffer, temp_pos ); - mud->mqtt_state.outbound_message->data = mud->mqtt_state.out_buffer; - mud->mqtt_state.outbound_message->length = temp_pos; + 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"); @@ -1062,7 +1111,7 @@ static int mqtt_socket_subscribe( lua_State* L ) { return 1; } qos = luaL_checkinteger( L, stack ); - mud->mqtt_state.outbound_message = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); + temp_msg = mqtt_msg_subscribe( &mud->mqtt_state.mqtt_connection, topic, qos, &msg_id ); stack++; } @@ -1073,8 +1122,8 @@ static int mqtt_socket_subscribe( lua_State* L ) { mud->cb_suback_ref = luaL_ref( L, LUA_REGISTRYINDEX ); } - msg_queue_t *node = msg_enqueue( &(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, - msg_id, MQTT_MSG_TYPE_SUBSCRIBE, (int)mqtt_get_qos(mud->mqtt_state.outbound_message->data) ); + 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) ); NODE_DBG("topic: %s - id: %d - qos: %d, length: %d\n", topic, node->msg_id, node->publish_qos, node->msg.length); @@ -1093,7 +1142,6 @@ static int mqtt_socket_subscribe( lua_State* L ) { } else { lua_pushboolean(L, 1); // enqueued succeed. } - mud->mqtt_state.outbound_message = NULL; NODE_DBG("subscribe, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_subscribe.\n"); return 1; @@ -1123,7 +1171,11 @@ static int mqtt_socket_publish( lua_State* L ) return 1; } - pesp_conn = mud->pesp_conn; + if(!mud->connected){ + luaL_error( L, "not connected" ); + lua_pushboolean(L, 0); + return 1; + } const char *topic = luaL_checklstring( L, stack, &l ); stack ++; @@ -1140,7 +1192,9 @@ 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, &msg_id); @@ -1152,7 +1206,7 @@ static int mqtt_socket_publish( lua_State* L ) mud->cb_puback_ref = luaL_ref(L, LUA_REGISTRYINDEX); } - msg_queue_t *node = msg_enqueue(&(mud->mqtt_state.pending_msg_q), mud->mqtt_state.outbound_message, + 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){ @@ -1170,7 +1224,7 @@ static int mqtt_socket_publish( lua_State* L ) } else { lua_pushboolean(L, 1); // enqueued succeed. } - mud->mqtt_state.outbound_message = NULL; + NODE_DBG("publish, queue size: %d\n", msg_size(&(mud->mqtt_state.pending_msg_q))); NODE_DBG("leave mqtt_socket_publish.\n"); return 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 2e2e752a..9206be8c 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -460,3 +460,15 @@ 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) From 855864119074eaf2804ace5ce63faa61b3bc9a63 Mon Sep 17 00:00:00 2001 From: funshine Date: Fri, 3 Apr 2015 16:05:14 +0800 Subject: [PATCH 11/25] add gpio.serout() api to help serialize bit out --- app/modules/gpio.c | 77 +++++++++++++++++++++++++++++++++++++++++++ examples/fragment.lua | 12 +++++++ 2 files changed, 89 insertions(+) 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/examples/fragment.lua b/examples/fragment.lua index 9206be8c..157d8c41 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -472,3 +472,15 @@ m:on("offline", function(conn) 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 From 4ca371f473f5780fb6c3280b51b9190e19e4b18d Mon Sep 17 00:00:00 2001 From: Martin Han Date: Fri, 3 Apr 2015 23:34:12 +0800 Subject: [PATCH 12/25] Add support to DHT11 and add some comments. Change function names. read->-read11() support DHT11 ->read22() support DHT21 DHT22 --- lua_modules/dht22/{dht22.lua => dht_lib.lua} | 77 +++++++++++++++++--- 1 file changed, 66 insertions(+), 11 deletions(-) rename lua_modules/dht22/{dht22.lua => dht_lib.lua} (54%) diff --git a/lua_modules/dht22/dht22.lua b/lua_modules/dht22/dht_lib.lua similarity index 54% rename from lua_modules/dht22/dht22.lua rename to lua_modules/dht22/dht_lib.lua index a80a1bd6..641f2e17 100644 --- a/lua_modules/dht22/dht22.lua +++ b/lua_modules/dht22/dht_lib.lua @@ -1,34 +1,43 @@ -- *************************************************************************** --- DHT22 module for ESP8266 with nodeMCU +-- DHTxx(11,21,22) module for ESP8266 with nodeMCU -- --- Written by Javier Yanez +-- 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 ->read11 +--DHT21 Not Tested->read22 +--DHT22 Tested->read22 + +--==========================Module Part====================== local moduleName = ... local M = {} _G[moduleName] = M - +--==========================Local the UMI and TEMP=========== local humidity local temperature +--==========================Local the bitStream============== +local bitStream = {} -function M.read(pin) - local checksum - local checksumTest +---------------------------Read bitStream from DHTXX-------------------------- +local function read(pin) + + local bitlength = 0 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) @@ -39,7 +48,7 @@ function M.read(pin) gpio.write(pin, gpio.HIGH) gpio.mode(pin, gpio.INPUT) - -- Step 2: DHT22 send response signal + -- 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 @@ -59,8 +68,53 @@ function M.read(pin) -- bus will always let up eventually, don't bother with timeout while (gpio_read(pin) == 0) do end end - +end +---------------------------Convert the bitStream into Number through DHT11 Ways-------------------------- +function M.read11(pin) +--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 + read(pin) + local checksum = 0 + local checksumTest --DHT data acquired, process. + for i = 1, 8, 1 do -- Byte[0] + if (bitStream[i] > 3) then + humidity = humidity + 2 ^ (8 - i) + end + end + for i = 1, 8, 1 do -- Byte[2] + if (bitStream[i + 16] > 3) then + temperature = temperature + 2 ^ (8 - i) + end + end + for i = 1, 8, 1 do --Byte[4] + if (bitStream[i + 32] > 3) then + checksum = checksum + 2 ^ (8 - i) + end + end + + if(checksum ~= humidity+temperature) then + humidity = nil + temperature = nil + end + +end +---------------------------Convert the bitStream into Number through DHT22 Ways-------------------------- +function M.read22( pin ) +--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 + read(pin) + local checksum = 0 + local checksumTest + --DHT data acquired, process. for i = 1, 16, 1 do if (bitStream[i] > 3) then humidity = humidity + 2 ^ (16 - i) @@ -91,6 +145,7 @@ function M.read(pin) end end +---------------------------Check out the data-------------------------- function M.getTemperature() return temperature end From 1bc81f4c3e30b5bcb77fb06d69f512d1e4286261 Mon Sep 17 00:00:00 2001 From: Martin Han Date: Fri, 3 Apr 2015 23:44:26 +0800 Subject: [PATCH 13/25] Add support to DHT11 and add some comments. --- lua_modules/dht22/README.md | 77 ++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/lua_modules/dht22/README.md b/lua_modules/dht22/README.md index b68a3278..ab7b30f9 100644 --- a/lua_modules/dht22/README.md +++ b/lua_modules/dht22/README.md @@ -1,46 +1,78 @@ -# DHT22 module +# DHTxx module -This module is compatible with DHT22 and DHT21. -Supports nodemcu with or without floating point. +This module is compatible with DHT11, DHT21 and DHT22. No need to use a resistor to connect the pin data of DHT22 to ESP8266. -## Example +##Integer Verison[When using DHT11, Float version is useless...] +### Example ```lua PIN = 4 -- data pin, GPIO2 -dht22 = require("dht22") -dht22.read(PIN) -t = dht22.getTemperature() -h = dht22.getHumidity() +DHT= require("dht_lib") + +--dht.read11(PIN) +DHT.read22(PIN) + +t = DHT.getTemperature() +h = DHT.getHumidity() if h == nil then - print("Error reading from DHT22") + print("Error reading from DHT11/22") 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 +DHT = nil +package.loaded["dht_lib"]=nil +``` +##Float Verison +###Example +```lua +PIN = 4 -- data pin, GPIO2 + +DHT= require("dht_lib") + +--dht.read11(PIN) +DHT.read22(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.." deg C") + print("Temperature: "..(9 * t / 50 + 32).." deg F") + + -- humidity + print("Humidity: "..h.."%") +end + +-- release module +DHT = nil +package.loaded["dht_lib"]=nil ``` ## Functions -### read -read(pin) -Read humidity and temperature from DHT22. - +### read11 +read11(pin) +Read humidity and temperature from DHT11. +###read22 +read22(pin) +Read humidity and temperature from DHT22/21. **Parameters:** -* pin - ESP8266 pin connect to data pin in DHT22 +* pin - ESP8266 pin connect to data pin ### getHumidity getHumidity() @@ -54,5 +86,6 @@ getTemperature() Returns the temperature of the last reading. **Returns:** -* last temperature reading in 0.1ºC +* last temperature reading in(dht22) 0.1ºC (dht11)1ºC +* From bcbde08bf70b703e32aa43bdc6a76102a50944d1 Mon Sep 17 00:00:00 2001 From: funshine Date: Sun, 5 Apr 2015 02:22:51 +0800 Subject: [PATCH 14/25] fix mqtt keepalive ping, add a example for mqtt in lua_examples. --- app/include/user_version.h | 2 +- app/modules/mqtt.c | 62 ++++++++++++++++++-------------------- examples/fragment.lua | 31 +++++++++++++++++++ lua_examples/mqtt_test.lua | 30 ++++++++++++++++++ 4 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 lua_examples/mqtt_test.lua diff --git a/app/include/user_version.h b/app/include/user_version.h index 06bce33b..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 20150403" +#define BUILD_DATE "build 20150405" #endif /* __USER_VERSION_H__ */ diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c index ce303af2..c7afd0ff 100644 --- a/app/modules/mqtt.c +++ b/app/modules/mqtt.c @@ -47,8 +47,6 @@ typedef struct mqtt_state_t uint16_t port; int auto_reconnect; mqtt_connect_info_t* connect_info; - uint8_t* in_buffer; - int in_buffer_length; uint16_t message_length; uint16_t message_length_read; mqtt_connection_t mqtt_connection; @@ -166,7 +164,6 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) NODE_DBG("enter deliver_publish.\n"); if(mud == NULL) return; - const char comma[] = ","; mqtt_event_data_t event_data; event_data.topic_length = length; @@ -181,11 +178,15 @@ static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length) return; if(mud->L == NULL) return; - 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); - if(event_data.data_length > 0){ + 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 { + 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 { @@ -202,6 +203,9 @@ static void mqtt_socket_received(void *arg, char *pdata, unsigned short len) 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) @@ -211,17 +215,17 @@ 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); + // 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: case MQTT_CONNECT_SENT: - if(mqtt_get_type(mud->mqtt_state.in_buffer) != MQTT_MSG_TYPE_CONNACK){ + if(mqtt_get_type(in_buffer) != MQTT_MSG_TYPE_CONNACK){ NODE_DBG("MQTT: Invalid packet\r\n"); mud->connState = MQTT_INIT; if(mud->secure) @@ -245,11 +249,11 @@ READPACKET: 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)); @@ -295,7 +299,7 @@ READPACKET: if(msg_qos == 1 || msg_qos == 2){ NODE_DBG("MQTT: Queue response QoS: %d\r\n", msg_qos); } - deliver_publish(mud, mud->mqtt_state.in_buffer, mud->mqtt_state.message_length_read); + deliver_publish(mud, in_buffer, mud->mqtt_state.message_length); break; case MQTT_MSG_TYPE_PUBACK: if(pending_msg && pending_msg->msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg->msg_id == msg_id){ @@ -365,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"); @@ -386,8 +390,8 @@ READPACKET: espconn_secure_sent( pesp_conn, node->msg.data, node->msg.length ); else espconn_sent( pesp_conn, node->msg.data, node->msg.length ); - mud->keep_alive_tick = 0; } + 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; @@ -406,6 +410,7 @@ static void mqtt_socket_sent(void *arg) return; // call mqtt_sent() mud->event_timeout = 0; + mud->keep_alive_tick = 0; if(mud->connState == MQTT_CONNECT_SENDING){ mud->connState = MQTT_CONNECT_SENT; @@ -430,7 +435,7 @@ static void mqtt_socket_sent(void *arg) 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_PINGRESP) { + } 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))); @@ -462,6 +467,7 @@ static void mqtt_socket_connected(void *arg) espconn_secure_sent(pesp_conn, temp_msg->data, temp_msg->length); else 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"); @@ -625,8 +631,7 @@ static int mqtt_socket_client( lua_State* L ) mud->connect_info.client_id = (uint8_t *)c_zalloc(idl+1); mud->connect_info.username = (uint8_t *)c_zalloc(unl + 1); mud->connect_info.password = (uint8_t *)c_zalloc(pwl + 1); - mud->mqtt_state.in_buffer = (uint8_t *)c_zalloc(MQTT_BUF_SIZE); - if(!mud->connect_info.client_id || !mud->connect_info.username || !mud->connect_info.password || !mud->mqtt_state.in_buffer){ + 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; @@ -638,10 +643,6 @@ static int mqtt_socket_client( lua_State* L ) if(mud->connect_info.password) { c_free(mud->connect_info.password); mud->connect_info.password = NULL; - } - if(mud->mqtt_state.in_buffer) { - c_free(mud->mqtt_state.in_buffer); - mud->mqtt_state.in_buffer = NULL; } return luaL_error(L, "not enough memory"); } @@ -660,9 +661,8 @@ static int mqtt_socket_client( lua_State* L ) mud->connect_info.will_retain = 0; mud->connect_info.keepalive = keepalive; - mud->mqtt_state.in_buffer_length = MQTT_BUF_SIZE; mud->mqtt_state.pending_msg_q = NULL; - mud->mqtt_state.auto_reconnect = 1; + mud->mqtt_state.auto_reconnect = 0; mud->mqtt_state.port = 1883; mud->mqtt_state.connect_info = &mud->connect_info; @@ -722,10 +722,6 @@ 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; - } // ------- // free (unref) callback ref diff --git a/examples/fragment.lua b/examples/fragment.lua index 157d8c41..3f4ee2d0 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -484,3 +484,34 @@ 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) ) diff --git a/lua_examples/mqtt_test.lua b/lua_examples/mqtt_test.lua new file mode 100644 index 00000000..d27c6a93 --- /dev/null +++ b/lua_examples/mqtt_test.lua @@ -0,0 +1,30 @@ +-- 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) ) From f13c5c61e6113473949bfbc8dab9a4e3353b921a Mon Sep 17 00:00:00 2001 From: Wayne Bartnick Date: Sun, 5 Apr 2015 09:21:16 -0400 Subject: [PATCH 15/25] wifi.sta.config (wifi_station_config): - range checking password length (8~64) wifi.ap.config (wifi_ap_config): - range checking ssid length (1~32) - range checking pwd length (8~64) - new params: - auth: wifi.OPEN, wifi.WPA_PSK, wifi.WPA2_PSK, wifi.WPA_WPA2_PSK - default WITH pwd: wifi.WPA_WPA2_PSK - default WITHOUT pwd: wifi.OPEN - channel: 1~13 (default: 6) - hidden: 0/1 (default: 0) - max: 1~4 (default: 4) - beacon: 100~60000ms (default: 100) wifi.ap.getclient (wifi_ap_listclient): - returns table(mac,ip) of all connected clients wifi.ap.dhcp: - new submodule - config (wifi_ap_dhcp_config), returns start/end ips - params: - start (e.g., "192.168.1.100") - end ip calculated from wifi.ap.config.max - start (wifi_ap_dhcp_start), returns boolean - stop (wifi_ap_dhcp_stop), returns boolean --- app/modules/wifi.c | 216 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 201 insertions(+), 15 deletions(-) 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 } From ff85cf43716814a1959cf7299290584393804596 Mon Sep 17 00:00:00 2001 From: Wolfram Ladurner Date: Sun, 5 Apr 2015 14:19:14 +0200 Subject: [PATCH 16/25] fixes issue #321 "ws2812.writergb scrambles buffer" reported by makefu. Don't modify Lua-internal lstring - use a copy instead. --- app/modules/ws2812.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) 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; } From 06193090e6c51956d4fa439b573b5e4928da3f9b Mon Sep 17 00:00:00 2001 From: cal Date: Sun, 5 Apr 2015 15:52:10 +0200 Subject: [PATCH 17/25] LUAL_BUFFERSIZE back to 1K and warning notice added --- app/lua/luaconf.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 /* }================================================================== */ From b1287756bca71055caf57345ab22e039a7a034d7 Mon Sep 17 00:00:00 2001 From: Martin Han Date: Sun, 5 Apr 2015 23:22:25 +0800 Subject: [PATCH 18/25] Adjust the detail, fix program bug --- lua_modules/dht_lib/README.md | 89 +++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 lua_modules/dht_lib/README.md 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 +* From c21dea9d8eca30d444449c9af1b6c6edce042ca1 Mon Sep 17 00:00:00 2001 From: Martin Han Date: Sun, 5 Apr 2015 23:23:18 +0800 Subject: [PATCH 19/25] Fix DHT11 10times BUG, add auto-select feature --- lua_modules/dht_lib/dht_lib.lua | 185 ++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 lua_modules/dht_lib/dht_lib.lua diff --git a/lua_modules/dht_lib/dht_lib.lua b/lua_modules/dht_lib/dht_lib.lua new file mode 100644 index 00000000..e1edf13a --- /dev/null +++ b/lua_modules/dht_lib/dht_lib.lua @@ -0,0 +1,185 @@ +-- *************************************************************************** +-- 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 ->read11 +--DHT21 Not Tested->read22 +--DHT22 Tested->read22 + +--==========================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 +---------------------------Convert the bitStream into Number through DHT11 Ways-------------------------- +local function bit2DHT11() +--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 + local checksum = 0 + local checksumTest + --DHT data acquired, process. + for i = 1, 8, 1 do -- Byte[0] + if (bitStream[i] > 3) then + humidity = humidity + 2 ^ (8 - i) + end + end + for i = 1, 8, 1 do -- Byte[2] + if (bitStream[i + 16] > 3) then + temperature = temperature + 2 ^ (8 - i) + end + end + for i = 1, 8, 1 do --Byte[4] + if (bitStream[i + 32] > 3) then + checksum = checksum + 2 ^ (8 - i) + end + end + + if(checksum ~= humidity+temperature) then + humidity = nil + temperature = nil + end + +end +---------------------------Convert the bitStream into Number through DHT22 Ways-------------------------- +local function bit2DHT22() +--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 + local checksum = 0 + local checksumTest + --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 + +---------------------------Check out the data-------------------------- +----Auto Select the DHT11/DHT22 By check the byte[1] && byte[3]AND --- +---------------Which is empty when using DHT11------------------------- +function M.read(pin) + + read(pin) + + local byte_1 = 0 + local byte_2 = 0 + + 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[1] + if (bitStream[i+24] > 3) then + byte_2 = byte_2 + 2 ^ (8 - i) + end + end + + if byte_1==0 and byte_2 == 0 then + bit2DHT11() + else + bit2DHT22() + end + +end + + +function M.getTemperature() + return temperature +end + +function M.getHumidity() + return humidity +end + +return M From 450b79dbde5c924ea59166c2d668cd5de40755aa Mon Sep 17 00:00:00 2001 From: funshine Date: Mon, 6 Apr 2015 00:05:08 +0800 Subject: [PATCH 20/25] add more mqtt example, add a mqtt subfolder --- examples/fragment.lua | 4 ++ .../{mqtt_test.lua => mqtt/mqtt2cloud.lua} | 13 +++-- lua_examples/mqtt/mqtt_file.lua | 56 +++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) rename lua_examples/{mqtt_test.lua => mqtt/mqtt2cloud.lua} (82%) create mode 100644 lua_examples/mqtt/mqtt_file.lua diff --git a/examples/fragment.lua b/examples/fragment.lua index 3f4ee2d0..6536024c 100644 --- a/examples/fragment.lua +++ b/examples/fragment.lua @@ -515,3 +515,7 @@ 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/lua_examples/mqtt_test.lua b/lua_examples/mqtt/mqtt2cloud.lua similarity index 82% rename from lua_examples/mqtt_test.lua rename to lua_examples/mqtt/mqtt2cloud.lua index d27c6a93..b6b2893a 100644 --- a/lua_examples/mqtt_test.lua +++ b/lua_examples/mqtt/mqtt2cloud.lua @@ -1,19 +1,19 @@ --- 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) + m_dis[t](m,pl) end end -function topic1func(pl) +function topic1func(m,pl) print("get1: "..pl) end -function topic2func(pl) +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()) @@ -26,5 +26,8 @@ m:on("offline", function(conn) 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) ) +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"} From 560ad8e029238c9a3da28a0e91bd282427bb157a Mon Sep 17 00:00:00 2001 From: funshine Date: Mon, 6 Apr 2015 00:11:12 +0800 Subject: [PATCH 21/25] remove dht22 lib, use dht_lib instead --- lua_modules/dht22/README.md | 91 -------------------- lua_modules/dht22/dht_lib.lua | 157 ---------------------------------- 2 files changed, 248 deletions(-) delete mode 100644 lua_modules/dht22/README.md delete mode 100644 lua_modules/dht22/dht_lib.lua diff --git a/lua_modules/dht22/README.md b/lua_modules/dht22/README.md deleted file mode 100644 index ab7b30f9..00000000 --- a/lua_modules/dht22/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# DHTxx module - -This module is compatible with DHT11, DHT21 and DHT22. -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.read11(PIN) -DHT.read22(PIN) - -t = DHT.getTemperature() -h = DHT.getHumidity() - -if h == nil then - print("Error reading from DHT11/22") -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.read11(PIN) -DHT.read22(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.." deg C") - print("Temperature: "..(9 * t / 50 + 32).." deg F") - - -- humidity - print("Humidity: "..h.."%") -end - --- release module -DHT = nil -package.loaded["dht_lib"]=nil -``` -## Functions -### read11 -read11(pin) -Read humidity and temperature from DHT11. -###read22 -read22(pin) -Read humidity and temperature from DHT22/21. -**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/dht22/dht_lib.lua b/lua_modules/dht22/dht_lib.lua deleted file mode 100644 index 641f2e17..00000000 --- a/lua_modules/dht22/dht_lib.lua +++ /dev/null @@ -1,157 +0,0 @@ --- *************************************************************************** --- 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 ->read11 ---DHT21 Not Tested->read22 ---DHT22 Tested->read22 - ---==========================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 ----------------------------Convert the bitStream into Number through DHT11 Ways-------------------------- -function M.read11(pin) ---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 - read(pin) - local checksum = 0 - local checksumTest - --DHT data acquired, process. - for i = 1, 8, 1 do -- Byte[0] - if (bitStream[i] > 3) then - humidity = humidity + 2 ^ (8 - i) - end - end - for i = 1, 8, 1 do -- Byte[2] - if (bitStream[i + 16] > 3) then - temperature = temperature + 2 ^ (8 - i) - end - end - for i = 1, 8, 1 do --Byte[4] - if (bitStream[i + 32] > 3) then - checksum = checksum + 2 ^ (8 - i) - end - end - - if(checksum ~= humidity+temperature) then - humidity = nil - temperature = nil - end - -end ----------------------------Convert the bitStream into Number through DHT22 Ways-------------------------- -function M.read22( pin ) ---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 - read(pin) - local checksum = 0 - local checksumTest - --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 - ----------------------------Check out the data-------------------------- -function M.getTemperature() - return temperature -end - -function M.getHumidity() - return humidity -end - -return M From 9df94c7ee64f34ff9621316b5ef25d94200c6e32 Mon Sep 17 00:00:00 2001 From: Martin Han Date: Mon, 6 Apr 2015 14:38:35 +0800 Subject: [PATCH 22/25] Really Fix the BUGs, add come comment Sorry for the mistake, I forgot to save the file when gitting... --- lua_modules/dht_lib/dht_lib.lua | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lua_modules/dht_lib/dht_lib.lua b/lua_modules/dht_lib/dht_lib.lua index e1edf13a..4fb60ae3 100644 --- a/lua_modules/dht_lib/dht_lib.lua +++ b/lua_modules/dht_lib/dht_lib.lua @@ -8,10 +8,15 @@ -- *************************************************************************** --Support list: ---DHT11 Tested ->read11 ---DHT21 Not Tested->read22 ---DHT22 Tested->read22 +--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) +--For example, the data read form DHT2x is 24.3 degree C, and the output will be 243 +---------------the data read form DHT1x is 27 degree C, and the output will be 270 --==========================Module Part====================== local moduleName = ... local M = {} @@ -99,7 +104,12 @@ local function bit2DHT11() if(checksum ~= humidity+temperature) then humidity = nil temperature = nil + else + humidity = humidity *10 -- In order to universe the DHT22 + temperature = temperature *10 end + + end ---------------------------Convert the bitStream into Number through DHT22 Ways-------------------------- @@ -144,7 +154,7 @@ local function bit2DHT22() end ---------------------------Check out the data-------------------------- -----Auto Select the DHT11/DHT22 By check the byte[1] && byte[3]AND --- +----Auto Select the DHT11/DHT22 by checking the byte[1]==0 && byte[3]==0 --- ---------------Which is empty when using DHT11------------------------- function M.read(pin) @@ -172,7 +182,7 @@ function M.read(pin) end end - +--------------API for geting the data out------------------ function M.getTemperature() return temperature @@ -181,5 +191,5 @@ end function M.getHumidity() return humidity end - +-------------Return Index------------------------------------ return M From 81d9f8893a17a93e25566ddbc2d3cf45af4cd298 Mon Sep 17 00:00:00 2001 From: zeroday Date: Sun, 12 Apr 2015 23:34:11 +0800 Subject: [PATCH 23/25] fix #353 --- app/modules/auxmods.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 )\ From a3b72906d587ca10c3d93ddc52632909a3b77b0d Mon Sep 17 00:00:00 2001 From: Martin Han Date: Tue, 14 Apr 2015 20:42:16 +0800 Subject: [PATCH 24/25] Yeelink Modules --- lua_modules/yeelink/yeelink_lib.lua | 105 ++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 lua_modules/yeelink/yeelink_lib.lua 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 From 0f203f32c35c2ff7bcc16178555bd4b8007016cf Mon Sep 17 00:00:00 2001 From: Martin Han Date: Mon, 20 Apr 2015 19:43:24 +0800 Subject: [PATCH 25/25] Resuce RAM Usage --- lua_modules/dht_lib/dht_lib.lua | 149 ++++++++++++++------------------ 1 file changed, 66 insertions(+), 83 deletions(-) diff --git a/lua_modules/dht_lib/dht_lib.lua b/lua_modules/dht_lib/dht_lib.lua index 4fb60ae3..97823455 100644 --- a/lua_modules/dht_lib/dht_lib.lua +++ b/lua_modules/dht_lib/dht_lib.lua @@ -15,8 +15,6 @@ --AM2320 Not Test yet --Output format-> Real temperature times 10(or DHT22 will miss it float part in Int Version) ---For example, the data read form DHT2x is 24.3 degree C, and the output will be 243 ----------------the data read form DHT1x is 27 degree C, and the output will be 270 --==========================Module Part====================== local moduleName = ... local M = {} @@ -42,8 +40,6 @@ local function read(pin) bitStream[j] = 0 end - - -- Step 1: send out start signal to DHT22 gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) @@ -62,7 +58,7 @@ local function read(pin) 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 @@ -74,70 +70,78 @@ local function read(pin) while (gpio_read(pin) == 0) do end end end ----------------------------Convert the bitStream into Number through DHT11 Ways-------------------------- -local function bit2DHT11() ---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 - local checksum = 0 - local checksumTest - --DHT data acquired, process. + +---------------------------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 - humidity = humidity + 2 ^ (8 - i) + 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 - temperature = temperature + 2 ^ (8 - i) - end - end - for i = 1, 8, 1 do --Byte[4] - if (bitStream[i + 32] > 3) then - checksum = checksum + 2 ^ (8 - i) + if (bitStream[i+16] > 3) then + byte_2 = byte_2 + 2 ^ (8 - i) end end - if(checksum ~= humidity+temperature) then - humidity = nil - temperature = nil - else - humidity = humidity *10 -- In order to universe the DHT22 - temperature = temperature *10 + 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 - -end ----------------------------Convert the bitStream into Number through DHT22 Ways-------------------------- -local function bit2DHT22() ---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 - local checksum = 0 - local checksumTest - --DHT data acquired, process. - for i = 1, 16, 1 do - if (bitStream[i] > 3) then - humidity = humidity + 2 ^ (16 - i) + 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 - 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 + + 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) @@ -151,35 +155,14 @@ local function bit2DHT22() if (checksumTest - checksum >= 1) or (checksum - checksumTest >= 1) then humidity = nil end -end ----------------------------Check out the data-------------------------- -----Auto Select the DHT11/DHT22 by checking the byte[1]==0 && byte[3]==0 --- ----------------Which is empty when using DHT11------------------------- -function M.read(pin) - - read(pin) - - local byte_1 = 0 - local byte_2 = 0 - - 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[1] - if (bitStream[i+24] > 3) then - byte_2 = byte_2 + 2 ^ (8 - i) - end - end - - if byte_1==0 and byte_2 == 0 then - bit2DHT11() - else - bit2DHT22() - end + byte_0 = nil + byte_1 = nil + byte_2 = nil + byte_3 = nil + byte_4 = nil end --------------API for geting the data out------------------