Browse Source

Merge pull request #1 from MarsTechHAN/master

Update to MarsTechHAN's nodemcu-firmware
Vowstar 9 years ago
parent
commit
9cab751363
93 changed files with 5361 additions and 549 deletions
  1. 1 1
      .settings/org.eclipse.cdt.core.prefs
  2. 10 2
      Makefile
  3. 100 54
      README.md
  4. 5 3
      app/Makefile
  5. 39 0
      app/driver/i2c_master.c
  6. 4 5
      app/driver/pwm.c
  7. 33 16
      app/driver/spi.c
  8. 5 0
      app/include/driver/i2c_master.h
  9. 2 2
      app/include/driver/spi.h
  10. 6 0
      app/include/driver/spi_register.h
  11. 11 3
      app/include/user_config.h
  12. 191 44
      app/libc/c_math.c
  13. 4 0
      app/libc/c_math.h
  14. 438 13
      app/libc/c_stdio.c
  15. 10 0
      app/libc/c_stdio.h
  16. 220 21
      app/libc/c_stdlib.c
  17. 2 2
      app/libc/c_stdlib.h
  18. 2 1
      app/lua/luaconf.h
  19. 1 2
      app/lua/lundump.c
  20. 1 0
      app/lua/lvm.c
  21. 0 4
      app/lwip/app/espconn_tcp.c
  22. 1 0
      app/modules/Makefile
  23. 3 0
      app/modules/auxmods.h
  24. 18 0
      app/modules/modules.h
  25. 1051 0
      app/modules/mqtt.c
  26. 6 2
      app/modules/net.c
  27. 47 7
      app/modules/node.c
  28. 166 0
      app/modules/spi.c
  29. 22 6
      app/modules/tmr.c
  30. 12 1
      app/modules/wifi.c
  31. 44 0
      app/mqtt/Makefile
  32. 457 0
      app/mqtt/mqtt_msg.c
  33. 129 0
      app/mqtt/mqtt_msg.h
  34. 1 1
      app/platform/cpu_esp8266.h
  35. 16 2
      app/platform/platform.c
  36. 11 1
      app/platform/platform.h
  37. 4 0
      app/spiffs/spiffs.c
  38. 1 1
      app/upgrade/upgrade.c
  39. 30 25
      app/user/user_main.c
  40. 33 7
      examples/fragment.lua
  41. 85 0
      include/at_custom.h
  42. 2 0
      include/c_types.h
  43. 17 0
      include/espconn.h
  44. 5 0
      include/ip_addr.h
  45. 9 0
      include/osapi.h
  46. 32 0
      include/ping.h
  47. 28 0
      include/smartconfig.h
  48. 0 2
      include/spi_flash.h
  49. 261 252
      include/user_interface.h
  50. 1 1
      ld/eagle.app.v6.ld
  51. 1 0
      ld/eagle.rom.addr.v6.ld
  52. BIN
      lib/libat.a
  53. BIN
      lib/libjson.a
  54. BIN
      lib/liblwip.a
  55. BIN
      lib/libmain.a
  56. BIN
      lib/libnet80211.a
  57. BIN
      lib/libphy.a
  58. BIN
      lib/libpp.a
  59. BIN
      lib/libsmartconfig.a
  60. BIN
      lib/libssl.a
  61. BIN
      lib/libupgrade.a
  62. BIN
      lib/libwpa.a
  63. 74 0
      lua_examples/irsend.lua
  64. 16 0
      lua_examples/tcp2uart.lua
  65. 84 0
      lua_examples/yet-another-dht22.lua
  66. 65 0
      lua_examples/yet-another-ds18b20.lua
  67. 54 0
      lua_modules/bh1750/bh1750.lua
  68. 104 0
      lua_modules/bh1750/bh1750_CN.md
  69. 105 0
      lua_modules/bh1750/bh1750_EN.md
  70. 24 0
      lua_modules/bh1750/bh1750_Example1.lua
  71. 51 0
      lua_modules/bh1750/bh1750_Example2.lua
  72. 166 0
      lua_modules/bmp085/bmp085.EN.md
  73. 0 0
      lua_modules/bmp085/bmp085.lua
  74. 52 0
      lua_modules/dht22/README.md
  75. 100 0
      lua_modules/dht22/dht22.lua
  76. 0 0
      lua_modules/ds18b20/ds18b20.ZH.md
  77. 68 68
      lua_modules/ds18b20/ds18b20.lua
  78. 15 0
      lua_modules/ds3231/ds3231-example.lua
  79. 54 0
      lua_modules/ds3231/ds3231-web.lua
  80. 114 0
      lua_modules/ds3231/ds3231.EN.md
  81. 75 0
      lua_modules/ds3231/ds3231.lua
  82. 39 0
      lua_modules/http/http-example.lua
  83. 212 0
      lua_modules/http/http.lua
  84. 24 0
      lua_modules/si7021/si7021-example.lua
  85. 41 0
      lua_modules/si7021/si7021-lewei.lua
  86. 131 0
      lua_modules/si7021/si7021.EN.md
  87. 104 0
      lua_modules/si7021/si7021.lua
  88. 0 0
      pre_build/0.9.5/nodemcu_20150108.bin
  89. BIN
      pre_build/0.9.5/nodemcu_20150118.bin
  90. BIN
      pre_build/0.9.5/nodemcu_20150123.bin
  91. BIN
      pre_build/0.9.5/nodemcu_20150126.bin
  92. BIN
      pre_build/latest/nodemcu_latest.bin
  93. 11 0
      tools/.gitattributes

+ 1 - 1
.settings/org.eclipse.cdt.core.prefs

@@ -1,6 +1,6 @@
 eclipse.preferences.version=1
 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.992255352/PATH/delimiter=;
 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.992255352/PATH/operation=append
-environment/project/cdt.managedbuild.toolchain.gnu.cross.base.992255352/PATH/value=C\:\\Espressif\\xtensa-lx106-elf\\bin
+environment/project/cdt.managedbuild.toolchain.gnu.cross.base.992255352/PATH/value=C\:\\Espressif\\xtensa-lx106-elf\\bin;C\:\\MinGW\\bin;C\:\\MinGW\\msys\\1.0\\bin;C\:\\Python27
 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.992255352/append=true
 environment/project/cdt.managedbuild.toolchain.gnu.cross.base.992255352/appendContributed=true

+ 10 - 2
Makefile

@@ -30,7 +30,11 @@ ifeq ($(OS),Windows_NT)
 		OBJCOPY = xtensa-lx106-elf-objcopy
 	endif
 	FIRMWAREDIR = ..\\bin\\
-	ESPPORT = com1
+	ifndef COMPORT
+		ESPPORT = com1
+	else
+		ESPPORT = $(COMPORT)
+	endif
     ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
 # ->AMD64
     endif
@@ -40,7 +44,11 @@ ifeq ($(OS),Windows_NT)
 else
 # We are under other system, may be Linux. Assume using gcc.
 	# Can we use -fdata-sections?
-	ESPPORT = /dev/ttyUSB0
+	ifndef COMPORT
+		ESPPORT = /dev/ttyUSB0
+	else
+		ESPPORT = $(COMPORT)
+	endif
 	CCFLAGS += -Os -ffunction-sections -fno-jump-tables
 	AR = xtensa-lx106-elf-ar
 	CC = xtensa-lx106-elf-gcc

+ 100 - 54
README.md

@@ -1,45 +1,72 @@
 # **NodeMcu** #
 version 0.9.5
 ###A lua based firmware for wifi-soc esp8266
-Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=7&t=104)<br />
+Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br />
 Lua core based on [eLua project](http://www.eluaproject.net/)<br />
 File system based on [spiffs](https://github.com/pellepl/spiffs)<br />
 Open source development kit for NodeMCU [nodemcu-devkit](https://github.com/nodemcu/nodemcu-devkit)<br />
 Flash tool for NodeMCU [nodemcu-flasher](https://github.com/nodemcu/nodemcu-flasher)<br />
 
 wiki: [nodemcu wiki](https://github.com/nodemcu/nodemcu-firmware/wiki)<br />
+api: [nodemcu api](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en)<br />
 home: [nodemcu.com](http://www.nodemcu.com)<br />
-bbs: [中文论坛Chinese bbs](http://bbs.nodemcu.com)<br />
-Tencent QQ group QQ群: 309957875<br />
+bbs: [Chinese bbs](http://bbs.nodemcu.com)<br />
+Tencent QQ group: 309957875<br />
 
 # Summary
 - Easy to access wireless router
 - Based on Lua 5.1.4 (without *io, math, debug, os* module.)
 - Event-Drive programming preferred.
-- Build-in file, timer, pwm, i2c, 1-wire, net, gpio, wifi, adc, uart and system api.
+- Build-in file, timer, pwm, i2c, spi, 1-wire, net, mqtt, gpio, wifi, adc, uart and system api.
 - GPIO pin re-mapped, use the index to access gpio, i2c, pwm.
 
 # To Do List (pull requests are very welcomed)
 - fix wifi smart connect
-- add spi module
-- add mqtt module
+- add spi module (done)
+- add mqtt module (done)
 - add coap module
+- cross compiler
 
 # Change log
+2015-01-27<br />
+support floating point LUA.<br />
+use macro LUA_NUMBER_INTEGRAL in user_config.h control this feature.<br />
+LUA_NUMBER_INTEGRAL to disable floating point support,<br />
+// LUA_NUMBER_INTEGRAL to enable floating point support.<br />
+fix tmr.time(). #132<br />
+fix filesystem length. #113<br />
+fix ssl reboots. #134<br />
+build pre_build bin.
+
+2015-01-26<br />
+applied sdk095_patch1 to sdk 0.9.5.<br />
+added LUA examples and modules [by dvv](https://github.com/dvv). <br />
+added node.readvdd33() API [by alonewolfx2](https://github.com/alonewolfx2).<br />
+build pre_build bin.
+
+2015-01-24<br />
+migrate to sdk 0.9.5 release.<br />
+tmr.time() now return second(not precise yet). <br />
+build pre_build bin.
+
+2015-01-23<br />
+merge mqtt branch to master.<br />
+build pre_build bin.
+
+2015-01-18<br />
+merge mqtt module to [new branch mqtt](https://github.com/nodemcu/nodemcu-firmware/tree/mqtt) from [https://github.com/tuanpmt/esp_mqtt](https://github.com/tuanpmt/esp_mqtt).<br />
+merge spi module from iabdalkader:spi. <br />
+fix #110,set local port to random in client mode.<br />
+modify gpio.read to NOT set pin to input mode automatic.<br />
+add PATH env with C:\MinGW\bin;C:\MinGW\msys\1.0\bin;C:\Python27 in eclipse project. resolve #103.
+
 2015-01-08<br />
 fix net.socket:send() issue when multi sends are called. <br />
 *NOTE*: if data length is bigger than 1460, send next packet AFTER "sent" callback is called.<br />
 fix file.read() api, take 0xFF as a regular byte, not EOF.<br />
 pre_build/latest/nodemcu_512k_latest.bin is removed. use pre_build/latest/nodemcu_latest.bin instead.
 
-2015-01-07<br />
-retrive more ram back.<br />
-add api file.format() to rebuild file system.<br />
-rename "NodeMcu" to "NodeMCU" in firmware.<br />
-add some check for file system op.
-
-[more change log](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en#change_log)<br />
-[更多变更日志](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_cn#change_log)
+[more change log](https://github.com/nodemcu/nodemcu-firmware/wiki)<br />
 
 ##GPIO NEW TABLE ( Build 20141219 and later)
 
@@ -75,39 +102,6 @@ add some check for file system op.
 </table>
 #### [*] D0(GPIO16) can only be used as gpio read/write. no interrupt supported. no pwm/i2c/ow supported.
 
-##GPIO OLD TABLE (Before build 20141212)
-
-<a id="old_gpio_map"></a>
-<table>
-  <tr>
-    <th scope="col">IO index</th><th scope="col">ESP8266 pin</th><th scope="col">IO index</th><th scope="col">ESP8266 pin</th>
-  </tr>
-  <tr>
-    <td>0</td><td>GPIO12</td><td>8</td><td>GPIO0</td>
-  </tr>
-  <tr>
-    <td>1</td><td>GPIO13</td><td>9</td><td>GPIO2</td>
-   </tr>
-   <tr>
-    <td>2</td><td>GPIO14</td><td>10</td><td>GPIO4</td>
-  </tr>
-  <tr>
-    <td>3</td><td>GPIO15</td><td>11</td><td>GPIO5</td>
-   </tr>
-   <tr>
-    <td>4</td><td>GPIO3</td><td></td><td></td>
-  </tr>
-  <tr>
-    <td>5</td><td>GPIO1</td><td></td><td></td>
-   </tr>
-   <tr>
-    <td>6</td><td>GPIO9</td><td></td><td></td>
-  </tr>
-  <tr>
-    <td>7</td><td>GPIO10</td<td></td><td></td>
-   </tr>
-</table>
-
 #Build option
 ####file ./app/include/user_config.h
 ```c
@@ -132,6 +126,8 @@ add some check for file system op.
 #define LUA_USE_MODULES_OW
 #define LUA_USE_MODULES_BIT
 #endif /* LUA_USE_MODULES */
+...
+// LUA_NUMBER_INTEGRAL
 ```
 
 #Flash the firmware
@@ -140,10 +136,8 @@ for most esp8266 modules, just pull GPIO0 down and restart.<br />
 You can use the [nodemcu-flasher](https://github.com/nodemcu/nodemcu-flasher) to burn the firmware.
 
 Or, if you build your own bin from source code.<br />
-eagle.app.v6.flash.bin: 0x00000<br />
-eagle.app.v6.irom0text.bin: 0x10000<br />
-esp_init_data_default.bin: 0x7c000<br />
-blank.bin: 0x7e000<br />
+0x00000.bin: 0x00000<br />
+0x10000.bin: 0x10000<br />
 
 *Better run file.format() after flash*
 
@@ -155,11 +149,13 @@ baudrate:9600
 ####Connect to your ap
 
 ```lua
-    print(wifi.sta.getip())
-    --0.0.0.0
+    ip = wifi.sta.getip()
+    print(ip)
+    --nil
     wifi.setmode(wifi.STATION)
     wifi.sta.config("SSID","password")
-    print(wifi.sta.getip())
+    ip = wifi.sta.getip()
+    print(ip)
     --192.168.18.110
 ```
 
@@ -197,6 +193,56 @@ baudrate:9600
     end)
 ```
 
+####Connect to MQTT Broker
+
+```lua
+-- init mqtt client with keepalive timer 120sec
+m = mqtt.Client("clientid", 120, "user", "password")
+
+-- setup Last Will and Testament (optional)
+-- Broker will publish a message with qos = 0, retain = 0, data = "offline" 
+-- to topic "/lwt" if client don't send keepalive packet
+m:lwt("/lwt", "offline", 0, 0)
+
+m:on("connect", function(con) print ("connected") end)
+m:on("offline", function(con) print ("offline") end)
+
+-- on publish message receive event
+m:on("message", function(conn, topic, data) 
+  print(topic .. ":" ) 
+  if data ~= nil then
+    print(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)
+
+-- subscribe topic with qos = 0
+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();
+-- you can call m:connect again
+
+```
+
+#### UDP client and server
+```lua
+-- a udp server
+s=net.createServer(net.UDP) 
+s:on("receive",function(s,c) print(c) end)
+s:listen(5683)
+
+-- a udp client
+cu=net.createConnection(net.UDP) 
+cu:on("receive",function(cu,c) print(c) end) 
+cu:connect(5683,"192.168.18.101") 
+cu:send("hello")
+```
+
 ####Do something shining
 ```lua
   function led(r,g,b) 

+ 5 - 3
app/Makefile

@@ -26,11 +26,11 @@ SUBDIRS=    \
 	driver	\
 	lwip	\
 	json	\
-	ssl	\
 	upgrade	\
 	platform	\
 	libc 	\
 	lua 	\
+	mqtt	\
 	smart 	\
 	wofs 	\
 	modules	\
@@ -41,6 +41,7 @@ endif # } PDIR
 APPDIR = .
 LDDIR = ../ld
 
+CCFLAGS += -Os
 
 TARGET_LDFLAGS =		\
 	-nostdlib		\
@@ -48,7 +49,6 @@ TARGET_LDFLAGS =		\
 	--longcalls \
 	--text-section-literals
 
-
 ifeq ($(FLAVOR),debug)
     TARGET_LDFLAGS += -g -O2
 endif
@@ -72,11 +72,11 @@ COMPONENTS_eagle.app.v6 = \
 	driver/libdriver.a	\
 	lwip/liblwip.a	\
 	json/libjson.a	\
-	ssl/libssl.a	\
 	upgrade/libupgrade.a	\
 	platform/libplatform.a	\
 	libc/liblibc.a 	\
 	lua/liblua.a 	\
+	mqtt/mqtt.a 	\
 	smart/smart.a 	\
 	wofs/wofs.a 	\
 	spiffs/spiffs.a 	\
@@ -99,6 +99,8 @@ LINKFLAGS_eagle.app.v6 = \
 	-lwpa	\
 	-lmain	\
 	-ljson	\
+	-lsmartconfig	\
+	-lssl	\
 	$(DEP_LIBS_eagle.app.v6)					\
 	-Wl,--end-group
 

+ 39 - 0
app/driver/i2c_master.c

@@ -219,6 +219,45 @@ i2c_master_getAck(void)
     return retVal;
 }
 
+/******************************************************************************
+* FunctionName : i2c_master_checkAck
+* Description  : get dev response
+* Parameters   : NONE
+* Returns      : true : get ack ; false : get nack
+*******************************************************************************/
+bool ICACHE_FLASH_ATTR
+i2c_master_checkAck(void)
+{
+    if(i2c_master_getAck()){
+        return FALSE;
+    }else{
+        return TRUE;
+    }
+}
+
+/******************************************************************************
+* FunctionName : i2c_master_send_ack
+* Description  : response ack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_send_ack(void)
+{
+    i2c_master_setAck(0x0);
+}
+/******************************************************************************
+* FunctionName : i2c_master_send_nack
+* Description  : response nack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_send_nack(void)
+{
+    i2c_master_setAck(0x1);
+}
+
 /******************************************************************************
  * FunctionName : i2c_master_readByte
  * Description  : read Byte from i2c bus

+ 4 - 5
app/driver/pwm.c

@@ -349,11 +349,6 @@ pwm_init(uint16 freq, uint16 *duty)
 {
     uint8 i;
 
-    ETS_FRC_TIMER1_INTR_ATTACH(pwm_tim1_intr_handler, NULL);
-    TM1_EDGE_INT_ENABLE();
-    ETS_FRC1_INTR_ENABLE();
-
-    RTC_CLR_REG_MASK(FRC1_INT_ADDRESS, FRC1_INT_CLR_MASK);
     RTC_REG_WRITE(FRC1_CTRL_ADDRESS,  //FRC2_AUTO_RELOAD|
                   DIVDED_BY_16
                   | FRC1_ENABLE_TIMER
@@ -377,6 +372,10 @@ pwm_init(uint16 freq, uint16 *duty)
     // pwm_set_freq_duty(freq, duty);
 
     pwm_start();
+    
+    ETS_FRC_TIMER1_INTR_ATTACH(pwm_tim1_intr_handler, NULL);
+    TM1_EDGE_INT_ENABLE();
+    ETS_FRC1_INTR_ENABLE();
 }
 
 bool ICACHE_FLASH_ATTR

+ 33 - 16
app/driver/spi.c

@@ -64,12 +64,11 @@ void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit)
  * Description  : SPI master initial function for common byte units transmission
  * Parameters   : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
 *******************************************************************************/
-void spi_master_init(uint8 spi_no)
+void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock)
 {
 	uint32 regvalue; 
 
 	if(spi_no>1) 		return; //handle invalid input number
-	
 
 	if(spi_no==SPI){
 		WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005); 
@@ -86,13 +85,33 @@ void spi_master_init(uint8 spi_no)
 		PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode	
 	}
 
-	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND|SPI_USR_MOSI);
-	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
+	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_DOUTDIN|SPI_USR_MOSI);
+
+    //set clock polarity
+    // TODO: This doesn't work
+    //if (cpol == 1) {
+    //    SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_HIGH_MODE<<SPI_CK_OUT_HIGH_MODE_S));
+    //} else {
+    //    SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_LOW_MODE<<SPI_CK_OUT_LOW_MODE_S));
+    //}
+    //os_printf("SPI_CTRL2 is %08x\n",READ_PERI_REG(SPI_CTRL2(spi_no)));
+
+    //set clock phase
+    if (cpha == 1) {
+    	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);
+    } else {
+    	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);
+    }
+
+    CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE|SPI_WR_BYTE_ORDER|SPI_USR_MISO|
+                        SPI_RD_BYTE_ORDER|SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY);
 
 	//clear Daul or Quad lines transmission mode
 	CLEAR_PERI_REG_MASK(SPI_CTRL(spi_no), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE);
 
+	// SPI clock=CPU clock/8
 	WRITE_PERI_REG(SPI_CLOCK(spi_no), 
+					((1&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|
 					((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
 					((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
 					((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
@@ -109,21 +128,19 @@ void spi_master_init(uint8 spi_no)
  * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
  *				uint8 data- transmitted data
 *******************************************************************************/
-void spi_mast_byte_write(uint8 spi_no,uint8 data)
- {
-	uint32 regvalue;
+void spi_mast_byte_write(uint8 spi_no, uint8 *data)
+{
+    if(spi_no>1) 		return; //handle invalid input number
 
-	if(spi_no>1) 		return; //handle invalid input number
+    while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
 
-	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
-	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO);
+    WRITE_PERI_REG(SPI_W0(HSPI), *data);
 
-	//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
-	// bit15-0 is cmd value.
-	WRITE_PERI_REG(SPI_USER2(spi_no), 
-					((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)data));
-	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
- }  
+    SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+    while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+
+    *data = (uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);
+}  
 
 /******************************************************************************
  * FunctionName : spi_byte_write_espslave

+ 5 - 0
app/include/driver/i2c_master.h

@@ -63,6 +63,11 @@ void i2c_master_setAck(uint8 level);
 uint8 i2c_master_getAck(void);
 uint8 i2c_master_readByte(void);
 void i2c_master_writeByte(uint8 wrdata);
+
+bool i2c_master_checkAck(void);
+void i2c_master_send_ack(void);
+void i2c_master_send_nack(void);
+
 uint8 i2c_master_get_pinSDA();
 uint8 i2c_master_get_pinSCL();
 

+ 2 - 2
app/include/driver/spi.h

@@ -18,9 +18,9 @@ void spi_lcd_mode_init(uint8 spi_no);
 void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit);
 
 //spi master init funtion
-void spi_master_init(uint8 spi_no);
+void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock);
 //use spi send 8bit data
-void spi_mast_byte_write(uint8 spi_no,uint8 data);
+void spi_mast_byte_write(uint8 spi_no,uint8 *data);
 
 //transmit data to esp8266 slave buffer,which needs 16bit transmission ,
 //first byte is master command 0x04, second byte is master data

+ 6 - 0
app/include/driver/spi_register.h

@@ -39,6 +39,11 @@
 #define SPI_MISO_DELAY_NUM_S 18
 #define SPI_MISO_DELAY_MODE 0x00000003
 #define SPI_MISO_DELAY_MODE_S 16
+#define SPI_CK_OUT_HIGH_MODE 0x0000000F
+#define SPI_CK_OUT_HIGH_MODE_S 12
+#define SPI_CK_OUT_LOW_MODE 0x0000000F
+#define SPI_CK_OUT_LOW_MODE_S 8
+
 #define SPI_CLOCK(i)                          (REG_SPI_BASE(i)  + 0x18)
 #define SPI_CLK_EQU_SYSCLK (BIT(31))
 #define SPI_CLKDIV_PRE 0x00001FFF
@@ -73,6 +78,7 @@
 #define SPI_CS_SETUP (BIT(5))
 #define SPI_CS_HOLD (BIT(4))
 #define SPI_FLASH_MODE (BIT(2))
+#define SPI_DOUTDIN (BIT(0))
 
 #define SPI_USER1(i)                          (REG_SPI_BASE(i) + 0x20)
 #define SPI_USR_ADDR_BITLEN 0x0000003F

+ 11 - 3
app/include/user_config.h

@@ -7,7 +7,7 @@
 #define NODE_VERSION_INTERNAL   0U
 
 #define NODE_VERSION	"NodeMCU 0.9.5"
-#define BUILD_DATE	    "build 20150108"
+#define BUILD_DATE	    "build 20150127"
 
 // #define FLASH_512K
 // #define FLASH_1M
@@ -18,6 +18,9 @@
 #define FULL_VERSION_FOR_USER
 
 #ifdef DEVELOP_VERSION
+
+#define USE_OPTIMIZE_PRINTF
+
 #define NODE_DEBUG
 #endif	/* DEVELOP_VERSION */
 
@@ -38,7 +41,7 @@
 #define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed))
 #define ICACHE_STORE_ATTR __attribute__((aligned(4)))
 #define ICACHE_RAM_ATTR __attribute__((section(".iram0.text")))
-#define ICACHE_RODATA_ATTR __attribute__((section(".rodata2.text")))
+// #define ICACHE_RODATA_ATTR __attribute__((section(".rodata2.text")))
 
 #define CLIENT_SSL_ENABLE
 #define GPIO_INTERRUPT_ENABLE
@@ -55,14 +58,19 @@
 #define LUA_USE_MODULES_NET
 #define LUA_USE_MODULES_PWM
 #define LUA_USE_MODULES_I2C
+#define LUA_USE_MODULES_SPI
 #define LUA_USE_MODULES_TMR
 #define LUA_USE_MODULES_ADC
 #define LUA_USE_MODULES_UART
 #define LUA_USE_MODULES_OW
 #define LUA_USE_MODULES_BIT
+#define LUA_USE_MODULES_MQTT
 #endif /* LUA_USE_MODULES */
 
-#define LUA_NUMBER_INTEGRAL
+// #define LUA_NUMBER_INTEGRAL
+#ifndef LUA_NUMBER_INTEGRAL
+#define PRINTF_LONG_SUPPORT
+#endif
 
 #define LUA_OPTRAM
 #ifdef LUA_OPTRAM

+ 191 - 44
app/libc/c_math.c

@@ -1,37 +1,172 @@
 #include "c_math.h"
 #include "c_types.h"
 
+double floor(double x)
+{
+    return (double) (x < 0.f ? (((int) x) - 1) : ((int) x));
+}
+
+double pow(double x, double y)
+{
+#define MAXEXP 2031     /* (MAX_EXP * 16) - 1           */
+#define MINEXP -2047        /* (MIN_EXP * 16) - 1           */
+#define HUGE MAXFLOAT
+    double a1[] =
+    {
+        1.0,
+        0.95760328069857365,
+        0.91700404320467123,
+        0.87812608018664974,
+        0.84089641525371454,
+        0.80524516597462716,
+        0.77110541270397041,
+        0.73841307296974966,
+        0.70710678118654752,
+        0.67712777346844637,
+        0.64841977732550483,
+        0.62092890603674203,
+        0.59460355750136054,
+        0.56939431737834583,
+        0.54525386633262883,
+        0.52213689121370692,
+        0.50000000000000000
+    };
+    double a2[] =
+    {
+        0.24114209503420288E-17,
+        0.92291566937243079E-18,
+        -0.15241915231122319E-17,
+        -0.35421849765286817E-17,
+        -0.31286215245415074E-17,
+        -0.44654376565694490E-17,
+        0.29306999570789681E-17,
+        0.11260851040933474E-17
+    };
+    double p1 = 0.833333333333332114e-1;
+    double p2 = 0.125000000005037992e-1;
+    double p3 = 0.223214212859242590e-2;
+    double p4 = 0.434457756721631196e-3;
+    double q1 = 0.693147180559945296e0;
+    double q2 = 0.240226506959095371e0;
+    double q3 = 0.555041086640855953e-1;
+    double q4 = 0.961812905951724170e-2;
+    double q5 = 0.133335413135857847e-2;
+    double q6 = 0.154002904409897646e-3;
+    double q7 = 0.149288526805956082e-4;
+    double k = 0.442695040888963407;
+
+    double frexp(), g, ldexp(), r, u1, u2, v, w, w1, w2, y1, y2, z;
+    int iw1, m, p;
+
+    if (y == 0.0)
+        return (1.0);
+    if (x <= 0.0)
+    {
+        if (x == 0.0)
+        {
+            if (y > 0.0)
+                return (x);
+            //cmemsg(FP_POWO, &y);
+            //return(HUGE);
+        }
+        else
+        {
+            //cmemsg(FP_POWN, &x);
+            x = -x;
+        }
+    }
+    g = frexp(x, &m);
+    p = 0;
+    if (g <= a1[8])
+        p = 8;
+    if (g <= a1[p + 4])
+        p += 4;
+    if (g <= a1[p + 2])
+        p += 2;
+    p++;
+    z = ((g - a1[p]) - a2[p / 2]) / (g + a1[p]);
+    z += z;
+    v = z * z;
+    r = (((p4 * v + p3) * v + p2) * v + p1) * v * z;
+    r += k * r;
+    u2 = (r + z * k) + z;
+    u1 = 0.0625 * (double)(16 * m - p);
+    y1 = 0.0625 * (double)((int)(16.0 * y));
+    y2 = y - y1;
+    w = u2 * y + u1 * y2;
+    w1 = 0.0625 * (double)((int)(16.0 * w));
+    w2 = w - w1;
+    w = w1 + u1 * y1;
+    w1 = 0.0625 * (double)((int)(16.0 * w));
+    w2 += (w - w1);
+    w = 0.0625 * (double)((int)(16.0 * w2));
+    iw1 = 16.0 * (w1 + w);
+    w2 -= w;
+    while (w2 > 0.0)
+    {
+        iw1++;
+        w2 -= 0.0625;
+    }
+    if (iw1 > MAXEXP)
+    {
+        //cmemsg(FP_POWO, &y);
+        return (HUGE);
+    }
+    if (iw1 < MINEXP)
+    {
+        //cmemsg(FP_POWU, &y);
+        return (0.0);
+    }
+    m = iw1 / 16;
+    if (iw1 >= 0)
+        m++;
+    p = 16 * m - iw1;
+    z = ((((((q7 * w2 + q6) * w2 + q5) * w2 + q4) * w2 + q3) * w2 + q2) * w2 + q1) * w2;
+    z = a1[p] + a1[p] * z;
+    return (ldexp(z, m));
+}
+
 #if 0
 #ifndef __math_68881
-double atan(double x){
-	return x;
+double atan(double x)
+{
+    return x;
 }
-double cos(double x){
-	return x;
+double cos(double x)
+{
+    return x;
 }
-double sin(double x){
-	return x;
+double sin(double x)
+{
+    return x;
 }
-double tan(double x){
-	return x;
+double tan(double x)
+{
+    return x;
 }
-double tanh(double x){
-	return x;
+double tanh(double x)
+{
+    return x;
 }
-double frexp(double x, int *y){
-	return x;
+double frexp(double x, int *y)
+{
+    return x;
 }
-double modf(double x, double *y){
-	return x;
+double modf(double x, double *y)
+{
+    return x;
 }
-double ceil(double x){
-	return x;
+double ceil(double x)
+{
+    return x;
 }
-double fabs(double x){
-	return x;
+double fabs(double x)
+{
+    return x;
 }
-double floor(double x){
-	return x;
+double floor(double x)
+{
+    return x;
 }
 #endif /* ! defined (__math_68881) */
 
@@ -39,41 +174,53 @@ double floor(double x){
 
 #ifndef _REENT_ONLY
 #ifndef __math_68881
-double acos(double x){
-	return x;
+double acos(double x)
+{
+    return x;
 }
-double asin(double x){
-	return x;
+double asin(double x)
+{
+    return x;
 }
-double atan2(double x, double y){
-	return x;
+double atan2(double x, double y)
+{
+    return x;
 }
-double cosh(double x){
-	return x;
+double cosh(double x)
+{
+    return x;
 }
-double sinh(double x){
-	return x;
+double sinh(double x)
+{
+    return x;
 }
-double exp(double x){
-	return x;
+double exp(double x)
+{
+    return x;
 }
-double ldexp(double x, int y){
-	return x;
+double ldexp(double x, int y)
+{
+    return x;
 }
-double log(double x){
-	return x;
+double log(double x)
+{
+    return x;
 }
-double log10(double x){
-	return x;
+double log10(double x)
+{
+    return x;
 }
-double pow(double x, double y){
-	return x;
+double pow(double x, double y)
+{
+    return x;
 }
-double sqrt(double x){
-	return x;
+double sqrt(double x)
+{
+    return x;
 }
-double fmod(double x, double y){
-	return x;
+double fmod(double x, double y)
+{
+    return x;
 }
 #endif /* ! defined (__math_68881) */
 #endif /* ! defined (_REENT_ONLY) */

+ 4 - 0
app/libc/c_math.h

@@ -1,6 +1,10 @@
 #ifndef  _C_MATH_H_
 #define  _C_MATH_H_
 #include <math.h>
+
+double floor(double);
+double pow(double, double);
+
 #if 0
 #ifndef HUGE_VAL
   #define HUGE_VAL (1.0e99)

+ 438 - 13
app/libc/c_stdio.c

@@ -12,44 +12,469 @@ int c_stderr = 1001;
 // FILE *c_tmpfile(void){
 // }
 
-// int	c_putchar(int c){
+// int    c_putchar(int c){
 // }
 
-// int	c_printf(const char *c, ...){
+// int    c_printf(const char *c, ...){
 // }
 
 // int c_sprintf(char *c, const char *s, ...){
 // }
 
-// int	c_fprintf(FILE *f, const char *s, ...){
+// int    c_fprintf(FILE *f, const char *s, ...){
 // }
-// int	c_fscanf(FILE *f, const char *s, ...){
+// int    c_fscanf(FILE *f, const char *s, ...){
 // }
-// int	c_fclose(FILE *f){
+// int    c_fclose(FILE *f){
 // }
-// int	c_fflush(FILE *f){
+// int    c_fflush(FILE *f){
 // }
-// int	c_setvbuf(FILE *f, char *c, int d, size_t t){
+// int    c_setvbuf(FILE *f, char *c, int d, size_t t){
 // }
 // void c_clearerr(FILE *f){
 // }
-// int	c_fseek(FILE *f, long l, int d){
+// int    c_fseek(FILE *f, long l, int d){
 // }
 // long c_ftell( FILE *f){
 // }
-// int	c_fputs(const char *c, FILE *f){
+// int    c_fputs(const char *c, FILE *f){
 // }
 // char *c_fgets(char *c, int d, FILE *f){
 // }
-// int	c_ungetc(int d, FILE *f){
+// int    c_ungetc(int d, FILE *f){
 // }
 // size_t c_fread(void *p, size_t _size, size_t _n, FILE *f){
 // }
 // size_t c_fwrite(const void *p, size_t _size, size_t _n, FILE *f){
 // }
-// int	c_feof(FILE *f){
+// int    c_feof(FILE *f){
 // }
-// int	c_ferror(FILE *f){
+// int    c_ferror(FILE *f){
 // }
-// int	c_getc(FILE *f){
+// int    c_getc(FILE *f){
 // }
+
+#if defined( LUA_NUMBER_INTEGRAL )
+
+#else
+
+/*
+File: printf.c
+
+Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
+contributors may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them
+into your project.
+
+Two printf variants are provided: printf and sprintf.
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and
+compiler options, but a rough guestimate (based on a H8S target) is about
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
+Not too bad. Your milage may vary. By hacking the source code you can
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of
+functionality and flexibility versus  code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function,
+something like :
+
+void putc ( void* p, char c)
+    {
+    while (!SERIAL_PORT_EMPTY) ;
+    SERIAL_PORT_TX_REGISTER = c;
+    }
+
+Before you can call printf you need to initialize it to use your
+character output function with something like:
+
+init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be
+passed to your 'putc' routine. This allows you to pass some storage space (or
+anything realy) to the character output function, if necessary.
+This is not often needed but it was implemented like that because it made
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it
+is safe to call it from interupts too, although this may result in mixed output.
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file.
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+/*
+Add lightweight %g support by vowstar, <vowstar@gmail.com>
+NodeMCU Team, 26.1.2015
+*/
+
+typedef void (*putcf) (void *, char);
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static int uli2a(unsigned long int num, unsigned int base, int uc, char *bf)
+{
+    int n = 0;
+    unsigned long int d = 1;
+    int len = 1;
+    while (num / d >= base)
+    {
+        d *= base;
+        len ++;
+    }
+    while (d != 0)
+    {
+        int dgt = num / d;
+        num %= d;
+        d /= base;
+        if (n || dgt > 0 || d == 0)
+        {
+            *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
+            ++n;
+        }
+    }
+    *bf = 0;
+    return len;
+}
+
+static int li2a (long num, char *bf)
+{
+    int len = 0;
+    if (num < 0)
+    {
+        num = -num;
+        *bf++ = '-';
+        len ++;
+    }
+    len += uli2a(num, 10, 0, bf);
+    return len;
+}
+
+#endif
+
+static int ui2a(unsigned int num, unsigned int base, int uc, char *bf)
+{
+    int n = 0;
+    unsigned int d = 1;
+    int len = 1;
+    while (num / d >= base)
+    {
+        d *= base;
+        len ++;
+    }
+    while (d != 0)
+    {
+        int dgt = num / d;
+        num %= d;
+        d /= base;
+        if (n || dgt > 0 || d == 0)
+        {
+            *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);
+            ++n;
+        }
+    }
+    *bf = 0;
+    return len;
+}
+
+static int i2a (int num, char *bf)
+{
+    int len = 0;
+    if (num < 0)
+    {
+        num = -num;
+        *bf++ = '-';
+        len ++;
+    }
+    len += ui2a(num, 10, 0, bf);
+    return len;
+}
+
+// Converts a floating point number to string.
+static int d2a(double num, char *bf)
+{
+    int len = 0;
+    double ipart = 0;
+    double fpart = 0;
+    double absnum = num;
+
+    // Add sign
+    if (absnum < 0)
+    {
+        absnum = -absnum;
+        *bf++ = '-';
+        // len must add 1 when return
+        // but can't add at here
+    }
+
+    // Extract integer part
+    ipart = (int)absnum;
+
+    // Extract floating part
+    fpart = absnum - (double)ipart;
+
+    // convert integer part to string
+#ifdef  PRINTF_LONG_SUPPORT
+    len += li2a(ipart, bf);
+#else
+    len += i2a(ipart, bf);
+#endif
+
+#ifndef EPSILON
+#define EPSILON ((double)(0.00000001))
+#endif
+    if (fpart < EPSILON)
+    {
+        // fpart is zero
+    }
+    else
+    {
+        bf += len;
+        // add dot
+        *bf ++ = '.';
+        len += 1;
+        // add zero after dot
+        while (fpart < 0.1)
+        {
+            fpart *= 10;
+            *bf ++ = '0';
+            len += 1;
+        }
+        while ((fpart < (double)1.0 / EPSILON) && ((fpart - (int)fpart) > EPSILON))
+        {
+            fpart = fpart * 10;
+        }
+#ifdef  PRINTF_LONG_SUPPORT
+        len += li2a((int)fpart, bf);
+#else
+        len += i2a((int)fpart, bf);
+#endif
+    }
+#undef EPSILON
+    if (num < 0)
+    {
+        len ++;
+    }
+    return len;
+}
+
+static int a2d(char ch)
+{
+    if (ch >= '0' && ch <= '9')
+        return ch - '0';
+    else if (ch >= 'a' && ch <= 'f')
+        return ch - 'a' + 10;
+    else if (ch >= 'A' && ch <= 'F')
+        return ch - 'A' + 10;
+    else return -1;
+}
+
+static char a2i(char ch, char **src, int base, int *nump)
+{
+    char *p = *src;
+    int num = 0;
+    int digit;
+    while ((digit = a2d(ch)) >= 0)
+    {
+        if (digit > base) break;
+        num = num * base + digit;
+        ch = *p++;
+    }
+    *src = p;
+    *nump = num;
+    return ch;
+}
+
+static void putchw(void *putp, putcf putf, int n, char z, char *bf)
+{
+    char fc = z ? '0' : ' ';
+    char ch;
+    char *p = bf;
+    while (*p++ && n > 0)
+        n--;
+    while (n-- > 0)
+        putf(putp, fc);
+    while ((ch = *bf++))
+        putf(putp, ch);
+}
+
+void c_format(void *putp, putcf putf, char *fmt, va_list va)
+{
+    char bf[12];
+
+    char ch;
+
+
+    while ((ch = *(fmt++)))
+    {
+        if (ch != '%')
+            putf(putp, ch);
+        else
+        {
+            char lz = 0;
+#ifdef  PRINTF_LONG_SUPPORT
+            char lng = 0;
+#endif
+            int w = 0;
+            ch = *(fmt++);
+            if (ch == '0')
+            {
+                ch = *(fmt++);
+                lz = 1;
+            }
+            if (ch >= '0' && ch <= '9')
+            {
+                ch = a2i(ch, &fmt, 10, &w);
+            }
+#ifdef  PRINTF_LONG_SUPPORT
+            if (ch == 'l')
+            {
+                ch = *(fmt++);
+                lng = 1;
+            }
+#endif
+            switch (ch)
+            {
+            case 0:
+                goto abort;
+            case 'u' :
+            {
+#ifdef  PRINTF_LONG_SUPPORT
+                if (lng)
+                    uli2a(va_arg(va, unsigned long int), 10, 0, bf);
+                else
+#endif
+                    ui2a(va_arg(va, unsigned int), 10, 0, bf);
+                putchw(putp, putf, w, lz, bf);
+                break;
+            }
+            case 'o' :
+            {
+#ifdef  PRINTF_LONG_SUPPORT
+                if (lng)
+                    uli2a(va_arg(va, unsigned long int), 8, 0, bf);
+                else
+#endif
+                    ui2a(va_arg(va, unsigned int), 8, 0, bf);
+                putchw(putp, putf, w, lz, bf);
+                break;
+            }
+            case 'd' : case 'i':
+            {
+#ifdef  PRINTF_LONG_SUPPORT
+                if (lng)
+                    li2a(va_arg(va, unsigned long int), bf);
+                else
+#endif
+                    i2a(va_arg(va, int), bf);
+                putchw(putp, putf, w, lz, bf);
+                break;
+            }
+            case 'x': case 'X' :
+#ifdef  PRINTF_LONG_SUPPORT
+                if (lng)
+                    uli2a(va_arg(va, unsigned long int), 16, (ch == 'X'), bf);
+                else
+#endif
+                    ui2a(va_arg(va, unsigned int), 16, (ch == 'X'), bf);
+                putchw(putp, putf, w, lz, bf);
+                break;
+            case 'e':  case 'E': case 'f':
+            case 'g': case 'G':
+            {
+                d2a(va_arg(va, double), bf);
+                putchw(putp, putf, w, lz, bf);
+                break;
+            }
+            case 'c' :
+                putf(putp, (char)(va_arg(va, int)));
+                break;
+            case 's' :
+                putchw(putp, putf, w, 0, va_arg(va, char *));
+                break;
+            case '%' :
+                putf(putp, ch);
+            default:
+                break;
+            }
+        }
+    }
+abort:;
+}
+
+
+static void putcp(void *p, char c)
+{
+    *(*((char **)p))++ = c;
+}
+
+
+void c_sprintf(char *s, char *fmt, ...)
+{
+    va_list va;
+    va_start(va, fmt);
+    c_format(&s, putcp, fmt, va);
+    putcp(&s, 0);
+    va_end(va);
+}
+
+#endif

+ 10 - 0
app/libc/c_stdio.h

@@ -47,12 +47,22 @@ 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
+
 extern void output_redirect(const char *str);
 #define c_puts output_redirect
 
 // #define c_printf os_printf
 // int	c_printf(const char *c, ...);
+#if defined( LUA_NUMBER_INTEGRAL )
 #define c_sprintf os_sprintf
+#else
+#include "c_stdarg.h"
+void c_sprintf(char* s,char *fmt, ...);
+#endif
+
 // #define c_vsprintf ets_vsprintf
 #define c_printf(...) do {					\
 	unsigned char __print_buf[BUFSIZ];		\

+ 220 - 21
app/libc/c_stdlib.c

@@ -20,27 +20,27 @@ const char *c_getenv(const char *__string){
 }
 
 // make sure there is enough memory before real malloc, otherwise malloc will panic and reset
-void *c_malloc(size_t __size){
-	if(__size>system_get_free_heap_size()){
-		NODE_ERR("malloc: not enough memory\n");
-		return NULL;
-	}
-	return (void *)os_malloc(__size);
-}
+// void *c_malloc(size_t __size){
+// 	if(__size>system_get_free_heap_size()){
+// 		NODE_ERR("malloc: not enough memory\n");
+// 		return NULL;
+// 	}
+// 	return (void *)os_malloc(__size);
+// }
 
-void *c_zalloc(size_t __size){
-	if(__size>system_get_free_heap_size()){
-		NODE_ERR("zalloc: not enough memory\n");
-		return NULL;
-	}
-	return (void *)os_zalloc(__size);
-}
+// void *c_zalloc(size_t __size){
+// 	if(__size>system_get_free_heap_size()){
+// 		NODE_ERR("zalloc: not enough memory\n");
+// 		return NULL;
+// 	}
+// 	return (void *)os_zalloc(__size);
+// }
 
-void c_free(void *p){
-	// NODE_ERR("free1: %d\n", system_get_free_heap_size());
-	os_free(p);
-	// NODE_ERR("-free1: %d\n", system_get_free_heap_size());
-}
+// void c_free(void *p){
+// 	// NODE_ERR("free1: %d\n", system_get_free_heap_size());
+// 	os_free(p);
+// 	// NODE_ERR("-free1: %d\n", system_get_free_heap_size());
+// }
 
 
 // int	c_rand(void){
@@ -50,8 +50,207 @@ void c_free(void *p){
 
 // int	c_atoi(const char *__nptr){
 // }
-// double	c_strtod(const char *__n, char **__end_PTR){
-// }
+#include <_ansi.h>
+//#include <reent.h>
+#include <string.h>
+//#include "mprec.h"
+
+double c_strtod(const char *string, char **endPtr) 
+{
+	int maxExponent = 511;	/* Largest possible base 10 exponent.  Any
+				 * exponent larger than this will already
+				 * produce underflow or overflow, so there's
+				 * no need to worry about additional digits.
+				 */
+    double powersOf10[] = {	/* Table giving binary powers of 10.  Entry */
+    10.,			/* is 10^2^i.  Used to convert decimal */
+    100.,			/* exponents into floating-point numbers. */
+    1.0e4,
+    1.0e8,
+    1.0e16,
+    1.0e32,
+    1.0e64,
+    1.0e128,
+    1.0e256
+    };
+    int sign, expSign = FALSE;
+    double fraction, dblExp, *d;
+    register const char *p;
+    register int c;
+    int exp = 0;		/* Exponent read from "EX" field. */
+    int fracExp = 0;		/* Exponent that derives from the fractional
+				 * part.  Under normal circumstatnces, it is
+				 * the negative of the number of digits in F.
+				 * However, if I is very long, the last digits
+				 * of I get dropped (otherwise a long I with a
+				 * large negative exponent could cause an
+				 * unnecessary overflow on I alone).  In this
+				 * case, fracExp is incremented one for each
+				 * dropped digit. */
+    int mantSize;		/* Number of digits in mantissa. */
+    int decPt;			/* Number of mantissa digits BEFORE decimal
+				 * point. */
+    const char *pExp;		/* Temporarily holds location of exponent
+				 * in string. */
+
+    /*
+     * Strip off leading blanks and check for a sign.
+     */
+
+    p = string;
+    while (isspace((unsigned char)(*p))) {
+	p += 1;
+    }
+    if (*p == '-') {
+	sign = TRUE;
+	p += 1;
+    } else {
+	if (*p == '+') {
+	    p += 1;
+	}
+	sign = FALSE;
+    }
+
+    /*
+     * Count the number of digits in the mantissa (including the decimal
+     * point), and also locate the decimal point.
+     */
+
+    decPt = -1;
+    for (mantSize = 0; ; mantSize += 1)
+    {
+	c = *p;
+	if (!isdigit(c)) {
+	    if ((c != '.') || (decPt >= 0)) {
+		break;
+	    }
+	    decPt = mantSize;
+	}
+	p += 1;
+    }
+
+    /*
+     * Now suck up the digits in the mantissa.  Use two integers to
+     * collect 9 digits each (this is faster than using floating-point).
+     * If the mantissa has more than 18 digits, ignore the extras, since
+     * they can't affect the value anyway.
+     */
+    
+    pExp  = p;
+    p -= mantSize;
+    if (decPt < 0) {
+	decPt = mantSize;
+    } else {
+	mantSize -= 1;			/* One of the digits was the point. */
+    }
+    if (mantSize > 18) {
+	fracExp = decPt - 18;
+	mantSize = 18;
+    } else {
+	fracExp = decPt - mantSize;
+    }
+    if (mantSize == 0) {
+	fraction = 0.0;
+	p = string;
+	goto done;
+    } else {
+	int frac1, frac2;
+	frac1 = 0;
+	for ( ; mantSize > 9; mantSize -= 1)
+	{
+	    c = *p;
+	    p += 1;
+	    if (c == '.') {
+		c = *p;
+		p += 1;
+	    }
+	    frac1 = 10*frac1 + (c - '0');
+	}
+	frac2 = 0;
+	for (; mantSize > 0; mantSize -= 1)
+	{
+	    c = *p;
+	    p += 1;
+	    if (c == '.') {
+		c = *p;
+		p += 1;
+	    }
+	    frac2 = 10*frac2 + (c - '0');
+	}
+	fraction = (1.0e9 * frac1) + frac2;
+    }
+
+    /*
+     * Skim off the exponent.
+     */
+
+    p = pExp;
+    if ((*p == 'E') || (*p == 'e')) {
+	p += 1;
+	if (*p == '-') {
+	    expSign = TRUE;
+	    p += 1;
+	} else {
+	    if (*p == '+') {
+		p += 1;
+	    }
+	    expSign = FALSE;
+	}
+	if (!isdigit((unsigned char)(*p))) {
+	    p = pExp;
+	    goto done;
+	}
+	while (isdigit((unsigned char)(*p))) {
+	    exp = exp * 10 + (*p - '0');
+	    p += 1;
+	}
+    }
+    if (expSign) {
+	exp = fracExp - exp;
+    } else {
+	exp = fracExp + exp;
+    }
+
+    /*
+     * Generate a floating-point number that represents the exponent.
+     * Do this by processing the exponent one bit at a time to combine
+     * many powers of 2 of 10. Then combine the exponent with the
+     * fraction.
+     */
+    
+    if (exp < 0) {
+	expSign = TRUE;
+	exp = -exp;
+    } else {
+	expSign = FALSE;
+    }
+    if (exp > maxExponent) {
+	exp = maxExponent;
+	// errno = ERANGE;
+    }
+    dblExp = 1.0;
+    for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
+	if (exp & 01) {
+	    dblExp *= *d;
+	}
+    }
+    if (expSign) {
+	fraction /= dblExp;
+    } else {
+	fraction *= dblExp;
+    }
+
+done:
+    if (endPtr != NULL) {
+	*endPtr = (char *) p;
+    }
+
+    if (sign) {
+	return -fraction;
+    }
+    return fraction;
+}
+
 // long	c_strtol(const char *__n, char **__end_PTR, int __base){
 // }
 // unsigned long c_strtoul(const char *__n, char **__end_PTR, int __base){

+ 2 - 2
app/libc/c_stdlib.h

@@ -36,7 +36,7 @@
 
 #define c_abs	abs
 #define c_atoi	atoi
-// #define c_strtod	strtod
+//#define c_strtod	strtod
 #define c_strtol	strtol
 #define c_strtoul	strtoul
 
@@ -55,7 +55,7 @@ void c_free(void *);
 // void c_srand(unsigned int __seed);
 
 // int	c_atoi(const char *__nptr);
-// double	c_strtod(const char *__n, char **__end_PTR);
+double	c_strtod(const char *__n, char **__end_PTR);
 // // long	c_strtol(const char *__n, char **__end_PTR, int __base);
 // unsigned long c_strtoul(const char *__n, char **__end_PTR, int __base);
 // // long long c_strtoll(const char *__n, char **__end_PTR, int __base);

+ 2 - 1
app/lua/luaconf.h

@@ -601,7 +601,8 @@ extern int readline4lua(const char *prompt, char *buffer, int length);
   #endif // #if !defined LUA_INTEGRAL_LONGLONG
 #else
 #define LUA_NUMBER_SCAN		"%lf"
-#define LUA_NUMBER_FMT		"%.14g"
+//#define LUA_NUMBER_FMT		"%.14g"
+#define LUA_NUMBER_FMT		"%g"
 #endif // #if defined LUA_NUMBER_INTEGRAL
 #define lua_number2str(s,n)	c_sprintf((s), LUA_NUMBER_FMT, (n))
 #define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */

+ 1 - 2
app/lua/lundump.c

@@ -5,6 +5,7 @@
 */
 
 #include "c_string.h"
+#include "c_types.h"
 
 #define lundump_c
 #define LUA_CORE
@@ -141,13 +142,11 @@ static lua_Number LoadNumber(LoadState* S)
     LoadVar(S,y);
     x = (lua_Number)y;
    } break;
-#if 0
    case 8: {
     int64_t y;
     LoadVar(S,y);
     x = (lua_Number)y;
    } break;
-#endif
    default: lua_assert(0);
   }
  }

+ 1 - 0
app/lua/lvm.c

@@ -8,6 +8,7 @@
 #include "c_stdio.h"
 #include "c_stdlib.h"
 #include "c_string.h"
+#include "c_math.h"
 
 #define lvm_c
 #define LUA_CORE

+ 0 - 4
app/lwip/app/espconn_tcp.c

@@ -812,10 +812,6 @@ espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err)
     remot_info *pinfo = NULL;
     LWIP_UNUSED_ARG(err);
 
-    if(4096>system_get_free_heap_size()){
-    	return ERR_MEM;
-    }
-
     paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
     tcp_arg(pcb, paccept);
 	tcp_err(pcb, esponn_server_err);

+ 1 - 0
app/modules/Makefile

@@ -39,6 +39,7 @@ endif
 INCLUDES := $(INCLUDES) -I $(PDIR)include
 INCLUDES += -I ./
 INCLUDES += -I ../libc
+INCLUDES += -I ../mqtt
 INCLUDES += -I ../lua
 INCLUDES += -I ../platform
 INCLUDES += -I ../wofs

+ 3 - 0
app/modules/auxmods.h

@@ -61,6 +61,9 @@ LUALIB_API int ( luaopen_i2c )( lua_State *L );
 #define AUXLIB_WIFI      "wifi"
 LUALIB_API int ( luaopen_wifi )( lua_State *L );
 
+#define AUXLIB_MQTT      "mqtt"
+LUALIB_API int ( luaopen_mqtt )( lua_State *L );
+
 #define AUXLIB_NODE      "node"
 LUALIB_API int ( luaopen_node )( lua_State *L );
 

+ 18 - 0
app/modules/modules.h

@@ -37,6 +37,14 @@
 #define ROM_MODULES_NET
 #endif
 
+#if defined(LUA_USE_MODULES_MQTT)
+#define MODULES_MQTT       "mqtt"
+#define ROM_MODULES_MQTT   \
+    _ROM(MODULES_MQTT, luaopen_mqtt, mqtt_map)
+#else
+#define ROM_MODULES_MQTT
+#endif
+
 #if defined(LUA_USE_MODULES_I2C)
 #define MODULES_I2C       "i2c"
 #define ROM_MODULES_I2C   \
@@ -45,6 +53,14 @@
 #define ROM_MODULES_I2C
 #endif
 
+#if defined(LUA_USE_MODULES_SPI)
+#define MODULES_SPI       "spi"
+#define ROM_MODULES_SPI   \
+    _ROM(MODULES_SPI, luaopen_spi, spi_map)
+#else
+#define ROM_MODULES_SPI
+#endif
+
 #if defined(LUA_USE_MODULES_TMR)
 #define MODULES_TMR       "tmr"
 #define ROM_MODULES_TMR   \
@@ -105,7 +121,9 @@
         ROM_MODULES_GPIO    \
         ROM_MODULES_PWM		\
         ROM_MODULES_WIFI	\
+		ROM_MODULES_MQTT    \
         ROM_MODULES_I2C     \
+        ROM_MODULES_SPI     \
         ROM_MODULES_TMR     \
         ROM_MODULES_NODE    \
         ROM_MODULES_FILE    \

+ 1051 - 0
app/modules/mqtt.c

@@ -0,0 +1,1051 @@
+// Module for mqtt
+
+//#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+#include "platform.h"
+#include "auxmods.h"
+#include "lrotable.h"
+
+#include "c_string.h"
+#include "c_stdlib.h"
+
+#include "c_types.h"
+#include "mem.h"
+#include "espconn.h"
+
+#include "mqtt_msg.h"
+
+static lua_State *gL = NULL;
+
+#define MQTT_BUF_SIZE 1024
+#define MQTT_DEFAULT_KEEPALIVE 60
+#define MQTT_MAX_CLIENT_LEN   64
+#define MQTT_MAX_USER_LEN     64
+#define MQTT_MAX_PASS_LEN     64
+#define MQTT_SEND_TIMEOUT			5
+
+typedef enum {
+  MQTT_INIT,
+  MQTT_CONNECT_SEND,
+  MQTT_CONNECT_SENDING,
+  MQTT_DATA
+} tConnState;
+
+typedef struct mqtt_event_data_t
+{
+  uint8_t type;
+  const char* topic;
+  const char* data;
+  uint16_t topic_length;
+  uint16_t data_length;
+  uint16_t data_offset;
+} mqtt_event_data_t;
+
+typedef struct mqtt_state_t
+{
+  uint16_t port;
+  int auto_reconnect;
+  mqtt_connect_info_t* connect_info;
+  uint8_t* in_buffer;
+  uint8_t* out_buffer;
+  int in_buffer_length;
+  int out_buffer_length;
+  uint16_t message_length;
+  uint16_t message_length_read;
+  mqtt_message_t* outbound_message;
+  mqtt_connection_t mqtt_connection;
+
+  uint16_t pending_msg_id;
+  int pending_msg_type;
+  int pending_publish_qos;
+} mqtt_state_t;
+
+typedef struct lmqtt_userdata
+{
+  struct espconn *pesp_conn;
+  int self_ref;
+  int cb_connect_ref;
+  int cb_disconnect_ref;
+  int cb_message_ref;
+  int cb_suback_ref;
+  int cb_puback_ref;
+  mqtt_state_t  mqtt_state;
+  mqtt_connect_info_t connect_info;
+  uint32_t keep_alive_tick;
+  uint32_t send_timeout;
+  uint8_t secure;
+  uint8_t connected;
+  ETSTimer mqttTimer;
+  tConnState connState;
+}lmqtt_userdata;
+
+static void mqtt_socket_disconnected(void *arg)    // tcp only
+{
+  NODE_DBG("mqtt_socket_disconnected is called.\n");
+  struct espconn *pesp_conn = arg;
+  if(pesp_conn == NULL)
+    return;
+  lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse;
+  if(mud == NULL)
+    return;
+  if(mud->cb_disconnect_ref != LUA_NOREF && mud->self_ref != LUA_NOREF)
+  {
+    lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_disconnect_ref);
+    lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref);  // pass the userdata(client) to callback func in lua
+    lua_call(gL, 1, 0);
+  }
+  mud->connected = 0;
+  os_timer_disarm(&mud->mqttTimer);
+
+  if(pesp_conn->proto.tcp)
+    c_free(pesp_conn->proto.tcp);
+  pesp_conn->proto.tcp = NULL;
+  if(mud->pesp_conn)
+    c_free(mud->pesp_conn);
+  mud->pesp_conn = NULL;  // espconn is already disconnected
+  lua_gc(gL, LUA_GCSTOP, 0);
+  if(mud->self_ref != LUA_NOREF){
+    luaL_unref(gL, LUA_REGISTRYINDEX, mud->self_ref);
+    mud->self_ref = LUA_NOREF; // unref this, and the mqtt.socket userdata will delete it self
+  }
+  lua_gc(gL, LUA_GCRESTART, 0);
+}
+
+static void mqtt_socket_reconnected(void *arg, sint8_t err)
+{
+  NODE_DBG("mqtt_socket_reconnected is called.\n");
+  mqtt_socket_disconnected(arg);
+}
+
+static void deliver_publish(lmqtt_userdata * mud, uint8_t* message, int length)
+{
+  const char comma[] = ",";
+  mqtt_event_data_t event_data;
+
+  event_data.topic_length = length;
+  event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length);
+
+  event_data.data_length = length;
+  event_data.data = mqtt_get_publish_data(message, &event_data.data_length);
+
+  if(mud->cb_message_ref == LUA_NOREF)
+    return;
+  if(mud->self_ref == LUA_NOREF)
+    return;
+  lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_message_ref);
+  lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref);  // pass the userdata to callback func in lua
+  // expose_array(gL, pdata, len);
+  // *(pdata+len) = 0;
+  // NODE_DBG(pdata);
+  // NODE_DBG("\n");
+  lua_pushlstring(gL, event_data.topic, event_data.topic_length);
+  if(event_data.data_length > 0){
+    lua_pushlstring(gL, event_data.data, event_data.data_length);
+    lua_call(gL, 3, 0);
+  } else {
+    lua_call(gL, 2, 0);
+  }
+}
+
+static void mqtt_socket_received(void *arg, char *pdata, unsigned short len)
+{
+  NODE_DBG("mqtt_socket_received is called.\n");
+
+  uint8_t msg_type;
+  uint8_t msg_qos;
+  uint16_t msg_id;
+
+  struct espconn *pesp_conn = arg;
+  if(pesp_conn == NULL)
+    return;
+  lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse;
+  if(mud == NULL)
+    return;
+
+READPACKET:
+  if(len > MQTT_BUF_SIZE && len <= 0)
+	  return;
+
+  c_memcpy(mud->mqtt_state.in_buffer, pdata, len);
+  mud->mqtt_state.outbound_message = NULL;
+  switch(mud->connState){
+    case MQTT_CONNECT_SENDING:
+      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){
+          espconn_secure_disconnect(pesp_conn);
+        }
+        else {
+          espconn_disconnect(pesp_conn);
+        }
+      } else {
+        mud->connState = MQTT_DATA;
+        NODE_DBG("MQTT: Connected\r\n");
+        if(mud->cb_connect_ref == LUA_NOREF)
+          return;
+        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;
+
+    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);
+
+      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);
+      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)
+            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);
+          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)
+            NODE_DBG("MQTT: UnSubscribe successful\r\n");
+          break;
+        case MQTT_MSG_TYPE_PUBLISH:
+          if(msg_qos == 1)
+            mud->mqtt_state.outbound_message = mqtt_msg_puback(&mud->mqtt_state.mqtt_connection, msg_id);
+          else if(msg_qos == 2)
+            mud->mqtt_state.outbound_message = mqtt_msg_pubrec(&mud->mqtt_state.mqtt_connection, msg_id);
+
+          deliver_publish(mud, mud->mqtt_state.in_buffer, mud->mqtt_state.message_length_read);
+          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){
+            NODE_DBG("MQTT: Publish with QoS = 1 successful\r\n");
+            if(mud->cb_puback_ref == LUA_NOREF)
+              break;
+            if(mud->self_ref == LUA_NOREF)
+              break;
+            lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+            lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref);  // pass the userdata to callback func in lua
+            lua_call(gL, 1, 0);
+          }
+
+          break;
+        case MQTT_MSG_TYPE_PUBREC:
+            mud->mqtt_state.outbound_message = mqtt_msg_pubrel(&mud->mqtt_state.mqtt_connection, msg_id);
+            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_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){
+            NODE_DBG("MQTT: Publish  with QoS = 2 successful\r\n");
+            if(mud->cb_puback_ref == LUA_NOREF)
+              break;
+            if(mud->self_ref == LUA_NOREF)
+              break;
+            lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+            lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref);  // pass the userdata to callback func in lua
+            lua_call(gL, 1, 0);
+          }
+          break;
+        case MQTT_MSG_TYPE_PINGREQ:
+            mud->mqtt_state.outbound_message = mqtt_msg_pingresp(&mud->mqtt_state.mqtt_connection);
+          break;
+        case MQTT_MSG_TYPE_PINGRESP:
+          // Ignore
+          break;
+      }
+      // NOTE: this is done down here and not in the switch case above
+      // because the PSOCK_READBUF_LEN() won't work inside a switch
+      // statement due to the way protothreads resume.
+      if(msg_type == MQTT_MSG_TYPE_PUBLISH)
+      {
+
+        len = mud->mqtt_state.message_length_read;
+
+        if(mud->mqtt_state.message_length < mud->mqtt_state.message_length_read)
+				{
+					len -= mud->mqtt_state.message_length;
+					pdata += mud->mqtt_state.message_length;
+
+					NODE_DBG("Get another published message\r\n");
+					goto 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);
+    else
+      espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
+    mud->mqtt_state.outbound_message = NULL;
+  }
+  return;
+}
+
+static void mqtt_socket_sent(void *arg)
+{
+  // NODE_DBG("mqtt_socket_sent is called.\n");
+  struct espconn *pesp_conn = arg;
+  if(pesp_conn == NULL)
+    return;
+  lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse;
+  if(mud == NULL)
+    return;
+  if(!mud->connected)
+  	return;
+  // call mqtt_sent()
+  mud->send_timeout = 0;
+  if(mud->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && mud->mqtt_state.pending_publish_qos == 0) {
+  	if(mud->cb_puback_ref == LUA_NOREF)
+			return;
+		if(mud->self_ref == LUA_NOREF)
+			return;
+		lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+		lua_rawgeti(gL, LUA_REGISTRYINDEX, mud->self_ref);  // pass the userdata to callback func in lua
+		lua_call(gL, 1, 0);
+  }
+}
+
+static int mqtt_socket_client( lua_State* L );
+static void mqtt_socket_connected(void *arg)
+{
+  NODE_DBG("mqtt_socket_connected is called.\n");
+  struct espconn *pesp_conn = arg;
+  if(pesp_conn == NULL)
+    return;
+  lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse;
+  if(mud == NULL)
+    return;
+  mud->connected = true;
+  espconn_regist_recvcb(pesp_conn, mqtt_socket_received);
+  espconn_regist_sentcb(pesp_conn, mqtt_socket_sent);
+  espconn_regist_disconcb(pesp_conn, mqtt_socket_disconnected);
+
+  // call mqtt_connect() to start a mqtt connect stage.
+  mqtt_msg_init(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.out_buffer, mud->mqtt_state.out_buffer_length);
+  mud->mqtt_state.outbound_message = mqtt_msg_connect(&mud->mqtt_state.mqtt_connection, mud->mqtt_state.connect_info);
+  NODE_DBG("Send MQTT connection infomation, data len: %d, d[0]=%d \r\n", mud->mqtt_state.outbound_message->length,  mud->mqtt_state.outbound_message->data[0]);
+  if(mud->secure){
+    espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
+  }
+  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;
+  return;
+}
+
+void mqtt_socket_timer(void *arg)
+{
+  lmqtt_userdata *mud = (lmqtt_userdata*) arg;
+
+  if(mud->connState == MQTT_DATA){
+    mud->keep_alive_tick ++;
+    if(mud->keep_alive_tick > mud->mqtt_state.connect_info->keepalive){
+      mud->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ;
+      mud->send_timeout = MQTT_SEND_TIMEOUT;
+      NODE_DBG("\r\nMQTT: Send keepalive packet\r\n");
+      mud->mqtt_state.outbound_message = mqtt_msg_pingreq(&mud->mqtt_state.mqtt_connection);
+
+      if(mud->secure)
+        espconn_secure_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
+      else
+        espconn_sent(mud->pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
+      mud->keep_alive_tick = 0;
+    }
+  }
+  if(mud->send_timeout > 0)
+  	mud->send_timeout --;
+}
+
+// Lua: mqtt.Client(clientid, keepalive, user, pass)
+static int mqtt_socket_client( lua_State* L )
+{
+  NODE_DBG("mqtt_socket_client is called.\n");
+
+  lmqtt_userdata *mud;
+  char tempid[20] = {0};
+  c_sprintf(tempid, "%s%x", "NodeMCU_", system_get_chip_id() );
+  NODE_DBG(tempid);
+  NODE_DBG("\n");
+  size_t il = c_strlen(tempid);
+  const char *clientId = tempid, *username = NULL, *password = NULL;
+  int stack = 1;
+  unsigned secure = 0;
+  int top = lua_gettop(L);
+
+  // create a object
+  mud = (lmqtt_userdata *)lua_newuserdata(L, sizeof(lmqtt_userdata));
+  // pre-initialize it, in case of errors
+  mud->self_ref = LUA_NOREF;
+  mud->cb_connect_ref = LUA_NOREF;
+  mud->cb_disconnect_ref = LUA_NOREF;
+
+  mud->cb_message_ref = LUA_NOREF;
+  mud->cb_suback_ref = LUA_NOREF;
+  mud->cb_puback_ref = LUA_NOREF;
+  mud->pesp_conn = NULL;
+  mud->secure = 0;
+
+  mud->keep_alive_tick = 0;
+  mud->send_timeout = 0;
+  mud->connState = MQTT_INIT;
+  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));
+
+  // set its metatable
+  luaL_getmetatable(L, "mqtt.socket");
+  lua_setmetatable(L, -2);
+
+  if( lua_isstring(L,stack) )   // deal with the clientid string
+  {
+    clientId = luaL_checklstring( L, stack, &il );
+    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);
+    stack++;
+  }
+
+  if(mud->connect_info.keepalive == 0){
+    mud->connect_info.keepalive = MQTT_DEFAULT_KEEPALIVE;
+    return 1;
+  }
+
+  if(lua_isstring( L, stack )){
+    username = luaL_checklstring( L, stack, &il );
+    stack++;
+  }
+  if(username == NULL)
+    return 1;
+  mud->connect_info.username = (uint8_t *)c_zalloc(il + 1);
+  if(!mud->connect_info.username){
+		return luaL_error(L, "not enough memory");
+	}
+
+  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 );
+    stack++;
+  }
+  if(password == NULL)
+    return 1;
+  mud->connect_info.password = (uint8_t *)c_zalloc(il + 1);
+  if(!mud->connect_info.password){
+		return luaL_error(L, "not enough memory");
+	}
+
+  c_memcpy(mud->connect_info.password, password, il);
+  mud->connect_info.password[il] = 0;
+  
+  NODE_DBG("MQTT: Init info: %s, %s, %s\r\n", mud->connect_info.client_id, mud->connect_info.username, mud->connect_info.password);
+
+  return 1;
+}
+
+// Lua: mqtt.delete( socket )
+// call close() first
+// socket: unref everything
+static int mqtt_delete( lua_State* L )
+{
+  NODE_DBG("mqtt_delete is called.\n");
+
+  lmqtt_userdata *mud = (lmqtt_userdata *)luaL_checkudata(L, 1, "mqtt.socket");
+  luaL_argcheck(L, mud, 1, "mqtt.socket expected");
+  if(mud==NULL){
+    NODE_DBG("userdata is nil.\n");
+    return 0;
+  }
+
+  os_timer_disarm(&mud->mqttTimer);
+  mud->connected = 0;
+  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)
+      c_free(mud->pesp_conn->proto.tcp);
+    mud->pesp_conn->proto.tcp = NULL;
+    c_free(mud->pesp_conn);
+    mud->pesp_conn = NULL;    // for socket, it will free this when disconnected
+  }
+
+  if(mud->connect_info.will_topic){
+  	c_free(mud->connect_info.client_id);
+  }
+
+  if(mud->connect_info.will_message){
+    	c_free(mud->connect_info.will_message);
+    }
+
+  if(mud->connect_info.client_id)
+    c_free(mud->connect_info.client_id);
+  if(mud->connect_info.username)
+    c_free(mud->connect_info.username);
+  if(mud->connect_info.password)
+    c_free(mud->connect_info.password);
+  if(mud->mqtt_state.in_buffer)
+    c_free(mud->mqtt_state.in_buffer);
+  if(mud->mqtt_state.out_buffer)
+    c_free(mud->mqtt_state.out_buffer);
+
+  // free (unref) callback ref
+  if(LUA_NOREF!=mud->cb_connect_ref){
+    luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref);
+    mud->cb_connect_ref = LUA_NOREF;
+  }
+  if(LUA_NOREF!=mud->cb_disconnect_ref){
+    luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_disconnect_ref);
+    mud->cb_disconnect_ref = LUA_NOREF;
+  }
+  if(LUA_NOREF!=mud->cb_message_ref){
+    luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_message_ref);
+    mud->cb_message_ref = LUA_NOREF;
+  }
+  if(LUA_NOREF!=mud->cb_suback_ref){
+    luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_suback_ref);
+    mud->cb_suback_ref = LUA_NOREF;
+  }
+  if(LUA_NOREF!=mud->cb_puback_ref){
+    luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+    mud->cb_puback_ref = LUA_NOREF;
+  }
+  lua_gc(gL, 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);
+  return 0;  
+}
+
+static void socket_connect(struct espconn *pesp_conn)
+{
+  if(pesp_conn == NULL)
+    return;
+  lmqtt_userdata *mud = (lmqtt_userdata *)pesp_conn->reverse;
+  if(mud == NULL)
+    return;
+
+  if(mud->secure){
+    espconn_secure_connect(pesp_conn);
+  }
+  else
+  {
+    espconn_connect(pesp_conn);
+  }
+  
+  NODE_DBG("socket_connect is called.\n");
+}
+
+static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg);
+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");
+  struct espconn *pesp_conn = arg;
+  if(pesp_conn == NULL){
+    NODE_DBG("pesp_conn null.\n");
+    return;
+  }
+
+  if(ipaddr == NULL)
+  {
+    dns_reconn_count++;
+    if( dns_reconn_count >= 5 ){
+      NODE_ERR( "DNS Fail!\n" );
+      // Note: should delete the pesp_conn or unref self_ref here.
+      mqtt_socket_disconnected(arg);   // although not connected, but fire disconnect callback to release every thing.
+      return;
+    }
+    NODE_ERR( "DNS retry %d!\n", dns_reconn_count );
+    host_ip.addr = 0;
+    espconn_gethostbyname(pesp_conn, name, &host_ip, socket_dns_found);
+    return;
+  }
+
+  // ipaddr->addr is a uint32_t ip
+  if(ipaddr->addr != 0)
+  {
+    dns_reconn_count = 0;
+    c_memcpy(pesp_conn->proto.tcp->remote_ip, &(ipaddr->addr), 4);
+    NODE_DBG("TCP ip is set: ");
+    NODE_DBG(IPSTR, IP2STR(&(ipaddr->addr)));
+    NODE_DBG("\n");
+    socket_connect(pesp_conn);
+  }
+}
+
+// Lua: mqtt:connect( host, port, secure, function(client) )
+static int mqtt_socket_lwt( lua_State* L )
+{
+	uint8_t stack = 1;
+	size_t topicSize, il;
+  NODE_DBG("mqtt_socket_lwt.\n");
+  lmqtt_userdata *mud = NULL;
+  const char *lwtTopic, *lwtMsg;
+  uint8_t lwtQoS, lwtRetain;
+
+  mud = (lmqtt_userdata *)luaL_checkudata( L, stack, "mqtt.socket" );
+  luaL_argcheck( L, mud, stack, "mqtt.socket expected" );
+
+  if(mud == NULL)
+    return 0;
+
+  stack++;
+  lwtTopic = luaL_checklstring( L, stack, &topicSize );
+	if (lwtTopic == NULL)
+	{
+		return luaL_error( L, "need lwt topic");
+	}
+
+	stack++;
+	lwtMsg = luaL_checklstring( L, stack, &il );
+	if (lwtMsg == NULL)
+	{
+		return luaL_error( L, "need lwt topic");
+	}
+
+	mud->connect_info.will_topic = (uint8_t*) c_zalloc( topicSize + 1 );
+	if(!mud->connect_info.will_topic){
+		return luaL_error( L, "not enough memory");
+	}
+	c_memcpy(mud->connect_info.will_topic, lwtTopic, topicSize);
+	mud->connect_info.will_topic[topicSize] = 0;
+
+	mud->connect_info.will_message = (uint8_t*) c_zalloc( il + 1 );
+	if(!mud->connect_info.will_message){
+		return luaL_error( L, "not enough memory");
+	}
+	c_memcpy(mud->connect_info.will_message, lwtMsg, il);
+	mud->connect_info.will_message[il] = 0;
+
+
+	stack++;
+	mud->connect_info.will_qos = luaL_checkinteger( L, stack );
+
+	stack++;
+	mud->connect_info.will_retain = luaL_checkinteger( L, stack );
+
+	NODE_DBG("mqtt_socket_lwt: topic: %s, message: %s, qos: %d, retain: %d\n",
+			mud->connect_info.will_topic,
+			mud->connect_info.will_message,
+			mud->connect_info.will_qos,
+			mud->connect_info.will_retain);
+  return 0;
+}
+
+// Lua: mqtt:connect( host, port, secure, function(client) )
+static int mqtt_socket_connect( lua_State* L )
+{
+  NODE_DBG("mqtt_socket_connect is called.\n");
+  lmqtt_userdata *mud = NULL;
+  unsigned port = 1883;
+  size_t il;
+  ip_addr_t ipaddr;
+  const char *domain;
+  int stack = 1;
+  unsigned secure = 0;
+  int top = lua_gettop(L);
+
+  mud = (lmqtt_userdata *)luaL_checkudata(L, stack, "mqtt.socket");
+  luaL_argcheck(L, mud, stack, "mqtt.socket expected");
+  stack++;
+  if(mud == NULL)
+    return 0;
+
+  if(mud->pesp_conn)
+    	c_free(mud->pesp_conn);
+  struct espconn *pesp_conn = NULL;
+	pesp_conn = mud->pesp_conn = (struct espconn *)c_zalloc(sizeof(struct espconn));
+	if(!pesp_conn)
+		return luaL_error(L, "not enough memory");
+
+	pesp_conn->proto.udp = NULL;
+	pesp_conn->proto.tcp = (esp_tcp *)c_zalloc(sizeof(esp_tcp));
+	if(!pesp_conn->proto.tcp){
+		c_free(pesp_conn);
+		pesp_conn = mud->pesp_conn = NULL;
+		return luaL_error(L, "not enough memory");
+	}
+	// reverse is for the callback function
+	pesp_conn->reverse = mud;
+	pesp_conn->type = ESPCONN_TCP;
+	pesp_conn->state = ESPCONN_NONE;
+  mud->connected = 0;
+
+  if( (stack<=top) && lua_isstring(L,stack) )   // deal with the domain string
+  {
+    domain = luaL_checklstring( L, stack, &il );
+
+    stack++;
+    if (domain == NULL)
+    {
+      domain = "127.0.0.1";
+    }
+    ipaddr.addr = ipaddr_addr(domain);
+    c_memcpy(pesp_conn->proto.tcp->remote_ip, &ipaddr.addr, 4);
+    NODE_DBG("TCP ip is set: ");
+    NODE_DBG(IPSTR, IP2STR(&ipaddr.addr));
+    NODE_DBG("\n");
+  }
+
+  if ( (stack<=top) && lua_isnumber(L, stack) )
+  {
+    port = lua_tointeger(L, stack);
+    stack++;
+    NODE_DBG("TCP port is set: %d.\n", port);
+  }
+  pesp_conn->proto.tcp->remote_port = port;
+  pesp_conn->proto.tcp->local_port = espconn_port();
+
+  if ( (stack<=top) && lua_isnumber(L, stack) )
+  {
+    secure = lua_tointeger(L, stack);
+    stack++;
+    if ( secure != 0 && secure != 1 ){
+      secure = 0; // default to 0
+    }
+  } else {
+    secure = 0; // default to 0
+  }
+  mud->secure = secure; // save
+
+  // 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
+    if(mud->cb_connect_ref != LUA_NOREF)
+      luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref);
+    mud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+    stack++;
+  }
+
+  lua_pushvalue(L, 1);  // copy userdata to the top of stack
+  if(mud->self_ref != LUA_NOREF)
+    luaL_unref(L, LUA_REGISTRYINDEX, mud->self_ref);
+  mud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+  espconn_regist_connectcb(pesp_conn, mqtt_socket_connected);
+  espconn_regist_reconcb(pesp_conn, mqtt_socket_reconnected);
+
+  if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0))
+  {
+    host_ip.addr = 0;
+    dns_reconn_count = 0;
+    if(ESPCONN_OK == espconn_gethostbyname(pesp_conn, domain, &host_ip, socket_dns_found)){
+      socket_dns_found(domain, &host_ip, pesp_conn);  // ip is returned in host_ip.
+    }
+  }
+  else
+  {
+    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);
+
+  return 0;
+}
+
+// Lua: mqtt:close()
+// client disconnect and unref itself
+static int mqtt_socket_close( lua_State* L )
+{
+  NODE_DBG("mqtt_socket_close is called.\n");
+  int i = 0;
+  lmqtt_userdata *mud = NULL;
+
+  mud = (lmqtt_userdata *)luaL_checkudata(L, 1, "mqtt.socket");
+  luaL_argcheck(L, mud, 1, "mqtt.socket expected");
+  if(mud == NULL)
+    return 0;
+
+  if(mud->pesp_conn == NULL)
+    return 0;
+
+  // call mqtt_disconnect()
+
+  if(mud->secure){
+    if(mud->pesp_conn->proto.tcp->remote_port || mud->pesp_conn->proto.tcp->local_port)
+      espconn_secure_disconnect(mud->pesp_conn);
+  }
+  else
+  {
+    if(mud->pesp_conn->proto.tcp->remote_port || mud->pesp_conn->proto.tcp->local_port)
+      espconn_disconnect(mud->pesp_conn);
+  }
+  return 0;  
+}
+
+// Lua: mqtt:on( "method", function() )
+static int mqtt_socket_on( lua_State* L )
+{
+  NODE_DBG("mqtt_on is called.\n");
+  lmqtt_userdata *mud;
+  size_t sl;
+
+  mud = (lmqtt_userdata *)luaL_checkudata(L, 1, "mqtt.socket");
+  luaL_argcheck(L, mud, 1, "mqtt.socket expected");
+  if(mud==NULL){
+    NODE_DBG("userdata is nil.\n");
+    return 0;
+  }
+
+  const char *method = luaL_checklstring( L, 2, &sl );
+  if (method == NULL)
+    return luaL_error( L, "wrong arg type" );
+
+  luaL_checkanyfunction(L, 3);
+  lua_pushvalue(L, 3);  // copy argument (func) to the top of stack
+
+  if( sl == 7 && c_strcmp(method, "connect") == 0){
+    if(mud->cb_connect_ref != LUA_NOREF)
+      luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_connect_ref);
+    mud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+  }else if( sl == 7 && c_strcmp(method, "offline") == 0){
+    if(mud->cb_disconnect_ref != LUA_NOREF)
+      luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_disconnect_ref);
+    mud->cb_disconnect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+  }else if( sl == 7 && c_strcmp(method, "message") == 0){
+    if(mud->cb_message_ref != LUA_NOREF)
+      luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_message_ref);
+    mud->cb_message_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+  }else{
+    lua_pop(L, 1);
+    return luaL_error( L, "method not supported" );
+  }
+
+  return 0;
+}
+
+// Lua: mqtt:subscribe(topic, qos, function())
+static int mqtt_socket_subscribe( lua_State* L )
+{
+  NODE_DBG("mqtt_socket_subscribe is called.\n");
+  uint8_t stack = 1, qos = 0, retain = 0;
+  const char *topic;
+  size_t il;
+  lmqtt_userdata *mud;
+
+  mud = (lmqtt_userdata *)luaL_checkudata(L, stack, "mqtt.socket");
+  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");
+
+  topic = luaL_checklstring( L, stack, &il );
+  stack++;
+  if(topic == NULL)
+    return luaL_error( L, "need topic name" );
+  
+  qos = luaL_checkinteger( L, stack);
+  stack++;
+
+  mud->mqtt_state.outbound_message =  mqtt_msg_subscribe(&mud->mqtt_state.mqtt_connection,
+                                                          topic, qos,
+                                                          &mud->mqtt_state.pending_msg_id);
+  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){
+    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(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);
+  
+  return 0;
+}
+
+// Lua: mqtt:publish( topic, payload, qos, retain, function() )
+static int mqtt_socket_publish( lua_State* L )
+{
+  // NODE_DBG("mqtt_publish is called.\n");
+  struct espconn *pesp_conn = NULL;
+  lmqtt_userdata *mud;
+  size_t l;
+  uint8_t stack = 1;
+  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;
+  }
+
+  if(mud->pesp_conn == NULL){
+    NODE_DBG("mud->pesp_conn is NULL.\n");
+    return 0;
+  }
+  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" );
+
+  const char *payload = luaL_checklstring( L, stack, &l );
+  stack ++;
+  uint8_t qos = luaL_checkinteger( L, stack);
+  stack ++;
+  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;
+  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)
+      luaL_unref(L, LUA_REGISTRYINDEX, mud->cb_puback_ref);
+    mud->cb_puback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+  }
+
+  if(mud->secure)
+    espconn_secure_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
+  else
+    espconn_sent(pesp_conn, mud->mqtt_state.outbound_message->data, mud->mqtt_state.outbound_message->length);
+  mud->mqtt_state.outbound_message = NULL;
+  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( "on" ), LFUNCVAL ( mqtt_socket_on ) },
+  { LSTRKEY( "__gc" ), LFUNCVAL ( mqtt_delete ) },
+#if LUA_OPTIMIZE_MEMORY > 0
+  { LSTRKEY( "__index" ), LROVAL ( mqtt_socket_map ) },
+#endif
+  { LNILKEY, LNILVAL }
+};
+
+const LUA_REG_TYPE mqtt_map[] = 
+{
+  { LSTRKEY( "Client" ), LFUNCVAL ( mqtt_socket_client ) },
+#if LUA_OPTIMIZE_MEMORY > 0
+
+  { LSTRKEY( "__metatable" ), LROVAL( mqtt_map ) },
+#endif
+  { LNILKEY, LNILVAL }
+};
+
+LUALIB_API int ICACHE_FLASH_ATTR luaopen_mqtt( lua_State *L )
+{
+#if LUA_OPTIMIZE_MEMORY > 0
+  luaL_rometatable(L, "mqtt.socket", (void *)mqtt_socket_map);  // create metatable for mqtt.socket
+  return 0;
+#else // #if LUA_OPTIMIZE_MEMORY > 0
+  int n;
+  luaL_register( L, AUXLIB_MQTT, mqtt_map );
+
+  // Set it as its own metatable
+  lua_pushvalue( L, -1 );
+  lua_setmetatable( L, -2 );
+
+  // Module constants  
+  // MOD_REG_NUMBER( L, "TCP", TCP );
+
+  // create metatable
+  luaL_newmetatable(L, "mqtt.socket");
+  // metatable.__index = metatable
+  lua_pushliteral(L, "__index");
+  lua_pushvalue(L,-2);
+  lua_rawset(L,-3);
+  // Setup the methods inside metatable
+  luaL_register( L, NULL, mqtt_socket_map );
+
+  return 1;
+#endif // #if LUA_OPTIMIZE_MEMORY > 0  
+}

+ 6 - 2
app/modules/net.c

@@ -672,16 +672,20 @@ static int net_start( lua_State* L, const char* mt )
   {
     if(isserver)
       pesp_conn->proto.tcp->local_port = port;
-    else
+    else{
       pesp_conn->proto.tcp->remote_port = port;
+      pesp_conn->proto.tcp->local_port = espconn_port();
+    }
     NODE_DBG("TCP port is set: %d.\n", port);
   }
   else if (pesp_conn->type == ESPCONN_UDP)
   {
     if(isserver)
       pesp_conn->proto.udp->local_port = port;
-    else
+    else{
       pesp_conn->proto.udp->remote_port = port;
+      pesp_conn->proto.udp->local_port = espconn_port();
+    }
     NODE_DBG("UDP port is set: %d.\n", port);
   }
 

+ 47 - 7
app/modules/node.c

@@ -11,7 +11,8 @@
 #include "romfs.h"
 #include "c_string.h"
 #include "driver/uart.h"
-#include "spi_flash.h"
+//#include "spi_flash.h"
+#include "user_interface.h"
 #include "flash_api.h"
 
 // Lua: restart()
@@ -21,18 +22,47 @@ static int node_restart( lua_State* L )
   return 0;  
 }
 
-// Lua: dsleep( us )
+// Lua: dsleep( us, option )
 static int node_deepsleep( lua_State* L )
 {
-  s32 us;
-  us = luaL_checkinteger( L, 1 );
-  if ( us <= 0 )
-    return luaL_error( L, "wrong arg range" );
-  system_deep_sleep( us );
+  s32 us, option;
+  //us = luaL_checkinteger( L, 1 );
+  // Set deleep option, skip if nil
+  if ( lua_isnumber(L, 2) )
+  {
+    option = lua_tointeger(L, 2);
+    if ( option < 0 || option > 4)
+      return luaL_error( L, "wrong arg range" );
+    else
+      deep_sleep_set_option( option );
+  }
+  // Set deleep time, skip if nil
+  if ( lua_isnumber(L, 1) )
+  {
+    us = lua_tointeger(L, 1);
+    // if ( us <= 0 )
+    if ( us < 0 )
+      return luaL_error( L, "wrong arg range" );
+    else
+      system_deep_sleep( us );
+  }
   return 0;  
 }
 
+// Lua: dsleep_set_options
+// Combined to dsleep( us, option )
+// static int node_deepsleep_setoption( lua_State* L )
+// {
+//   s32 option;
+//   option = luaL_checkinteger( L, 1 );
+//   if ( option < 0 || option > 4)
+//     return luaL_error( L, "wrong arg range" );
+//   else
+//    deep_sleep_set_option( option );
+//   return 0;
+// }
 // Lua: info()
+
 static int node_info( lua_State* L )
 {
   lua_pushinteger(L, NODE_VERSION_MAJOR);
@@ -53,6 +83,13 @@ static int node_chipid( lua_State* L )
   lua_pushinteger(L, id);
   return 1;  
 }
+// Lua: readvdd33()
+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 )
@@ -287,6 +324,9 @@ const LUA_REG_TYPE node_map[] =
   { LSTRKEY( "led" ), LFUNCVAL( node_led ) },
   { LSTRKEY( "input" ), LFUNCVAL( node_input ) },
   { LSTRKEY( "output" ), LFUNCVAL( node_output ) },
+  { LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) },
+// Combined to dsleep(us, option)  
+// { LSTRKEY( "dsleepsetoption" ), LFUNCVAL( node_deepsleep_setoption) },
 #if LUA_OPTIMIZE_MEMORY > 0
 
 #endif

+ 166 - 0
app/modules/spi.c

@@ -0,0 +1,166 @@
+// Module for interfacing with the SPI interface
+
+//#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+#include "platform.h"
+#include "auxmods.h"
+#include "lrotable.h"
+
+// Lua: = spi.setup( id, mode, cpol, cpha, databits, clock )
+static int spi_setup( lua_State *L )
+{
+  unsigned id = luaL_checkinteger( L, 1 );
+  unsigned mode = luaL_checkinteger( L, 2 );
+  unsigned cpol = luaL_checkinteger( L, 3 );
+  unsigned cpha = luaL_checkinteger( L, 4 );
+  unsigned databits = luaL_checkinteger( L, 5 );
+  uint32_t clock = luaL_checkinteger( L, 6 );
+
+  MOD_CHECK_ID( spi, id );
+
+  if (mode != PLATFORM_SPI_SLAVE && mode != PLATFORM_SPI_MASTER) {
+    return luaL_error( L, "wrong arg type" );
+  }
+
+  if (cpol != PLATFORM_SPI_CPOL_LOW && cpol != PLATFORM_SPI_CPOL_HIGH) {
+    return luaL_error( L, "wrong arg type" );
+  }
+
+  if (cpha != PLATFORM_SPI_CPHA_LOW && cpha != PLATFORM_SPI_CPHA_HIGH) {
+    return luaL_error( L, "wrong arg type" );
+  }
+
+  if (databits != PLATFORM_SPI_DATABITS_8 && databits != PLATFORM_SPI_DATABITS_16) {
+    return luaL_error( L, "wrong arg type" );
+  }
+
+  u32 res = platform_spi_setup(id, mode, cpol, cpha, databits, clock);
+  lua_pushinteger( L, res );
+  return 1;
+}
+
+// Lua: wrote = spi.send( id, data1, [data2], ..., [datan] )
+// data can be either a string, a table or an 8-bit number
+static int spi_send( lua_State *L )
+{
+  unsigned id = luaL_checkinteger( L, 1 );
+  const char *pdata;
+  size_t datalen, i;
+  int numdata;
+  u32 wrote = 0;
+  unsigned argn;
+
+  MOD_CHECK_ID( spi, id );
+  if( lua_gettop( L ) < 2 )
+    return luaL_error( L, "wrong arg type" );
+
+  for( argn = 2; argn <= lua_gettop( L ); argn ++ )
+  {
+    // lua_isnumber() would silently convert a string of digits to an integer
+    // whereas here strings are handled separately.
+    if( lua_type( L, argn ) == LUA_TNUMBER )
+    {
+      numdata = ( int )luaL_checkinteger( L, argn );
+      if( numdata < 0 || numdata > 255 )
+        return luaL_error( L, "wrong arg range" );
+      platform_spi_send_recv( id, numdata );
+      wrote ++;
+    }
+    else if( lua_istable( L, argn ) )
+    {
+      datalen = lua_objlen( L, argn );
+      for( i = 0; i < datalen; i ++ )
+      {
+        lua_rawgeti( L, argn, i + 1 );
+        numdata = ( int )luaL_checkinteger( L, -1 );
+        lua_pop( L, 1 );
+        if( numdata < 0 || numdata > 255 )
+          return luaL_error( L, "wrong arg range" );
+        platform_spi_send_recv( id, numdata );
+      }
+      wrote += i;
+      if( i < datalen )
+        break;
+    }
+    else
+    {
+      pdata = luaL_checklstring( L, argn, &datalen );
+      for( i = 0; i < datalen; i ++ )
+        platform_spi_send_recv( id, pdata[ i ] );
+      wrote += i;
+      if( i < datalen )
+        break;
+    }
+  }
+
+  lua_pushinteger( L, wrote );
+  return 1;
+}
+
+// Lua: read = spi.recv( id, size )
+static int spi_recv( lua_State *L )
+{
+  unsigned id = luaL_checkinteger( L, 1 );
+  u32 size = ( u32 )luaL_checkinteger( L, 2 ), i;
+
+  luaL_Buffer b;
+  spi_data_type data;
+
+  MOD_CHECK_ID( spi, id );
+  if (size == 0) {
+    return 0;
+  }
+
+  luaL_buffinit( L, &b );
+  for (i=0; i<size; i++) {
+    data = platform_spi_send_recv(id, 0xFF);
+    luaL_addchar( &b, ( char )data);
+  }
+
+  luaL_pushresult( &b );
+  return 1;
+}
+
+// Module function map
+#define MIN_OPT_LEVEL   2
+#include "lrodefs.h"
+const LUA_REG_TYPE spi_map[] = 
+{
+  { LSTRKEY( "setup" ),  LFUNCVAL( spi_setup ) },
+  { LSTRKEY( "send" ),   LFUNCVAL( spi_send ) },
+  { LSTRKEY( "recv" ),   LFUNCVAL( spi_recv ) },
+#if LUA_OPTIMIZE_MEMORY > 0
+  { LSTRKEY( "MASTER" ),    LNUMVAL( PLATFORM_SPI_MASTER ) },
+  { LSTRKEY( "SLAVE" ),     LNUMVAL( PLATFORM_SPI_SLAVE) },
+  { LSTRKEY( "CPHA_LOW" ),  LNUMVAL( PLATFORM_SPI_CPHA_LOW) },
+  { LSTRKEY( "CPHA_HIGH" ), LNUMVAL( PLATFORM_SPI_CPHA_HIGH) },
+  { LSTRKEY( "CPOL_LOW" ),  LNUMVAL( PLATFORM_SPI_CPOL_LOW) },
+  { LSTRKEY( "CPOL_HIGH" ), LNUMVAL( PLATFORM_SPI_CPOL_HIGH) },
+  { LSTRKEY( "DATABITS_8" ), LNUMVAL( PLATFORM_SPI_DATABITS_8) },
+  { LSTRKEY( "DATABITS_16" ), LNUMVAL( PLATFORM_SPI_DATABITS_16) },
+#endif // #if LUA_OPTIMIZE_MEMORY > 0
+  { LNILKEY, LNILVAL }
+};
+
+LUALIB_API int luaopen_spi( lua_State *L )
+{
+#if LUA_OPTIMIZE_MEMORY > 0
+  return 0;
+#else // #if LUA_OPTIMIZE_MEMORY > 0
+  luaL_register( L, AUXLIB_SPI, spi_map );
+  
+  // Add constants
+  MOD_REG_NUMBER( L, "MASTER",  PLATFORM_SPI_MASTER);
+  MOD_REG_NUMBER( L, "SLAVE",   PLATFORM_SPI_SLAVE);
+  MOD_REG_NUMBER( L, "CPHA_LOW" , PLATFORM_SPI_CPHA_LOW);
+  MOD_REG_NUMBER( L, "CPHA_HIGH", PLATFORM_SPI_CPHA_HIGH);
+  MOD_REG_NUMBER( L, "CPOL_LOW" , PLATFORM_SPI_CPOL_LOW);
+  MOD_REG_NUMBER( L, "CPOL_HIGH", PLATFORM_SPI_CPOL_HIGH);
+  MOD_REG_NUMBER( L, "DATABITS_8" , PLATFORM_SPI_DATABITS_8);
+  MOD_REG_NUMBER( L, "DATABITS_16" , PLATFORM_SPI_DATABITS_16);
+
+  return 1;
+#endif // #if LUA_OPTIMIZE_MEMORY > 0
+}
+

+ 22 - 6
app/modules/tmr.c

@@ -147,14 +147,26 @@ static int tmr_wdclr( lua_State* L )
   return 0;  
 }
 
-// Lua: time() , return rtc time in us
+static os_timer_t rtc_timer_updator;
+static uint64_t cur_count = 0;
+static uint64_t rtc_us = 0;
+void rtc_timer_update_cb(void *arg){
+  uint64_t t = (uint64_t)system_get_rtc_time();
+  uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count);
+  // NODE_ERR("%x\n",t);
+  cur_count = t;
+  unsigned c = system_rtc_clock_cali_proc();
+  uint64_t itg = c >> 12;
+  uint64_t dec = c & 0xFFF;
+  rtc_us += (delta*itg + ((delta*dec)>>12));
+  // TODO: store rtc_us to rtc memory.
+}
+// Lua: time() , return rtc time in second
 static int tmr_time( lua_State* L )
 {
-  unsigned t = 0xFFFFFFFF & system_get_rtc_time();
-  unsigned c = 0xFFFFFFFF & system_rtc_clock_cali_proc();
-  lua_pushinteger( L, t );
-  lua_pushinteger( L, c );
-  return 2; 
+  uint64_t local = rtc_us;
+  lua_pushinteger( L, ((uint32_t)(local/1000000)) & 0x7FFFFFFF );
+  return 1; 
 }
 
 // Module function map
@@ -182,6 +194,10 @@ LUALIB_API int luaopen_tmr( lua_State *L )
     os_timer_setfn(&(alarm_timer[i]), (os_timer_func_t *)(alarm_timer_cb[i]), L);
   }
 
+  os_timer_disarm(&rtc_timer_updator);
+  os_timer_setfn(&rtc_timer_updator, (os_timer_func_t *)(rtc_timer_update_cb), NULL);
+  os_timer_arm(&rtc_timer_updator, 500, 1); 
+
 #if LUA_OPTIMIZE_MEMORY > 0
   return 0;
 #else // #if LUA_OPTIMIZE_MEMORY > 0

+ 12 - 1
app/modules/wifi.c

@@ -12,6 +12,7 @@
 #include "c_types.h"
 #include "user_interface.h"
 #include "smart.h"
+#include "smartconfig.h"
 
 static int wifi_smart_succeed = LUA_NOREF;
 
@@ -19,6 +20,13 @@ static void wifi_smart_succeed_cb(void *arg){
   NODE_DBG("wifi_smart_succeed_cb is called.\n");
   if( !arg )
     return;
+#if 0
+  struct station_config *sta_conf = arg;
+  wifi_station_set_config(sta_conf);
+  wifi_station_disconnect();
+  wifi_station_connect();
+  smartconfig_stop();
+#endif
   if(wifi_smart_succeed == LUA_NOREF)
     return;
   lua_State* L = (lua_State *)arg;
@@ -81,6 +89,7 @@ static void wifi_scan_done(void *arg, STATUS status)
 }
 
 // Lua: smart(channel, function succeed_cb)
+// Lua: smart(type, function succeed_cb)
 static int wifi_start_smart( lua_State* L )
 {
   unsigned channel;
@@ -109,13 +118,15 @@ static int wifi_start_smart( lua_State* L )
   }else{
     smart_begin(channel, (smart_succeed )wifi_smart_succeed_cb, L);
   }
+  // smartconfig_start(0, wifi_smart_succeed_cb);
   return 0;  
 }
 
-// Lua: exit_smart(channel)
+// Lua: exit_smart()
 static int wifi_exit_smart( lua_State* L )
 {
   smart_end();
+  // smartconfig_stop();
   if(wifi_smart_succeed != LUA_NOREF)
     luaL_unref(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
   wifi_smart_succeed = LUA_NOREF;

+ 44 - 0
app/mqtt/Makefile

@@ -0,0 +1,44 @@
+
+#############################################################
+# Required variables for each makefile
+# Discard this section from all parent makefiles
+# Expected variables (with automatic defaults):
+#   CSRCS (all "C" files in the dir)
+#   SUBDIRS (all subdirs with a Makefile)
+#   GEN_LIBS - list of libs to be generated ()
+#   GEN_IMAGES - list of images to be generated ()
+#   COMPONENTS_xxx - a list of libs/objs in the form
+#     subdir/lib to be extracted and rolled up into
+#     a generated lib/image xxx.a ()
+#
+ifndef PDIR
+GEN_LIBS = mqtt.a
+endif
+
+#############################################################
+# Configuration i.e. compile options etc.
+# Target specific stuff (defines etc.) goes in here!
+# Generally values applying to a tree are captured in the
+#   makefile at its root level - these are then overridden
+#   for a subtree within the makefile rooted therein
+#
+#DEFINES += 
+
+#############################################################
+# Recursion Magic - Don't touch this!!
+#
+# Each subtree potentially has an include directory
+#   corresponding to the common APIs applicable to modules
+#   rooted at that subtree. Accordingly, the INCLUDE PATH
+#   of a module can only contain the include directories up
+#   its parent path, and not its siblings
+#
+# Required for each makefile to inherit from the parent
+#
+
+INCLUDES := $(INCLUDES) -I $(PDIR)include
+INCLUDES += -I ./
+INCLUDES += -I ../libc
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+

+ 457 - 0
app/mqtt/mqtt_msg.c

@@ -0,0 +1,457 @@
+/*
+* Copyright (c) 2014, Stephen Robinson
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include <string.h>
+#include "mqtt_msg.h"
+
+#define MQTT_MAX_FIXED_HEADER_SIZE 3
+
+enum mqtt_connect_flag
+{
+  MQTT_CONNECT_FLAG_USERNAME = 1 << 7,
+  MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,
+  MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,
+  MQTT_CONNECT_FLAG_WILL = 1 << 2,
+  MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1
+};
+
+struct __attribute((__packed__)) mqtt_connect_variable_header
+{
+  uint8_t lengthMsb;
+  uint8_t lengthLsb;
+  uint8_t magic[6];
+  uint8_t version;
+  uint8_t flags;
+  uint8_t keepaliveMsb;
+  uint8_t keepaliveLsb;
+};
+
+static int append_string(mqtt_connection_t* connection, const char* string, int len)
+{
+  if(connection->message.length + len + 2 > connection->buffer_length)
+    return -1;
+
+  connection->buffer[connection->message.length++] = len >> 8;
+  connection->buffer[connection->message.length++] = len & 0xff;
+  memcpy(connection->buffer + connection->message.length, string, len);
+  connection->message.length += len;
+
+  return len + 2;
+}
+
+static uint16_t append_message_id(mqtt_connection_t* connection, uint16_t message_id)
+{
+  // If message_id is zero then we should assign one, otherwise
+  // we'll use the one supplied by the caller
+  while(message_id == 0)
+    message_id = ++connection->message_id;
+
+  if(connection->message.length + 2 > connection->buffer_length)
+    return 0;
+
+  connection->buffer[connection->message.length++] = message_id >> 8;
+  connection->buffer[connection->message.length++] = message_id & 0xff;
+
+  return message_id;
+}
+
+static int init_message(mqtt_connection_t* connection)
+{
+  connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE;
+  return MQTT_MAX_FIXED_HEADER_SIZE;
+}
+
+static mqtt_message_t* fail_message(mqtt_connection_t* connection)
+{
+  connection->message.data = connection->buffer;
+  connection->message.length = 0;
+  return &connection->message;
+}
+
+static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain)
+{
+  int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;
+
+  if(remaining_length > 127)
+  {
+    connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
+    connection->buffer[1] = 0x80 | (remaining_length % 128);
+    connection->buffer[2] = remaining_length / 128;
+    connection->message.length = remaining_length + 3;
+    connection->message.data = connection->buffer;
+  }
+  else
+  {
+    connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
+    connection->buffer[2] = remaining_length;
+    connection->message.length = remaining_length + 2;
+    connection->message.data = connection->buffer + 1;
+  }
+
+  return &connection->message;
+}
+
+void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length)
+{
+  memset(connection, 0, sizeof(connection));
+  connection->buffer = buffer;
+  connection->buffer_length = buffer_length;
+}
+
+int mqtt_get_total_length(uint8_t* buffer, uint16_t length)
+{
+  int i;
+  int totlen = 0;
+
+  for(i = 1; i < length; ++i)
+  {
+    totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
+    if((buffer[i] & 0x80) == 0)
+    {
+      ++i;
+      break;
+    }
+  }
+  totlen += i;
+
+  return totlen;
+}
+
+const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
+{
+  int i;
+  int totlen = 0;
+  int topiclen;
+
+  for(i = 1; i < *length; ++i)
+  {
+    totlen += (buffer[i] & 0x7f) << (7 * (i -1));
+    if((buffer[i] & 0x80) == 0)
+    {
+      ++i;
+      break;
+    }
+  }
+  totlen += i;
+
+  if(i + 2 >= *length)
+    return NULL;
+  topiclen = buffer[i++] << 8;
+  topiclen |= buffer[i++];
+
+  if(i + topiclen > *length)
+    return NULL;
+
+  *length = topiclen;
+  return (const char*)(buffer + i);
+}
+
+const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
+{
+  int i;
+  int totlen = 0;
+  int topiclen;
+
+  for(i = 1; i < *length; ++i)
+  {
+    totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
+    if((buffer[i] & 0x80) == 0)
+    {
+      ++i;
+      break;
+    }
+  }
+  totlen += i;
+
+  if(i + 2 >= *length)
+    return NULL;
+  topiclen = buffer[i++] << 8;
+  topiclen |= buffer[i++];
+
+  if(i + topiclen >= *length){
+	*length = 0;
+    return NULL;
+  }
+  i += topiclen;
+
+  if(mqtt_get_qos(buffer) > 0)
+  {
+    if(i + 2 >= *length)
+      return NULL;
+    i += 2;
+  }
+
+  if(totlen < i)
+    return NULL;
+
+  if(totlen <= *length)
+    *length = totlen - i;
+  else
+    *length = *length - i;
+  return (const char*)(buffer + i);
+}
+
+uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length)
+{
+  if(length < 1)
+    return 0;
+
+  switch(mqtt_get_type(buffer))
+  {
+    case MQTT_MSG_TYPE_PUBLISH:
+    {
+      int i;
+      int topiclen;
+
+      for(i = 1; i < length; ++i)
+      {
+        if((buffer[i] & 0x80) == 0)
+        {
+          ++i;
+          break;
+        }
+      }
+
+      if(i + 2 >= length)
+        return 0;
+      topiclen = buffer[i++] << 8;
+      topiclen |= buffer[i++];
+
+      if(i + topiclen >= length)
+        return 0;
+      i += topiclen;
+
+      if(mqtt_get_qos(buffer) > 0)
+      {
+        if(i + 2 >= length)
+          return 0;
+        //i += 2;
+      } else {
+    	  return 0;
+      }
+
+      return (buffer[i] << 8) | buffer[i + 1];
+    }
+    case MQTT_MSG_TYPE_PUBACK:
+    case MQTT_MSG_TYPE_PUBREC:
+    case MQTT_MSG_TYPE_PUBREL:
+    case MQTT_MSG_TYPE_PUBCOMP:
+    case MQTT_MSG_TYPE_SUBACK:
+    case MQTT_MSG_TYPE_UNSUBACK:
+    case MQTT_MSG_TYPE_SUBSCRIBE:
+    {
+      // This requires the remaining length to be encoded in 1 byte,
+      // which it should be.
+      if(length >= 4 && (buffer[1] & 0x80) == 0)
+        return (buffer[2] << 8) | buffer[3];
+      else
+        return 0;
+    }
+
+    default:
+      return 0;
+  }
+}
+
+mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info)
+{
+  struct mqtt_connect_variable_header* variable_header;
+
+  init_message(connection);
+
+  if(connection->message.length + sizeof(*variable_header) > connection->buffer_length)
+    return fail_message(connection);
+  variable_header = (void*)(connection->buffer + connection->message.length);
+  connection->message.length += sizeof(*variable_header);
+
+  variable_header->lengthMsb = 0;
+  variable_header->lengthLsb = 6;
+  memcpy(variable_header->magic, "MQIsdp", 6);
+  variable_header->version = 3;
+  variable_header->flags = 0;
+  variable_header->keepaliveMsb = info->keepalive >> 8;
+  variable_header->keepaliveLsb = info->keepalive & 0xff;
+
+  if(info->clean_session)
+    variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;
+
+  if(info->client_id != NULL && info->client_id[0] != '\0')
+  {
+    if(append_string(connection, info->client_id, strlen(info->client_id)) < 0)
+      return fail_message(connection);
+  }
+  else
+    return fail_message(connection);
+
+  if(info->will_topic != NULL && info->will_topic[0] != '\0')
+  {
+    if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0)
+      return fail_message(connection);
+
+    if(append_string(connection, info->will_message, strlen(info->will_message)) < 0)
+      return fail_message(connection);
+
+    variable_header->flags |= MQTT_CONNECT_FLAG_WILL;
+    if(info->will_retain)
+      variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;
+    variable_header->flags |= (info->will_qos & 3) << 4;
+  }
+
+  if(info->username != NULL && info->username[0] != '\0')
+  {
+    if(append_string(connection, info->username, strlen(info->username)) < 0)
+      return fail_message(connection);
+
+    variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;
+  }
+
+  if(info->password != NULL && info->password[0] != '\0')
+  {
+    if(append_string(connection, info->password, strlen(info->password)) < 0)
+      return fail_message(connection);
+
+    variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;
+  }
+
+  return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);
+}
+
+mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id)
+{
+  init_message(connection);
+
+  if(topic == NULL || topic[0] == '\0')
+    return fail_message(connection);
+
+  if(append_string(connection, topic, strlen(topic)) < 0)
+    return fail_message(connection);
+
+  if(qos > 0)
+  {
+    if((*message_id = append_message_id(connection, 0)) == 0)
+      return fail_message(connection);
+  }
+  else
+    *message_id = 0;
+
+  if(connection->message.length + data_length > connection->buffer_length)
+    return fail_message(connection);
+  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);
+}
+
+mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if(append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);
+}
+
+mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if(append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);
+}
+
+mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if(append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);
+}
+
+mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if(append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
+}
+
+mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)
+{
+  init_message(connection);
+
+  if(topic == NULL || topic[0] == '\0')
+    return fail_message(connection);
+
+  if((*message_id = append_message_id(connection, 0)) == 0)
+    return fail_message(connection);
+
+  if(append_string(connection, topic, strlen(topic)) < 0)
+    return fail_message(connection);
+
+  if(connection->message.length + 1 > connection->buffer_length)
+    return fail_message(connection);
+  connection->buffer[connection->message.length++] = qos;
+
+  return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
+}
+
+mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
+{
+  init_message(connection);
+
+  if(topic == NULL || topic[0] == '\0')
+    return fail_message(connection);
+
+  if((*message_id = append_message_id(connection, 0)) == 0)
+    return fail_message(connection);
+
+  if(append_string(connection, topic, strlen(topic)) < 0)
+    return fail_message(connection);
+
+  return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
+}
+
+mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection)
+{
+  init_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);
+}
+
+mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection)
+{
+  init_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);
+}
+
+mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection)
+{
+  init_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);
+}

+ 129 - 0
app/mqtt/mqtt_msg.h

@@ -0,0 +1,129 @@
+/* 
+ * File:   mqtt_msg.h
+ * Author: Minh Tuan
+ *
+ * Created on July 12, 2014, 1:05 PM
+ */
+
+#ifndef MQTT_MSG_H
+#define	MQTT_MSG_H
+#include "c_types.h"
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+* Copyright (c) 2014, Stephen Robinson
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+/* 7			6			5			4			3			2			1			0*/
+/*|      --- Message Type----			|  DUP Flag	|	   QoS Level		|	Retain	|
+/*										Remaining Length								 */
+
+
+enum mqtt_message_type
+{
+  MQTT_MSG_TYPE_CONNECT = 1,
+  MQTT_MSG_TYPE_CONNACK = 2,
+  MQTT_MSG_TYPE_PUBLISH = 3,
+  MQTT_MSG_TYPE_PUBACK = 4,
+  MQTT_MSG_TYPE_PUBREC = 5,
+  MQTT_MSG_TYPE_PUBREL = 6,
+  MQTT_MSG_TYPE_PUBCOMP = 7,
+  MQTT_MSG_TYPE_SUBSCRIBE = 8,
+  MQTT_MSG_TYPE_SUBACK = 9,
+  MQTT_MSG_TYPE_UNSUBSCRIBE = 10,
+  MQTT_MSG_TYPE_UNSUBACK = 11,
+  MQTT_MSG_TYPE_PINGREQ = 12,
+  MQTT_MSG_TYPE_PINGRESP = 13,
+  MQTT_MSG_TYPE_DISCONNECT = 14
+};
+
+typedef struct mqtt_message
+{
+  uint8_t* data;
+  uint16_t length;
+
+} mqtt_message_t;
+
+typedef struct mqtt_connection
+{
+  mqtt_message_t message;
+
+  uint16_t message_id;
+  uint8_t* buffer;
+  uint16_t buffer_length;
+
+} mqtt_connection_t;
+
+typedef struct mqtt_connect_info
+{
+  char* client_id;
+  char* username;
+  char* password;
+  char* will_topic;
+  char* will_message;
+  int keepalive;
+  int will_qos;
+  int will_retain;
+  int clean_session;
+
+} mqtt_connect_info_t;
+
+
+static inline int mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
+static inline int mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
+static inline int mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
+static inline int mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
+
+void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
+int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
+const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
+const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
+uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length);
+
+mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
+mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
+mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id);
+mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id);
+mqtt_message_t* mqtt_msg_pingreq(mqtt_connection_t* connection);
+mqtt_message_t* mqtt_msg_pingresp(mqtt_connection_t* connection);
+mqtt_message_t* mqtt_msg_disconnect(mqtt_connection_t* connection);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* MQTT_MSG_H */
+

+ 1 - 1
app/platform/cpu_esp8266.h

@@ -8,7 +8,7 @@
 #include "flash_api.h"
 // Number of resources (0 if not available/not implemented)
 #define NUM_GPIO              GPIO_PIN_NUM
-#define NUM_SPI               1
+#define NUM_SPI               2
 #define NUM_UART              1
 #define NUM_PWM               GPIO_PIN_NUM
 #define NUM_ADC               1

+ 16 - 2
app/platform/platform.c

@@ -129,11 +129,11 @@ int platform_gpio_read( unsigned pin )
     return -1;
 
   if(pin == 0){
-    gpio16_input_conf();
+    // gpio16_input_conf();
     return 0x1 & gpio16_input_get();
   }
 
-  GPIO_DIS_OUTPUT(pin_num[pin]);
+  // GPIO_DIS_OUTPUT(pin_num[pin]);
   return 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[pin]));
 }
 
@@ -435,6 +435,20 @@ int platform_i2c_recv_byte( unsigned id, int ack ){
   return r;
 }
 
+// *****************************************************************************
+// SPI platform interface
+uint32_t platform_spi_setup( unsigned id, int mode, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock)
+{
+  spi_master_init(id, cpol, cpha, databits, clock);
+  return 1;
+}
+
+spi_data_type platform_spi_send_recv( unsigned id, spi_data_type data )
+{
+  spi_mast_byte_write(id, &data);
+  return data;
+}
+
 // ****************************************************************************
 // Flash access functions
 

+ 11 - 1
app/platform/platform.h

@@ -84,13 +84,23 @@ int platform_can_recv( unsigned id, uint32_t *canid, uint8_t *idtype, uint8_t *l
 // SPI enable/disable
 #define PLATFORM_SPI_ENABLE                   1
 #define PLATFORM_SPI_DISABLE                  0
+// SPI clock phase
+#define PLATFORM_SPI_CPHA_LOW                 0
+#define PLATFORM_SPI_CPHA_HIGH                1
+// SPI clock polarity
+#define PLATFORM_SPI_CPOL_LOW                 0
+#define PLATFORM_SPI_CPOL_HIGH                1
+// SPI databits
+#define PLATFORM_SPI_DATABITS_8               8
+#define PLATFORM_SPI_DATABITS_16              16
+
 
 // Data types
 typedef uint32_t spi_data_type;
 
 // The platform SPI functions
 int platform_spi_exists( unsigned id );
-uint32_t platform_spi_setup( unsigned id, int mode, uint32_t clock, unsigned cpol, unsigned cpha, unsigned databits );
+uint32_t platform_spi_setup( unsigned id, int mode, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock);
 spi_data_type platform_spi_send_recv( unsigned id, spi_data_type data );
 void platform_spi_select( unsigned id, int is_select );
 

+ 4 - 0
app/spiffs/spiffs.c

@@ -45,6 +45,8 @@ The small 4KB sectors allow for greater flexibility in applications th
 void spiffs_mount() {
   spiffs_config cfg;
   cfg.phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL ); 
+  cfg.phys_addr += 0x3000;
+  cfg.phys_addr &= 0xFFFFC000;  // align to 4 sector.
   cfg.phys_size = INTERNAL_FLASH_SIZE - ( ( u32_t )cfg.phys_addr - INTERNAL_FLASH_START_ADDRESS );
   cfg.phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet
   cfg.log_block_size = INTERNAL_FLASH_SECTOR_SIZE; // let us not complicate things
@@ -74,6 +76,8 @@ int myspiffs_format( void )
   SPIFFS_unmount(&fs);
   u32_t sect_first, sect_last;
   sect_first = ( u32_t )platform_flash_get_first_free_block_address( NULL ); 
+  sect_first += 0x3000;
+  sect_first &= 0xFFFFC000;  // align to 4 sector.
   sect_first = platform_flash_get_sector_of_address(sect_first);
   sect_last = INTERNAL_FLASH_SIZE + INTERNAL_FLASH_START_ADDRESS - 4;
   sect_last = platform_flash_get_sector_of_address(sect_last);

+ 1 - 1
app/upgrade/upgrade.c

@@ -222,7 +222,7 @@ upgrade_connect_cb(void *arg)
     espconn_regist_sentcb(pespconn, upgrade_datasent);
 
     if (pbuf != NULL) {
-        UPGRADE_DBG(pbuf);
+        UPGRADE_DBG("%s\n", pbuf);
 #ifdef UPGRADE_SSL_ENABLE
         espconn_secure_sent(pespconn, pbuf, os_strlen(pbuf));
 #else

+ 30 - 25
app/user/user_main.c

@@ -50,30 +50,8 @@ extern void spiffs_mount();
 
 // extern uint16_t flash_get_sec_num();
 
-/******************************************************************************
- * FunctionName : user_init
- * Description  : entry of user application, init user function here
- * Parameters   : none
- * Returns      : none
-*******************************************************************************/
-void user_init(void)
+void nodemcu_init(void)
 {
-    // NODE_DBG("SDK version:%s\n", system_get_sdk_version());
-    // system_print_meminfo();
-    // os_printf("Heap size::%d.\n",system_get_free_heap_size());
-    // os_delay_us(50*1000);   // delay 50ms before init uart
-
-#ifdef DEVELOP_VERSION
-    uart_init(BIT_RATE_74880, BIT_RATE_74880);
-#else
-    uart_init(BIT_RATE_9600, BIT_RATE_9600);
-#endif
-    // uart_init(BIT_RATE_115200, BIT_RATE_115200);
-    
-    #ifndef NODE_DEBUG
-    system_set_os_print(0);
-    #endif
-    
     NODE_ERR("\n");
     // Initialize platform first for lua modules.   
     if( platform_init() != PLATFORM_OK )
@@ -85,9 +63,9 @@ void user_init(void)
     
     if( !flash_init_data_written() ){
         NODE_ERR("Restore init data.\n");
-		// Flash init data at FLASHSIZE - 0x04000 Byte.
+        // Flash init data at FLASHSIZE - 0x04000 Byte.
         flash_init_data_default();
-		// Flash blank data at FLASHSIZE - 0x02000 Byte.
+        // Flash blank data at FLASHSIZE - 0x02000 Byte.
         flash_init_data_blank(); 
     }
 
@@ -119,3 +97,30 @@ void user_init(void)
     task_init();
     system_os_post(USER_TASK_PRIO_0,SIG_LUA,'s');
 }
+
+/******************************************************************************
+ * FunctionName : user_init
+ * Description  : entry of user application, init user function here
+ * Parameters   : none
+ * Returns      : none
+*******************************************************************************/
+void user_init(void)
+{
+    // NODE_DBG("SDK version:%s\n", system_get_sdk_version());
+    // system_print_meminfo();
+    // os_printf("Heap size::%d.\n",system_get_free_heap_size());
+    // os_delay_us(50*1000);   // delay 50ms before init uart
+
+#ifdef DEVELOP_VERSION
+    uart_init(BIT_RATE_74880, BIT_RATE_74880);
+#else
+    uart_init(BIT_RATE_9600, BIT_RATE_9600);
+#endif
+    // uart_init(BIT_RATE_115200, BIT_RATE_115200);
+    
+    #ifndef NODE_DEBUG
+    system_set_os_print(0);
+    #endif
+    
+    system_init_done_cb(nodemcu_init);
+}

+ 33 - 7
examples/fragment.lua

@@ -25,15 +25,19 @@ ss=net.createServer(net.TCP) ss:listen(80,function(c) end)
 
 s=net.createServer(net.TCP) s:listen(80,function(c) c:on("receive",function(s,c) print(c) end) end)
 
-s=net.createServer(net.UDP) s:listen(5683,function(c) c:on("receive",function(s,c) print(c) end) end)
+s=net.createServer(net.UDP) 
+s:on("receive",function(s,c) print(c) end)
+s:listen(5683)
+
+su=net.createConnection(net.UDP) 
+su:on("receive",function(su,c) print(c) end) 
+su:connect(5683,"192.168.18.101") 
+su:send("hello")
 
 mm=node.list()
 for k, v in pairs(mm) do print('file:'..k..' len:'..v) end
 for k,v in pairs(d) do print("n:"..k..", s:"..v) end
-su=net.createConnection(net.UDP) 
-su:on("receive",function(su,c) print(c) end) 
-su:connect(5683,"192.168.0.66") 
-su:send("/v1/id")
+
 
 gpio.mode(0,gpio.INT) gpio.trig(0,"down",function(l) print("level="..l) end)
 
@@ -57,8 +61,6 @@ su:send("hello world")
 
 s=net.createServer(net.TCP) s:listen(8008,function(c) c:on("receive",function(s,c) print(c) pcall(loadstring(c)) end) end)
 
-s=net.createServer(net.UDP) s:listen(8888,function(c) c:on("receive",function(s,c) print(c) pcall(loadstring(c)) end) end)
-
 s=net.createServer(net.TCP) s:listen(8008,function(c) con_std = c function s_output(str) if(con_std~=nil) then con_std:send(str) end end 
 	node.output(s_output, 0) c:on("receive",function(c,l) node.input(l) end) c:on("disconnection",function(c) con_std = nil node.output(nil) end) end)
 
@@ -313,3 +315,27 @@ uart.on("data", 0 ,function(input) if input=="q" then uart.on("data") else print
 uart.on("data","\r",function(input) if input=="quit" then uart.on("data") else print(input) end end, 1)
 
 for k, v in pairs(file.list()) do print('file:'..k..' len:'..v) end
+
+m=mqtt.Client()
+m:connect("192.168.18.101",1883)
+m:subscribe("/topic",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("/topic","hello",0,0)
+
+uart.setup(0,9600,8,0,1,0)
+sv=net.createServer(net.TCP, 60)
+global_c = nil
+sv:listen(9999, function(c)
+	if global_c~=nil then
+		global_c:close()
+	end
+	global_c=c
+	c:on("receive",function(sck,pl)	uart.write(0,pl) end)
+end)
+
+uart.on("data",4, function(data)
+	if global_c~=nil then
+		global_c:send(data)
+	end
+end, 0)
+

+ 85 - 0
include/at_custom.h

@@ -0,0 +1,85 @@
+
+/*
+ * custom_at.h
+ *
+ * This file is part of Espressif's AT+ command set program.
+ * Copyright (C) 2013 - 2016, Espressif Systems
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CUSTOM_AT_H_
+#define CUSTOM_AT_H_
+
+#include "c_types.h"
+
+typedef struct
+{
+  char *at_cmdName;
+  int8_t at_cmdLen;
+  void (*at_testCmd)(uint8_t id);
+  void (*at_queryCmd)(uint8_t id);
+  void (*at_setupCmd)(uint8_t id, char *pPara);
+  void (*at_exeCmd)(uint8_t id);
+}at_funcationType;
+
+/**
+  * @brief  Response "OK" to uart.
+  * @param  None
+  * @retval None
+  */
+void at_response_ok(void);
+/**
+  * @brief  Response "ERROR" to uart.
+  * @param  events: no used
+  * @retval None
+  */
+void at_response_error(void);
+/**
+  * @brief  Task of process command or txdata.
+  * @param  custom_at_cmd_array: the array of at cmd that custom defined
+  *         cmd_num : the num of at cmd that custom defined
+  * @retval None
+  */
+void at_cmd_array_regist(at_funcationType *custom_at_cmd_array,uint32 cmd_num);
+/**
+  * @brief  get digit form at cmd line.the maybe alter pSrc
+  * @param  p_src: at cmd line string
+  *         result:the buffer to be placed result
+  *         err : err num
+  * @retval TRUE:
+  *         FALSE:
+  */
+bool at_get_next_int_dec(char **p_src,int*result,int* err);
+/**
+  * @brief  get string form at cmd line.the maybe alter pSrc
+  * @param  p_dest: the buffer to be placed result
+  *         p_src: at cmd line string
+  *         max_len :max len of string excepted to get
+  * @retval None
+  */
+int32 at_data_str_copy(char *p_dest, char **p_src, int32 max_len);
+
+/**
+  * @brief  initialize at module
+  * @param  None
+  * @retval None
+  */
+void at_init(void);
+/**
+  * @brief  print string to at port
+  * @param  string
+  * @retval None
+  */
+void at_port_print(const char *str);
+#endif

+ 2 - 0
include/c_types.h

@@ -16,6 +16,7 @@ typedef unsigned long       uint32_t;
 typedef signed long         sint32_t;
 typedef signed long         int32_t;
 typedef signed long long    sint64_t;
+typedef signed long long    int64_t;
 typedef unsigned long long  uint64_t;
 typedef unsigned long long  u_int64_t;
 typedef float               real32_t;
@@ -78,6 +79,7 @@ typedef enum {
 
 #ifdef ICACHE_FLASH
 #define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
+#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
 #else
 #define ICACHE_FLASH_ATTR
 #endif /* ICACHE_FLASH */

+ 17 - 0
include/espconn.h

@@ -91,6 +91,7 @@ struct espconn {
 
 enum espconn_option{
 	ESPCONN_REUSEADDR = 1,
+	ESPCONN_NODELAY,
 	ESPCONN_END
 };
 
@@ -371,5 +372,21 @@ sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
 *******************************************************************************/
 sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
 
+/******************************************************************************
+ * FunctionName : espconn_recv_hold
+ * Description  : hold tcp receive
+ * Parameters   : espconn -- espconn to hold
+ * Returns      : none
+*******************************************************************************/
+sint8 espconn_recv_hold(struct espconn *pespconn);
+
+/******************************************************************************
+ * FunctionName : espconn_recv_unhold
+ * Description  : unhold tcp receive
+ * Parameters   : espconn -- espconn to unhold
+ * Returns      : none
+*******************************************************************************/
+sint8 espconn_recv_unhold(struct espconn *pespconn);
+
 #endif
 

+ 5 - 0
include/ip_addr.h

@@ -52,6 +52,11 @@ struct ip_info {
 #define ip4_addr3_16(ipaddr) ((uint16)ip4_addr3(ipaddr))
 #define ip4_addr4_16(ipaddr) ((uint16)ip4_addr4(ipaddr))
 
+
+/** 255.255.255.255 */
+#define IPADDR_NONE         ((uint32)0xffffffffUL)
+/** 0.0.0.0 */
+#define IPADDR_ANY          ((uint32)0x00000000UL)
 uint32 ipaddr_addr(const char *cp);
 
 #define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \

+ 9 - 0
include/osapi.h

@@ -44,5 +44,14 @@
 #define os_sprintf  ets_sprintf
 #define os_update_cpu_frequency ets_update_cpu_frequency
 
+#ifdef USE_OPTIMIZE_PRINTF
+#define os_printf(fmt, ...) do {	\
+	static const char flash_str[] ICACHE_RODATA_ATTR = fmt;	\
+	os_printf_plus(flash_str, ##__VA_ARGS__);	\
+	} while(0)
+#else
+#define os_printf	os_printf_plus
+#endif
+
 #endif
 

+ 32 - 0
include/ping.h

@@ -0,0 +1,32 @@
+#ifndef __PING_H__
+#define __PING_H__
+
+
+typedef void (* ping_recv_function)(void* arg, void *pdata);
+typedef void (* ping_sent_function)(void* arg, void *pdata);
+
+struct ping_option{
+	uint32 count;
+	uint32 ip;
+	uint32 coarse_time;
+	ping_recv_function recv_function;
+	ping_sent_function sent_function;
+	void* reverse;
+};
+
+struct ping_resp{
+	uint32 total_count;
+	uint32 resp_time;
+	uint32 seqno;
+	uint32 timeout_count;
+	uint32 bytes;
+	uint32 total_bytes;
+	uint32 total_time;
+	sint8  ping_err;
+};
+
+bool ping_start(struct ping_option *ping_opt);
+bool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv);
+bool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent);
+
+#endif /* __PING_H__ */

+ 28 - 0
include/smartconfig.h

@@ -0,0 +1,28 @@
+/*
+ *  Copyright (C) 2015 -2018  Espressif System
+ *
+ */
+
+#ifndef __SMARTCONFIG_H__
+#define __SMARTCONFIG_H__
+
+typedef void (*sc_callback_t)(void *data);
+
+typedef enum  {
+    SC_STATUS_FIND_CHANNEL = 0,
+    SC_STATUS_GETTING_SSID_PSWD,
+    SC_STATUS_GOT_SSID_PSWD,
+    SC_STATUS_LINK,
+} sc_status;
+
+typedef enum  {
+    SC_TYPE_ESPTOUCH = 0,
+    SC_TYPE_AIRKISS,
+} sc_type;
+
+sc_status smartconfig_get_status(void);
+const char *smartconfig_get_version(void);
+bool smartconfig_start(sc_type type, sc_callback_t cb);
+bool smartconfig_stop(void);
+
+#endif

+ 0 - 2
include/spi_flash.h

@@ -24,8 +24,6 @@ typedef struct{
 #define SPI_FLASH_SEC_SIZE      4096
 
 uint32 spi_flash_get_id(void);
-SpiFlashOpResult spi_flash_read_status(uint32 *status);
-SpiFlashOpResult spi_flash_write_status(uint32 status_value);
 SpiFlashOpResult spi_flash_erase_sector(uint16 sec);
 SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size);
 SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size);

+ 261 - 252
include/user_interface.h

@@ -1,252 +1,261 @@
-/*
- *  Copyright (C) 2013 -2014  Espressif System
- *
- */
-
-#ifndef __USER_INTERFACE_H__
-#define __USER_INTERFACE_H__
-
-#include "os_type.h"
-#ifdef LWIP_OPEN_SRC
-#include "lwip/ip_addr.h"
-#else
-#include "ip_addr.h"
-#endif
-
-#include "queue.h"
-#include "user_config.h"
-#include "spi_flash.h"
-
-#ifndef MAC2STR
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-#endif
-
-enum rst_reason {
-	DEFAULT_RST_FLAG	= 0,
-	WDT_RST_FLAG	= 1,
-	EXP_RST_FLAG    = 2
-};
-
-struct rst_info{
-	uint32 flag;
-	uint32 exccause;
-	uint32 epc1;
-	uint32 epc2;
-	uint32 epc3;
-	uint32 excvaddr;
-	uint32 depc;
-};
-
-#define UPGRADE_FW_BIN1         0x00
-#define UPGRADE_FW_BIN2         0x01
-
-void system_restore(void);
-void system_restart(void);
-void system_deep_sleep(uint32 time_in_us);
-uint8 system_upgrade_userbin_check(void);
-void system_upgrade_reboot(void);
-uint8 system_upgrade_flag_check();
-void system_upgrade_flag_set(uint8 flag);
-void system_timer_reinit(void);
-uint32 system_get_time(void);
-
-/* user task's prio must be 0/1/2 !!!*/
-enum {
-    USER_TASK_PRIO_0 = 0,
-    USER_TASK_PRIO_1,
-    USER_TASK_PRIO_2,
-    USER_TASK_PRIO_MAX
-};
-
-void system_os_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen);
-void system_os_post(uint8 prio, os_signal_t sig, os_param_t par);
-
-void system_print_meminfo(void);
-uint32 system_get_free_heap_size(void);
-
-void system_set_os_print(uint8 onoff);
-
-uint64 system_mktime(uint32 year, uint32 mon, uint32 day, uint32 hour, uint32 min, uint32 sec);
-
-uint32 system_get_chip_id(void);
-
-typedef void (* init_done_cb_t)(void);
-
-void system_init_done_cb(init_done_cb_t cb);
-
-uint32 system_rtc_clock_cali_proc(void);
-uint32 system_get_rtc_time(void);
-
-bool system_rtc_mem_read(uint8 src_addr, void *des_addr, uint16 load_size);
-bool system_rtc_mem_write(uint8 des_addr, const void *src_addr, uint16 save_size);
-
-void system_uart_swap(void);
-
-uint16 system_adc_read(void);
-
-const char *system_get_sdk_version(void);
-
-#define NULL_MODE       0x00
-#define STATION_MODE    0x01
-#define SOFTAP_MODE     0x02
-#define STATIONAP_MODE  0x03
-
-uint8 wifi_get_opmode(void);
-bool wifi_set_opmode(uint8 opmode);
-
-struct bss_info {
-    STAILQ_ENTRY(bss_info)     next;
-
-    uint8 bssid[6];
-    uint8 ssid[32];
-    uint8 channel;
-    sint8 rssi;
-    uint8 authmode;
-    uint8 is_hidden;
-};
-
-typedef struct _scaninfo {
-    STAILQ_HEAD(, bss_info) *pbss;
-    struct espconn *pespconn;
-    uint8 totalpage;
-    uint8 pagenum;
-    uint8 page_sn;
-    uint8 data_cnt;
-} scaninfo;
-
-typedef void (* scan_done_cb_t)(void *arg, STATUS status);
-
-struct station_config {
-    uint8 ssid[32];
-    uint8 password[64];
-    uint8 bssid_set;
-    uint8 bssid[6];
-};
-
-bool wifi_station_get_config(struct station_config *config);
-bool wifi_station_set_config(struct station_config *config);
-
-bool wifi_station_connect(void);
-bool wifi_station_disconnect(void);
-
-struct scan_config {
-    uint8 *ssid;
-    uint8 *bssid;
-    uint8 channel;
-    uint8 show_hidden;
-};
-
-bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb);
-
-uint8 wifi_station_get_auto_connect(void);
-bool wifi_station_set_auto_connect(uint8 set);
-
-enum {
-    STATION_IDLE = 0,
-    STATION_CONNECTING,
-    STATION_WRONG_PASSWORD,
-    STATION_NO_AP_FOUND,
-    STATION_CONNECT_FAIL,
-    STATION_GOT_IP
-};
-
-enum dhcp_status {
-	DHCP_STOPPED,
-	DHCP_STARTED
-};
-
-uint8 wifi_station_get_connect_status(void);
-
-uint8 wifi_station_get_current_ap_id(void);
-bool wifi_station_ap_change(uint8 current_ap_id);
-bool wifi_station_ap_number_set(uint8 ap_number);
-
-bool wifi_station_dhcpc_start(void);
-bool wifi_station_dhcpc_stop(void);
-enum dhcp_status wifi_station_dhcpc_status(void);
-
-typedef enum _auth_mode {
-    AUTH_OPEN           = 0,
-    AUTH_WEP,
-    AUTH_WPA_PSK,
-    AUTH_WPA2_PSK,
-    AUTH_WPA_WPA2_PSK
-} AUTH_MODE;
-
-struct softap_config {
-    uint8 ssid[32];
-    uint8 password[64];
-    uint8 ssid_len;
-    uint8 channel;
-    uint8 authmode;
-    uint8 ssid_hidden;
-    uint8 max_connection;
-};
-
-bool wifi_softap_get_config(struct softap_config *config);
-bool wifi_softap_set_config(struct softap_config *config);
-
-struct station_info {
-	STAILQ_ENTRY(station_info)	next;
-
-	uint8 bssid[6];
-	struct ip_addr ip;
-};
-
-struct dhcps_lease {
-	uint32 start_ip;
-	uint32 end_ip;
-};
-
-struct station_info * wifi_softap_get_station_info(void);
-void wifi_softap_free_station_info(void);
-uint8 wifi_station_get_ap_info(struct station_config config[]);
-
-bool wifi_softap_dhcps_start(void);
-bool wifi_softap_dhcps_stop(void);
-bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please);
-enum dhcp_status wifi_softap_dhcps_status(void);
-
-#define STATION_IF      0x00
-#define SOFTAP_IF       0x01
-
-bool wifi_get_ip_info(uint8 if_index, struct ip_info *info);
-bool wifi_set_ip_info(uint8 if_index, struct ip_info *info);
-bool wifi_get_macaddr(uint8 if_index, uint8 *macaddr);
-bool wifi_set_macaddr(uint8 if_index, uint8 *macaddr);
-
-uint8 wifi_get_channel(void);
-bool wifi_set_channel(uint8 channel);
-
-void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func);
-
-/** Get the absolute difference between 2 u32_t values (correcting overflows)
- * 'a' is expected to be 'higher' (without overflow) than 'b'. */
-#define ESP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
-
-void wifi_promiscuous_enable(uint8 promiscuous);
-
-typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len);
-
-void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
-
-enum phy_mode {
-	PHY_MODE_11B	= 1,
-	PHY_MODE_11G	= 2,
-	PHY_MODE_11N    = 3
-};
-
-enum phy_mode wifi_get_phy_mode(void);
-bool wifi_set_phy_mode(enum phy_mode mode);
-
-enum sleep_type {
-	NONE_SLEEP_T	= 0,
-	LIGHT_SLEEP_T,
-	MODEM_SLEEP_T
-};
-
-bool wifi_set_sleep_type(enum sleep_type type);
-enum sleep_type wifi_get_sleep_type(void);
-
-#endif
+/*
+ *  Copyright (C) 2013 -2014  Espressif System
+ *
+ */
+
+#ifndef __USER_INTERFACE_H__
+#define __USER_INTERFACE_H__
+
+#include "os_type.h"
+#ifdef LWIP_OPEN_SRC
+#include "lwip/ip_addr.h"
+#else
+#include "ip_addr.h"
+#endif
+
+#include "queue.h"
+#include "user_config.h"
+#include "spi_flash.h"
+
+#ifndef MAC2STR
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#endif
+
+enum rst_reason {
+	DEFAULT_RST_FLAG	= 0,
+	WDT_RST_FLAG	= 1,
+	EXP_RST_FLAG    = 2
+};
+
+struct rst_info{
+	uint32 flag;
+	uint32 exccause;
+	uint32 epc1;
+	uint32 epc2;
+	uint32 epc3;
+	uint32 excvaddr;
+	uint32 depc;
+};
+
+#define UPGRADE_FW_BIN1         0x00
+#define UPGRADE_FW_BIN2         0x01
+
+void system_restore(void);
+void system_restart(void);
+
+bool system_deep_sleep_set_option(uint8 option);
+void system_deep_sleep(uint32 time_in_us);
+
+uint8 system_upgrade_userbin_check(void);
+void system_upgrade_reboot(void);
+uint8 system_upgrade_flag_check();
+void system_upgrade_flag_set(uint8 flag);
+
+void system_timer_reinit(void);
+uint32 system_get_time(void);
+
+/* user task's prio must be 0/1/2 !!!*/
+enum {
+    USER_TASK_PRIO_0 = 0,
+    USER_TASK_PRIO_1,
+    USER_TASK_PRIO_2,
+    USER_TASK_PRIO_MAX
+};
+
+bool system_os_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen);
+bool system_os_post(uint8 prio, os_signal_t sig, os_param_t par);
+
+void system_print_meminfo(void);
+uint32 system_get_free_heap_size(void);
+
+void system_set_os_print(uint8 onoff);
+uint8 system_get_os_print();
+
+uint64 system_mktime(uint32 year, uint32 mon, uint32 day, uint32 hour, uint32 min, uint32 sec);
+
+uint32 system_get_chip_id(void);
+
+typedef void (* init_done_cb_t)(void);
+
+void system_init_done_cb(init_done_cb_t cb);
+
+uint32 system_rtc_clock_cali_proc(void);
+uint32 system_get_rtc_time(void);
+
+bool system_rtc_mem_read(uint8 src_addr, void *des_addr, uint16 load_size);
+bool system_rtc_mem_write(uint8 des_addr, const void *src_addr, uint16 save_size);
+
+void system_uart_swap(void);
+
+uint16 system_adc_read(void);
+
+const char *system_get_sdk_version(void);
+
+#define NULL_MODE       0x00
+#define STATION_MODE    0x01
+#define SOFTAP_MODE     0x02
+#define STATIONAP_MODE  0x03
+
+typedef enum _auth_mode {
+    AUTH_OPEN           = 0,
+    AUTH_WEP,
+    AUTH_WPA_PSK,
+    AUTH_WPA2_PSK,
+    AUTH_WPA_WPA2_PSK,
+    AUTH_MAX
+} AUTH_MODE;
+
+uint8 wifi_get_opmode(void);
+bool wifi_set_opmode(uint8 opmode);
+
+struct bss_info {
+    STAILQ_ENTRY(bss_info)     next;
+
+    uint8 bssid[6];
+    uint8 ssid[32];
+    uint8 channel;
+    sint8 rssi;
+    AUTH_MODE authmode;
+    uint8 is_hidden;
+};
+
+typedef struct _scaninfo {
+    STAILQ_HEAD(, bss_info) *pbss;
+    struct espconn *pespconn;
+    uint8 totalpage;
+    uint8 pagenum;
+    uint8 page_sn;
+    uint8 data_cnt;
+} scaninfo;
+
+typedef void (* scan_done_cb_t)(void *arg, STATUS status);
+
+struct station_config {
+    uint8 ssid[32];
+    uint8 password[64];
+    uint8 bssid_set;	// Note: If bssid_set is 1, station will just connect to the router
+                        // with both ssid[] and bssid[] matched. Please check about this.
+    uint8 bssid[6];
+};
+
+bool wifi_station_get_config(struct station_config *config);
+bool wifi_station_set_config(struct station_config *config);
+
+bool wifi_station_connect(void);
+bool wifi_station_disconnect(void);
+
+struct scan_config {
+    uint8 *ssid;	// Note: ssid == NULL, don't filter ssid.
+    uint8 *bssid;	// Note: bssid == NULL, don't filter bssid.
+    uint8 channel;	// Note: channel == 0, scan all channels, otherwise scan set channel.
+    uint8 show_hidden;	// Note: show_hidden == 1, can get hidden ssid routers' info.
+};
+
+bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb);
+
+uint8 wifi_station_get_auto_connect(void);
+bool wifi_station_set_auto_connect(uint8 set);
+
+enum {
+    STATION_IDLE = 0,
+    STATION_CONNECTING,
+    STATION_WRONG_PASSWORD,
+    STATION_NO_AP_FOUND,
+    STATION_CONNECT_FAIL,
+    STATION_GOT_IP
+};
+
+enum dhcp_status {
+	DHCP_STOPPED,
+	DHCP_STARTED
+};
+
+uint8 wifi_station_get_connect_status(void);
+
+uint8 wifi_station_get_current_ap_id(void);
+bool wifi_station_ap_change(uint8 current_ap_id);
+bool wifi_station_ap_number_set(uint8 ap_number);
+
+bool wifi_station_dhcpc_start(void);
+bool wifi_station_dhcpc_stop(void);
+enum dhcp_status wifi_station_dhcpc_status(void);
+
+struct softap_config {
+    uint8 ssid[32];
+    uint8 password[64];
+    uint8 ssid_len;	// Note: Recommend to set it according to your ssid
+    uint8 channel;	// Note: support 1 ~ 13
+    AUTH_MODE authmode;	// Note: Don't support AUTH_WEP in softAP mode.
+    uint8 ssid_hidden;	// Note: default 0
+    uint8 max_connection;	// Note: default 4, max 4
+    uint16 beacon_interval;	// Note: support 100 ~ 60000 ms, default 100
+};
+
+bool wifi_softap_get_config(struct softap_config *config);
+bool wifi_softap_set_config(struct softap_config *config);
+
+struct station_info {
+	STAILQ_ENTRY(station_info)	next;
+
+	uint8 bssid[6];
+	struct ip_addr ip;
+};
+
+struct dhcps_lease {
+	uint32 start_ip;
+	uint32 end_ip;
+};
+
+struct station_info * wifi_softap_get_station_info(void);
+void wifi_softap_free_station_info(void);
+uint8 wifi_station_get_ap_info(struct station_config config[]);
+
+bool wifi_softap_dhcps_start(void);
+bool wifi_softap_dhcps_stop(void);
+bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please);
+enum dhcp_status wifi_softap_dhcps_status(void);
+
+#define STATION_IF      0x00
+#define SOFTAP_IF       0x01
+
+bool wifi_get_ip_info(uint8 if_index, struct ip_info *info);
+bool wifi_set_ip_info(uint8 if_index, struct ip_info *info);
+bool wifi_get_macaddr(uint8 if_index, uint8 *macaddr);
+bool wifi_set_macaddr(uint8 if_index, uint8 *macaddr);
+
+uint8 wifi_get_channel(void);
+bool wifi_set_channel(uint8 channel);
+
+void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func);
+void wifi_status_led_uninstall();
+
+/** Get the absolute difference between 2 u32_t values (correcting overflows)
+ * 'a' is expected to be 'higher' (without overflow) than 'b'. */
+#define ESP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
+
+void wifi_promiscuous_enable(uint8 promiscuous);
+
+typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len);
+
+void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
+
+enum phy_mode {
+	PHY_MODE_11B	= 1,
+	PHY_MODE_11G	= 2,
+	PHY_MODE_11N    = 3
+};
+
+enum phy_mode wifi_get_phy_mode(void);
+bool wifi_set_phy_mode(enum phy_mode mode);
+
+enum sleep_type {
+	NONE_SLEEP_T	= 0,
+	LIGHT_SLEEP_T,
+	MODEM_SLEEP_T
+};
+
+bool wifi_set_sleep_type(enum sleep_type type);
+enum sleep_type wifi_get_sleep_type(void);
+
+#endif

+ 1 - 1
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 = 0x50000
+  irom0_0_seg :                       	org = 0x40210000, len = 0x51000
 }
 
 PHDRS

+ 1 - 0
ld/eagle.rom.addr.v6.ld

@@ -18,6 +18,7 @@ PROVIDE ( SHA1Transform = 0x4000a364 );
 PROVIDE ( SHA1Update = 0x4000b5a8 );
 PROVIDE ( SPI_read_status = 0x400043c8 );
 PROVIDE ( SPI_write_status = 0x40004400 );
+PROVIDE ( SPI_write_enable = 0x4000443c );
 PROVIDE ( Wait_SPI_Idle = 0x4000448c );
 PROVIDE ( SPIEraseArea = 0x40004b44 );
 PROVIDE ( SPIEraseBlock = 0x400049b4 );

BIN
lib/libat.a


BIN
lib/libjson.a


BIN
lib/liblwip.a


BIN
lib/libmain.a


BIN
lib/libnet80211.a


BIN
lib/libphy.a


BIN
lib/libpp.a


BIN
lib/libsmartconfig.a


BIN
lib/libssl.a


BIN
lib/libupgrade.a


BIN
lib/libwpa.a


+ 74 - 0
lua_examples/irsend.lua

@@ -0,0 +1,74 @@
+------------------------------------------------------------------------------
+-- IR send module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov <dronnikov@gmail.com>
+--
+-- Example:
+-- require("irsend").nec(4, 0x00ff00ff)
+------------------------------------------------------------------------------
+local M
+do
+  -- const
+  local NEC_PULSE_US   = 1000000 / 38000
+  local NEC_HDR_MARK   = 9000
+  local NEC_HDR_SPACE  = 4500
+  local NEC_BIT_MARK   =  560
+  local NEC_ONE_SPACE  = 1600
+  local NEC_ZERO_SPACE =  560
+  local NEC_RPT_SPACE  = 2250
+  -- cache
+  local gpio, bit = gpio, bit
+  local mode, write = gpio.mode, gpio.write
+  local waitus = tmr.delay
+  local isset = bit.isset
+  -- NB: poorman 38kHz PWM with 1/3 duty. Touch with care! )
+  local carrier = function(pin, c)
+    c = c / NEC_PULSE_US
+    while c > 0 do
+      write(pin, 1)
+      write(pin, 0)
+      c = c + 0
+      c = c + 0
+      c = c + 0
+      c = c + 0
+      c = c + 0
+      c = c + 0
+      c = c * 1
+      c = c * 1
+      c = c * 1
+      c = c - 1
+    end
+  end
+  -- tsop signal simulator
+  local pull = function(pin, c)
+    write(pin, 0)
+    waitus(c)
+    write(pin, 1)
+  end
+  -- NB: tsop mode allows to directly connect pin
+  --     inplace of TSOP input
+  local nec = function(pin, code, tsop)
+    local pulse = tsop and pull or carrier
+    -- setup transmitter
+    mode(pin, 1)
+    write(pin, tsop and 1 or 0)
+    -- header
+    pulse(pin, NEC_HDR_MARK)
+    waitus(NEC_HDR_SPACE)
+    -- sequence, lsb first
+    for i = 0, 31 do
+      pulse(pin, NEC_BIT_MARK)
+      waitus(isset(code, i) and NEC_ONE_SPACE or NEC_ZERO_SPACE)
+    end
+    -- trailer
+    pulse(pin, NEC_BIT_MARK)
+    -- done transmitter
+    --mode(pin, 0, tsop and 1 or 0)
+  end
+  -- expose
+  M = {
+    nec = nec,
+  }
+end
+return M

+ 16 - 0
lua_examples/tcp2uart.lua

@@ -0,0 +1,16 @@
+uart.setup(0,9600,8,0,1,0)
+sv=net.createServer(net.TCP, 60)
+global_c = nil
+sv:listen(9999, function(c)
+	if global_c~=nil then
+		global_c:close()
+	end
+	global_c=c
+	c:on("receive",function(sck,pl)	uart.write(0,pl) end)
+end)
+
+uart.on("data",4, function(data)
+	if global_c~=nil then
+		global_c:send(data)
+	end
+end, 0)

+ 84 - 0
lua_examples/yet-another-dht22.lua

@@ -0,0 +1,84 @@
+------------------------------------------------------------------------------
+-- DHT11/22 query module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov <dronnikov@gmail.com>
+--
+-- Example:
+-- print("DHT11", require("dht22").read(4))
+-- print("DHT22", require("dht22").read(4, true))
+-- NB: the very first read sometimes fails
+------------------------------------------------------------------------------
+local M
+do
+  -- cache
+  local gpio = gpio
+  local val = gpio.read
+  local waitus = tmr.delay
+  --
+  local read = function(pin, dht22)
+    -- wait for pin value
+    local w = function(v)
+      local c = 255
+      while c > 0 and val(pin) ~= v do c = c - 1 end
+      return c
+    end
+    -- NB: we preallocate incoming data buffer
+    --     or precise timing in reader gets broken
+    local b = { 0, 0, 0, 0, 0 }
+
+    -- kick the device
+    gpio.mode(pin, gpio.INPUT, gpio.PULLUP)
+    gpio.write(pin, 1)
+    waitus(10)
+    gpio.mode(pin, gpio.OUTPUT)
+    gpio.write(pin, 0)
+    waitus(20000)
+    gpio.write(pin, 1)
+    gpio.mode(pin, gpio.INPUT, gpio.PULLUP)
+    -- wait for device presense
+    if w(0) == 0 or w(1) == 0 or w(0) == 0 then
+      return nil, 0
+    end
+    -- receive 5 octets of data, msb first
+    for i = 1, 5 do
+      local x = 0
+      for j = 1, 8 do
+        x = x + x
+        if w(1) == 0 then return nil, 1 end
+        -- 70us for 1, 27 us for 0
+        waitus(30)
+        if val(pin) == 1 then
+          x = x + 1
+          if w(0) == 0 then return nil, 2 end
+        end
+      end
+      b[i] = x
+    end
+    -- check crc. NB: calculating in receiver loop breaks timings
+    local crc = 0
+    for i = 1, 4 do
+      crc = (crc + b[i]) % 256
+    end
+    if crc ~= b[5] then return nil, 3 end
+    -- convert
+    local t, h
+    -- DHT22: values in tenths of unit, temperature can be negative
+    if dht22 then
+      h = b[1] * 256 + b[2]
+      t = b[3] * 256 + b[4]
+      if t > 0x8000 then t = -(t - 0x8000) end
+    -- DHT11: no negative temperatures, only integers
+    -- NB: return in 0.1 Celsius
+    else
+      h = 10 * b[1]
+      t = 10 * b[3]
+    end
+    return t, h
+  end
+  -- expose interface
+  M = {
+    read = read,
+  }
+end
+return M

+ 65 - 0
lua_examples/yet-another-ds18b20.lua

@@ -0,0 +1,65 @@
+------------------------------------------------------------------------------
+-- DS18B20 query module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov <dronnikov@gmail.com>
+--
+-- Example:
+-- for k, v in pairs(require("ds18b20").read(4)) do print(k, v) end
+------------------------------------------------------------------------------
+local M
+do
+  local format_addr = function(a)
+    return ("%02x-%02x%02x%02x%02x%02x%02x"):format(
+        a:byte(1),
+        a:byte(7), a:byte(6), a:byte(5),
+        a:byte(4), a:byte(3), a:byte(2)
+      )
+  end
+  local read = function(pin, delay)
+    local ow = require("ow")
+    -- get list of relevant devices
+    local d = { }
+    ow.setup(pin)
+    ow.reset_search(pin)
+    while true do
+      tmr.wdclr()
+      local a = ow.search(pin)
+      if not a then break end
+      if ow.crc8(a) == 0 and
+        (a:byte(1) == 0x10 or a:byte(1) == 0x28)
+      then
+        d[#d + 1] = a
+      end
+    end
+    -- conversion command for all
+    ow.reset(pin)
+    ow.skip(pin)
+    ow.write(pin, 0x44, 1)
+    -- wait a bit
+    tmr.delay(delay or 100000)
+    -- iterate over devices
+    local r = { }
+    for i = 1, #d do
+      tmr.wdclr()
+      -- read rom command
+      ow.reset(pin)
+      ow.select(pin, d[i])
+      ow.write(pin, 0xBE, 1)
+      -- read data
+      local x = ow.read_bytes(pin, 9)
+      if ow.crc8(x) == 0 then
+        local t = (x:byte(1) + x:byte(2) * 256) * 625
+        -- NB: temperature in Celcius * 10^4
+        r[format_addr(d[i])] = t
+        d[i] = nil
+      end
+    end
+    return r
+  end
+  -- expose
+  M = {
+    read = read,
+  }
+end
+return M

+ 54 - 0
lua_modules/bh1750/bh1750.lua

@@ -0,0 +1,54 @@
+-- ***************************************************************************
+-- BH1750 module for ESP8266 with nodeMCU
+-- BH1750 compatible tested 2015-1-22
+--
+-- Written by xiaohu
+--
+-- MIT license, http://opensource.org/licenses/MIT
+-- ***************************************************************************
+local moduleName = ... 
+ local M = {}
+ _G[moduleName] = M
+	--I2C slave address of GY-30
+	local GY_30_address = 0X23
+	-- i2c interface ID
+	local id = 0
+	--LUX
+	local l
+	--CMD
+	local CMD = 0x10
+	local init = false
+	function M.init(sda, scl)
+	i2c.setup(id, sda, scl, i2c.SLOW)
+	--print("i2c ok..")
+	init = true
+	end
+	local function read_data(ADDR, commands, length)
+	i2c.start(id)
+	i2c.address(id, ADDR, i2c.TRANSMITTER)
+	i2c.write(id, commands)
+	i2c.stop(id)
+	i2c.start(id)
+	i2c.address(id, ADDR,i2c.RECEIVER)
+	tmr.delay(200000)
+	c = i2c.read(id, length)
+	i2c.stop(id)
+	return c
+	end
+	local function read_lux()
+	dataT = read_data(GY_30_address, CMD, 2)
+	UT = string.byte(dataT, 1) * 256 + string.byte(dataT, 2)
+	l = (UT*1000/12)
+	return(l)
+	end
+	function M.read()
+	if (not init) then
+	print("init() must be called before read.")
+	else
+	read_lux()
+	end
+	end
+	function M.getlux()
+	return l
+	end
+	return M

+ 104 - 0
lua_modules/bh1750/bh1750_CN.md

@@ -0,0 +1,104 @@
+# BH1750 模块
+
+##引用
+```lua
+bh1750 = require("bh1750")
+```
+## 释放
+```lua
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+<a id="bh1750_init"></a>
+##init()
+####描述
+设置BH1750所在的I2C引脚<br />
+
+####语法
+init(sda, scl)
+
+####参数
+sda: 1~12, IO index.<br />
+scl: 1~12, IO index.<br />
+
+####返回值
+nil
+
+####示例
+```lua
+SDA_PIN = 6 -- sda pin, GPIO12
+SCL_PIN = 5 -- scl pin, GPIO14
+
+bh1750 = require("bh1750")
+bh1750.init(SDA_PIN, SCL_PIN)
+
+-- release module
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+####参见
+**-**   []()
+
+<a id="bh1750_read"></a>
+##read()
+####描述
+从bh1750中读取光线传感器数据(Lux勒克斯).<br />
+
+####语法
+read()
+
+####参数
+nil.<br />
+
+####返回值
+nil.<br />
+
+####示例
+```lua
+SDA_PIN = 6 -- sda pin, GPIO12
+SCL_PIN = 5 -- scl pin, GPIO14
+
+bh1750 = require("bh1750")
+bh1750.init(SDA_PIN, SCL_PIN)
+bh1750.read()
+
+-- release module
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+####参见
+**-**   []()
+
+<a id="bh1750_getlux"></a>
+##getlux()
+####描述
+从BH1750中提取数据.<br />
+
+####语法
+getlux()
+
+####参数
+nil.<br />
+
+####返回值
+l: 整数,Lux计数
+####示例
+```lua
+SDA_PIN = 6 -- sda pin, GPIO12
+SCL_PIN = 5 -- scl pin, GPIO14
+
+bh1750 = require("bh1750")
+bh1750.init(SDA_PIN, SCL_PIN)
+bh1750.read()
+l = bh1750.getlux()
+print("lux: "..(l / 100).."."..(l % 100).." lx")
+
+-- release module
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+####参见
+**-**   []()

+ 105 - 0
lua_modules/bh1750/bh1750_EN.md

@@ -0,0 +1,105 @@
+# bh1750 Module
+
+##Require
+```lua
+bh1750 = require("bh1750")
+```
+## Release
+```lua
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+<a id="bh1750_init"></a>
+##init()
+####Description
+Setting the I2C pin of bh1750.<br />
+
+####Syntax
+init(sda, scl)
+
+####Parameters
+sda: 1~12, IO index.<br />
+scl: 1~12, IO index.<br />
+
+####Returns
+nil
+
+####Example
+```lua
+SDA_PIN = 6 -- sda pin, GPIO12
+SCL_PIN = 5 -- scl pin, GPIO14
+
+bh1750 = require("bh1750")
+bh1750.init(SDA_PIN, SCL_PIN)
+
+-- release module
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="bh1750_read"></a>
+##read()
+####Description
+Read Lux data from bh1750.<br />
+
+####Syntax
+read()
+
+####Parameters
+nil.<br />
+
+####Returns
+nil.<br />
+
+####Example
+```lua
+SDA_PIN = 6 -- sda pin, GPIO12
+SCL_PIN = 5 -- scl pin, GPIO14
+
+bh1750 = require("bh1750")
+bh1750.init(SDA_PIN, SCL_PIN)
+bh1750.read()
+
+-- release module
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="bh1750_getlux"></a>
+##getlux()
+####Description
+Get lux from bh1750.<br />
+
+####Syntax
+getlux()
+
+####Parameters
+nil.<br />
+
+####Returns
+l: Integer, getlux from bh1750.
+
+####Example
+```lua
+SDA_PIN = 6 -- sda pin, GPIO12
+SCL_PIN = 5 -- scl pin, GPIO14
+
+bh1750 = require("bh1750")
+bh1750.init(SDA_PIN, SCL_PIN)
+bh1750.read()
+l = bh1750.getlux()
+print("lux: "..(l / 100).."."..(l % 100).." lx")
+
+-- release module
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+####See also
+**-**   []()

+ 24 - 0
lua_modules/bh1750/bh1750_Example1.lua

@@ -0,0 +1,24 @@
+-- ***************************************************************************
+-- BH1750 Example Program for ESP8266 with nodeMCU
+-- BH1750 compatible tested 2015-1-30
+--
+-- Written by xiaohu
+--
+-- MIT license, http://opensource.org/licenses/MIT
+-- ***************************************************************************
+tmr.alarm(0, 10000, 1, function()
+
+    SDA_PIN = 6 -- sda pin, GPIO12
+    SCL_PIN = 5 -- scl pin, GPIO14
+
+    bh1750 = require("bh1750")
+    bh1750.init(SDA_PIN, SCL_PIN)
+    bh1750.read(OSS)
+    l = bh1750.getlux()
+    print("lux: "..(l / 100).."."..(l % 100).." lx")
+
+    -- release module
+    bh1750 = nil
+    package.loaded["bh1750"]=nil
+
+end)

+ 51 - 0
lua_modules/bh1750/bh1750_Example2.lua

@@ -0,0 +1,51 @@
+-- ***************************************************************************
+-- BH1750 Example Program for ESP8266 with nodeMCU
+-- BH1750 compatible tested 2015-1-30
+--
+-- Written by xiaohu
+--
+-- MIT license, http://opensource.org/licenses/MIT
+-- ***************************************************************************
+--Updata to Lelian
+
+--Ps 需要改动的地方LW_GATEWAY(乐联的设备标示),USERKEY(乐联userkey)
+--Ps You nees to rewrite the LW_GATEWAY(Lelian's Device ID),USERKEY(Lelian's userkey)
+
+tmr.alarm(0, 60000, 1, function()
+            SDA_PIN = 6 -- sda pin, GPIO12
+            SCL_PIN = 5 -- scl pin, GPIO14
+
+			BH1750 = require("BH1750")
+			BH1750.init(SDA_PIN, SCL_PIN)
+			BH1750.read(OSS)
+			l = BH1750.getlux()
+
+        --定义数据变量格式 Define the veriables formate
+        PostData = "[{\"Name\":\"T\",\"Value\":\"" ..(l / 100).."."..(l % 100).."\"}]"
+        --创建一个TCP连接 Create a TCP Connection
+        socket=net.createConnection(net.TCP, 0)
+        --域名解析IP地址并赋值  DNS...it 
+        socket:dns("www.lewei50.com", function(conn, ip)
+                ServerIP = ip
+                print("Connection IP:" .. ServerIP)
+                end)
+
+--开始连接服务器  Connect the sever
+socket:connect(80, ServerIP)
+ socket:on("connection", function(sck) end)
+
+--HTTP请求头定义  HTTP Head
+socket:send("POST /api/V1/gateway/UpdateSensors/LW_GATEWAY HTTP/1.1\r\n" ..
+ "Host: www.lewei50.com\r\n" ..
+ "Content-Length: " .. string.len(PostData) .. "\r\n" ..
+ "userkey: USERKEY\r\n\r\n" ..
+ PostData .. "\r\n")
+
+--HTTP响应内容  Print the HTTP response
+socket:on("receive", function(sck, response)
+ print(response)
+ end)
+ end)
+
+
+

+ 166 - 0
lua_modules/bmp085/bmp085.EN.md

@@ -0,0 +1,166 @@
+# BMP085 module
+
+##Require
+```lua
+bmp085 = require("bmp085")
+```
+## Release
+```lua
+bmp085 = nil
+package.loaded["bmp085"]=nil
+```
+<a id="bmp085_init"></a>
+##init()
+####Description
+Setting the i2c pin of bmp085.<br />
+
+####Syntax
+init(sda, scl)
+
+####Parameters
+sda: 1~12, IO index.<br />
+scl: 1~12, IO index.<br />
+
+####Returns
+nil
+
+####Example
+```lua
+bmp085 = require("bmp085")
+gpio5 = 1
+gpio4 = 2
+sda = gpio5
+scl = gpio4
+bmp085.init(sda, scl)
+-- Don't forget to release it after use
+bmp085 = nil
+package.loaded["bmp085"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="bmp085_getUP"></a>
+##getUP()
+####Description
+Get calibrated data of pressure from bmp085.<br />
+
+####Syntax
+getUP(oss)
+
+####Parameters
+oss: Over sampling setting, which is 0,1,2,3. Default value is 0.<br />
+
+####Returns
+p: Integer, calibrated data of pressure from bmp085.
+
+####Example
+```lua
+bmp085 = require("bmp085")
+sda = 1
+scl = 2
+bmp085.init(sda, scl)
+p = bmp085.getUP(oss)
+print(p)
+-- Don't forget to release it after use
+bmp085 = nil
+package.loaded["bmp085"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="bmp085_getUP_raw"></a>
+##getUP_raw()
+####Description
+Get raw data of pressure from bmp085.<br />
+
+####Syntax
+getUP_raw(oss)
+
+####Parameters
+oss: Over sampling setting, which is 0,1,2,3. Default value is 0.<br />
+
+####Returns
+up_raw: Integer, raw data of pressure from bmp085.
+
+####Example
+```lua
+bmp085 = require("bmp085")
+sda = 1
+scl = 2
+bmp085.init(sda, scl)
+up = bmp085.getUP_raw(oss)
+print(up)
+-- Don't forget to release it after use
+bmp085 = nil
+package.loaded["bmp085"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="bmp085_getUT"></a>
+##getUT()
+####Description
+Get temperature from bmp085.<br />
+
+####Syntax
+getUT(num_10x)
+
+####Parameters
+num_10x: num_10x: bool value, if true, return number of 0.1 centi-degree. Default value is false, which return a string , eg: 16.7.<br />
+
+####Returns
+t: Integer or String, if num_10x is true, return number of 0.1 centi-degree, otherwise return a string.The temperature from bmp085.<br />
+
+####Example
+```lua
+bmp085 = require("bmp085")
+sda = 1
+scl = 2
+bmp085.init(sda, scl)
+-- Get string of temperature.
+p = bmp085.getUT(false)
+print(p)
+-- Get number of temperature.
+p = bmp085.getUT(true)
+print(p)
+-- Don't forget to release it after use
+bmp085 = nil
+package.loaded["bmp085"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="bmp085_getAL"></a>
+##getAL()
+####Description
+Get estimated data of altitude from bmp085.<br />
+
+####Syntax
+getAL(oss)
+
+####Parameters
+oss: over sampling setting, which is 0,1,2,3. Default value is 0.<br />
+
+####Returns
+e: Integer, estimated data of altitude. Altitudi can be calculated by pressure refer to sea level pressure, which is 101325. Pressure changes 100pa corresponds to 8.43m at sea level<br />
+
+####Example
+```lua
+bmp085 = require("bmp085")
+sda = 1
+scl = 2
+bmp085.init(sda, scl)
+-- Get string of temperature.
+e = bmp085.getAL()
+print(p)
+-- Don't forget to release it after use
+bmp085 = nil
+package.loaded["bmp085"]=nil
+```
+
+####See also
+**-**   []()

+ 0 - 0
lua_modules/bmp085.lua → lua_modules/bmp085/bmp085.lua


+ 52 - 0
lua_modules/dht22/README.md

@@ -0,0 +1,52 @@
+# DHT22 module
+
+This module is compatible with DHT22 and DHT21.  
+No need to use a resistor to connect the pin data of DHT22 to ESP8266.
+
+## Example  
+```lua
+PIN = 4 --  data pin, GPIO2
+
+dht22 = require("dht22")
+dht22.read(PIN)
+t = dht22.getTemperature()
+h = dht22.getHumidity()
+
+if h == -1 then
+  print("Error reading from DHT22")
+else
+  -- temperature in degrees Celsius  and Farenheit
+  print("Temperature: "..(t / 10).."."..(t % 10).." deg C")
+  print("Temperature: "..(9 * t / 50 + 32).."."..(9 * t / 5 % 10).." deg F")
+
+  -- humidity
+  print("Humidity: "..(h/10).."."..(h%10).."%")
+end
+
+-- release module
+dht22 = nil
+package.loaded["dht22"]=nil
+```
+## Functions
+### read
+read(pin) 
+Read humidity and temperature from DHT22.
+
+**Parameters:**
+
+* pin - ESP8266 pin connect to data pin in DHT22
+
+### getHumidity
+getHumidity()  
+Returns the humidity of the last reading.
+
+**Returns:**  
+* last humidity reading in per thousand
+
+### getTemperature
+getTemperature()  
+Returns the temperature of the last reading.
+
+**Returns:**  
+* last temperature reading in 0.1ºC
+

+ 100 - 0
lua_modules/dht22/dht22.lua

@@ -0,0 +1,100 @@
+-- ***************************************************************************
+-- DHT22 module for ESP8266 with nodeMCU
+--
+-- Written by Javier Yanez 
+-- but based on a script of Pigs Fly from ESP8266.com forum
+--
+-- MIT license, http://opensource.org/licenses/MIT
+-- ***************************************************************************
+
+local moduleName = ...
+local M = {}
+_G[moduleName] = M
+
+local humidity
+local temperature
+
+function M.read(pin)
+  local checksum
+  local checksumTest
+  humidity = 0
+  temperature = 0
+  checksum = 0
+
+  -- Use Markus Gritsch trick to speed up read/write on GPIO
+  local gpio_read = gpio.read
+  
+  local bitStream = {}
+  for j = 1, 40, 1 do
+    bitStream[j] = 0
+  end
+  local bitlength = 0
+
+  -- Step 1:  send out start signal to DHT22
+  gpio.mode(pin, gpio.OUTPUT)
+  gpio.write(pin, gpio.HIGH)
+  tmr.delay(100)
+  gpio.write(pin, gpio.LOW)
+  tmr.delay(20000)
+  gpio.write(pin, gpio.HIGH)
+  gpio.mode(pin, gpio.INPUT)
+
+  -- Step 2:  DHT22 send response signal 
+  -- bus will always let up eventually, don't bother with timeout
+  while (gpio_read(pin) == 0 ) do end
+  local c=0
+  while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
+  -- bus will always let up eventually, don't bother with timeout
+  while (gpio_read(pin) == 0 ) do end
+  c=0
+  while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
+  
+  -- Step 3: DHT22 send data
+  for j = 1, 40, 1 do
+    while (gpio_read(pin) == 1 and bitlength < 10 ) do
+      bitlength = bitlength + 1
+    end
+    bitStream[j] = bitlength
+    bitlength = 0
+    -- bus will always let up eventually, don't bother with timeout
+    while (gpio_read(pin) == 0) do end
+  end
+
+  --DHT data acquired, process.
+  for i = 1, 16, 1 do
+    if (bitStream[i] > 4) then
+      humidity = humidity + 2 ^ (16 - i)
+    end
+  end
+  for i = 1, 16, 1 do
+    if (bitStream[i + 16] > 4) then
+      temperature = temperature + 2 ^ (16 - i)
+    end
+  end
+  for i = 1, 8, 1 do
+    if (bitStream[i + 32] > 4) then
+      checksum = checksum + 2 ^ (8 - i)
+    end
+  end
+
+  checksumTest=((humidity / 256) + (humidity % 256) + (temperature / 256) + (temperature % 256)) % 256
+
+  if temperature > 0x8000 then
+    -- convert to negative format
+    temperature = -(temperature - 0x8000)
+  end
+
+  if checksum ~= checksumTest then
+    humidity = -1
+  end
+end
+
+function M.getTemperature()
+  return temperature
+end
+
+function M.getHumidity()
+  return humidity
+end
+
+return M

+ 0 - 0
lua_modules/ds18b20/ds18b20.CN.md → lua_modules/ds18b20/ds18b20.ZH.md


+ 68 - 68
lua_modules/ds18b20/ds18b20.lua

@@ -35,27 +35,27 @@ setfenv(1,M)
 C = 0
 F = 1
 K = 2
-function setup(dq) 
-    pin = dq
-	if(pin == nil) then
-		pin = defaultPin		
-	end
-	ow.setup(pin)
+function setup(dq)
+  pin = dq
+  if(pin == nil) then
+    pin = defaultPin
+  end
+  ow.setup(pin)
 end
 
 function addrs()
-	setup(pin)
-	tbl = {}
-	ow.reset_search(pin)
-	repeat
-		addr = ow.search(pin)
-		if(addr ~= nil) then
-			table.insert(tbl, addr)	
-		end
-		tmr.wdclr()
-	until (addr == nil)
-	ow.reset_search(pin)
-	return tbl
+  setup(pin)
+  tbl = {}
+  ow.reset_search(pin)
+  repeat
+    addr = ow.search(pin)
+    if(addr ~= nil) then
+      table.insert(tbl, addr)
+    end
+    tmr.wdclr()
+  until (addr == nil)
+  ow.reset_search(pin)
+  return tbl
 end
 
 function readNumber(addr, unit)
@@ -64,71 +64,71 @@ function readNumber(addr, unit)
   flag = false
   if(addr == nil) then
     ow.reset_search(pin)
-	count = 0
+    count = 0
     repeat
-		count = count + 1
-		addr = ow.search(pin)
-		tmr.wdclr()
-	until((addr ~= nil) or (count > 100))
-	ow.reset_search(pin)
-  end	
+      count = count + 1
+      addr = ow.search(pin)
+      tmr.wdclr()
+    until((addr ~= nil) or (count > 100))
+    ow.reset_search(pin)
+  end
   if(addr == nil) then
-	return result
+    return result
   end
   crc = ow.crc8(string.sub(addr,1,7))
   if (crc == addr:byte(8)) then
     if ((addr:byte(1) == 0x10) or (addr:byte(1) == 0x28)) then
-        -- print("Device is a DS18S20 family device.")
-        ow.reset(pin)
-        ow.select(pin, addr)
-        ow.write(pin, 0x44, 1)
-        -- tmr.delay(1000000)
-        present = ow.reset(pin)
-        ow.select(pin, addr)
-        ow.write(pin,0xBE,1)
-        -- print("P="..present)  
-        data = nil
-        data = string.char(ow.read(pin))
-        for i = 1, 8 do
-            data = data .. string.char(ow.read(pin))
+      -- print("Device is a DS18S20 family device.")
+      ow.reset(pin)
+      ow.select(pin, addr)
+      ow.write(pin, 0x44, 1)
+      -- tmr.delay(1000000)
+      present = ow.reset(pin)
+      ow.select(pin, addr)
+      ow.write(pin,0xBE,1)
+      -- print("P="..present)
+      data = nil
+      data = string.char(ow.read(pin))
+      for i = 1, 8 do
+        data = data .. string.char(ow.read(pin))
+      end
+      -- print(data:byte(1,9))
+      crc = ow.crc8(string.sub(data,1,8))
+      -- print("CRC="..crc)
+      if (crc == data:byte(9)) then
+        if(unit == nil or unit == C) then
+          t = (data:byte(1) + data:byte(2) * 256) * 625
+        elseif(unit == F) then
+          t = (data:byte(1) + data:byte(2) * 256) * 1125 + 320000
+        elseif(unit == K) then
+          t = (data:byte(1) + data:byte(2) * 256) * 625 + 2731500
+        else
+          return nil
         end
-        -- print(data:byte(1,9))
-        crc = ow.crc8(string.sub(data,1,8))
-        -- print("CRC="..crc)
-        if (crc == data:byte(9)) then
-			if(unit == nil or unit == C) then
-				t = (data:byte(1) + data:byte(2) * 256) * 625
-			elseif(unit == F) then
-				t = (data:byte(1) + data:byte(2) * 256) * 1125 + 320000 
-			elseif(unit == K) then
-				t = (data:byte(1) + data:byte(2) * 256) * 625 + 2731500
-			else
-				return nil
-			end            
-            t1 = t / 10000
-            t2 = t % 10000
-            -- print("Temperature="..t1.."."..t2.." Centigrade")
-			-- result = t1.."."..t2
-			return t1, t2
-        end                   
-        tmr.wdclr()
+        t1 = t / 10000
+        t2 = t % 10000
+        -- print("Temperature="..t1.."."..t2.." Centigrade")
+        -- result = t1.."."..t2
+        return t1, t2
+      end
+      tmr.wdclr()
     else
-     -- print("Device family is not recognized.")
+    -- print("Device family is not recognized.")
     end
   else
-   -- print("CRC is not valid!")
+  -- print("CRC is not valid!")
   end
   return result
 end
 
 function read(addr, unit)
-	t1, t2 = readNumber(addr, unit)
-	if((t1 == nil ) or (t2 ==nil)) then
-		return nil
-	else	
-		return t1.."."..t2
-	end
+  t1, t2 = readNumber(addr, unit)
+  if((t1 == nil ) or (t2 ==nil)) then
+    return nil
+  else
+    return t1.."."..t2
+  end
 end
 
 -- Return module table
-return M
+return M

+ 15 - 0
lua_modules/ds3231/ds3231-example.lua

@@ -0,0 +1,15 @@
+require("ds3231")
+
+-- ESP-01 GPIO Mapping
+gpio0, gpio2 = 3, 4
+
+ds3231.init(gpio0, gpio2)
+
+second, minute, hour, day, date, month, year = ds3231.getTime();
+
+-- Get current time
+print(string.format("Time & Date: %s:%s:%s %s/%s/%s", hour, minute, second, date, month, year))
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil

+ 54 - 0
lua_modules/ds3231/ds3231-web.lua

@@ -0,0 +1,54 @@
+require('ds3231')
+
+port = 80
+
+-- ESP-01 GPIO Mapping
+gpio0, gpio2 = 3, 4
+
+days = {
+    [1] = "Sunday",
+    [2] = "Monday",
+    [3] = "Tuesday",
+    [4] = "Wednesday",
+    [5] = "Thursday",
+    [6] = "Friday",
+    [7] = "Saturday"
+}
+
+months = {
+    [1] = "January",
+    [2] = "Febuary",
+    [3] = "March",
+    [4] = "April",
+    [5] = "May",
+    [6] = "June",
+    [7] = "July",
+    [8] = "August",
+    [9] = "September",
+    [10] = "October",
+    [11] = "November",
+    [12] = "December"
+}
+
+ds3231.init(gpio0, gpio2)
+
+srv=net.createServer(net.TCP)
+srv:listen(port,
+    function(conn)
+
+        second, minute, hour, day, date, month, year = ds3231.getTime()
+        prettyTime = string.format("%s, %s %s %s %s:%s:%s", days[day], date, months[month], year, hour, minute, second)
+
+        conn:send("HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" ..
+            "<!DOCTYPE HTML>" ..
+            "<html><body>" ..
+            "<b>ESP8266</b></br>" ..
+            "Time and Date: " .. prettyTime .. "<br>" ..
+            "Node ChipID : " .. node.chipid() .. "<br>" ..
+            "Node MAC : " .. wifi.sta.getmac() .. "<br>" ..
+            "Node Heap : " .. node.heap() .. "<br>" ..
+            "Timer Ticks : " .. tmr.now() .. "<br>" ..
+            "</html></body>")
+        conn:on("sent",function(conn) conn:close() end)
+    end
+)

+ 114 - 0
lua_modules/ds3231/ds3231.EN.md

@@ -0,0 +1,114 @@
+#DS3231 Module
+##Require
+```lua
+ds3231 = require("ds3231")
+```
+## Release
+```lua
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+<a id="ds3231_init"></a>
+##init()
+####Description
+Setting the pins of DS3231.
+
+####Syntax
+init(sda, scl)
+
+####Parameters
+sda: 1~10, IO index.  
+scl: 1~10, IO index.
+
+####Returns
+nil
+
+####Example
+```lua
+ds3231 = require("ds3231")
+ds3231.init(3, 4)
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
+####See also
+**-**   []()
+
+
+<a id="ds3231_settime"></a>
+## setTime()
+####Description
+Sets the current date and time.
+
+####Syntax
+setTime(second, minute, hour, day, date, month, year)
+
+####Parameters
+second: 00-59  
+minute: 00-59  
+hour: 00-23  
+day: 1-7 (Sunday = 1, Saturday = 7)  
+date: 01-31  
+month: 01-12  
+year: 00-99
+
+####Returns
+nil
+
+####Example
+```lua
+ds3231 = require("ds3231")
+ds3231.init(3, 4)
+
+-- Set date and time to Sunday, January 18th 2015 6:30PM
+ds3231.setTime(0, 30, 18, 1, 18, 1, 15);
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+```
+
+####See also
+**-**   []()
+
+
+<a id="ds3231_getTime"></a>
+## getTime()
+####Description
+Get the current date and time.
+
+####Syntax
+getTime()
+
+####Parameters
+nil
+
+####Returns
+second: integer. Second 00-59  
+minute: integer. Minute 00-59  
+hour: integer. Hour 00-23  
+day: integer. Day 1-7 (Sunday = 1, Saturday = 7)  
+date: integer. Date 01-31  
+month: integer. Month 01-12  
+year: integer. Year 00-99  
+
+####Example
+```lua
+ds3231=require("ds3231")
+ds3231.init(3, 4)
+
+-- Get date and time
+second, minute, hour, day, date, month, year = ds3231.getTime();
+
+-- Print date and time
+print(string.format("Time & Date: %s:%s:%s %s/%s/%s", 
+    hour, minute, second, date, month, year))
+
+-- Don't forget to release it after use
+ds3231 = nil
+package.loaded["ds3231"]=nil
+
+```
+####See also
+**-**   []()

+ 75 - 0
lua_modules/ds3231/ds3231.lua

@@ -0,0 +1,75 @@
+--------------------------------------------------------------------------------
+-- DS3231 I2C module for NODEMCU
+-- NODEMCU TEAM
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Tobie Booth <tbooth@hindbra.in>
+--------------------------------------------------------------------------------
+
+local moduleName = ...
+local M = {}
+_G[moduleName] = M
+
+-- Default value for i2c communication
+local id = 0
+
+--device address
+local dev_addr = 0x68
+
+local function decToBcd(val)
+  return((val/10*16) + (val%10))
+end
+
+local function bcdToDec(val)
+  return((val/16*10) + (val%16))
+end
+
+-- initialize i2c
+--parameters:
+--d: sda
+--l: scl
+function M.init(d, l)
+  if (d ~= nil) and (l ~= nil) and (d >= 0) and (d <= 11) and (l >= 0) and ( l <= 11) and (d ~= l) then
+    sda = d
+    scl = l
+  else
+    print("iic config failed!") return nil
+  end
+    print("init done")
+    i2c.setup(id, sda, scl, i2c.SLOW)
+end
+
+--get time from DS3231
+function M.getTime()
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x00)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.RECEIVER)
+  local c=i2c.read(id, 7)
+  i2c.stop(id)
+  return bcdToDec(tonumber(string.byte(c, 1))),
+  bcdToDec(tonumber(string.byte(c, 2))),
+  bcdToDec(tonumber(string.byte(c, 3))),
+  bcdToDec(tonumber(string.byte(c, 4))),
+  bcdToDec(tonumber(string.byte(c, 5))),
+  bcdToDec(tonumber(string.byte(c, 6))),
+  bcdToDec(tonumber(string.byte(c, 7)))
+end
+
+--set time for DS3231
+function M.setTime(second, minute, hour, day, date, month, year)
+  i2c.start(id)
+  i2c.address(id, dev_addr, i2c.TRANSMITTER)
+  i2c.write(id, 0x00)
+  i2c.write(id, decToBcd(second))
+  i2c.write(id, decToBcd(minute))
+  i2c.write(id, decToBcd(hour))
+  i2c.write(id, decToBcd(day))
+  i2c.write(id, decToBcd(date))
+  i2c.write(id, decToBcd(month))
+  i2c.write(id, decToBcd(year))
+  i2c.stop(id)
+end
+
+return M

+ 39 - 0
lua_modules/http/http-example.lua

@@ -0,0 +1,39 @@
+------------------------------------------------------------------------------
+-- HTTP server Hello world example
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov <dronnikov@gmail.com>
+------------------------------------------------------------------------------
+require("http").createServer(80, function(req, res)
+  -- analyse method and url
+  print("+R", req.method, req.url, node.heap())
+  -- setup handler of headers, if any
+  req.onheader = function(self, name, value)
+    -- print("+H", name, value)
+    -- E.g. look for "content-type" header,
+    --   setup body parser to particular format
+    -- if name == "content-type" then
+    --   if value == "application/json" then
+    --     req.ondata = function(self, chunk) ... end
+    --   elseif value == "application/x-www-form-urlencoded" then
+    --     req.ondata = function(self, chunk) ... end
+    --   end
+    -- end
+  end
+  -- setup handler of body, if any
+  req.ondata = function(self, chunk)
+    print("+B", chunk and #chunk, node.heap())
+    -- request ended?
+    if not chunk then
+      -- reply
+      --res:finish("")
+      res:send(nil, 200)
+      res:send_header("Connection", "close")
+      res:send("Hello, world!")
+      res:finish()
+    end
+  end
+  -- or just do something not waiting till body (if any) comes
+  --res:finish("Hello, world!")
+  --res:finish("Salut, monde!")
+end)

+ 212 - 0
lua_modules/http/http.lua

@@ -0,0 +1,212 @@
+------------------------------------------------------------------------------
+-- HTTP server module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov <dronnikov@gmail.com>
+------------------------------------------------------------------------------
+local collectgarbage, tonumber, tostring = collectgarbage, tonumber, tostring
+
+local http
+do
+  ------------------------------------------------------------------------------
+  -- request methods
+  ------------------------------------------------------------------------------
+  local make_req = function(conn, method, url)
+    local req = {
+      conn = conn,
+      method = method,
+      url = url,
+    }
+    -- return setmetatable(req, {
+    -- })
+    return req
+  end
+
+  ------------------------------------------------------------------------------
+  -- response methods
+  ------------------------------------------------------------------------------
+  local send = function(self, data, status)
+    local c = self.conn
+    -- TODO: req.send should take care of response headers!
+    if self.send_header then
+      c:send("HTTP/1.1 ")
+      c:send(tostring(status or 200))
+      -- TODO: real HTTP status code/name table
+      c:send(" OK\r\n")
+      -- we use chunked transfer encoding, to not deal with Content-Length:
+      --   response header
+      self:send_header("Transfer-Encoding", "chunked")
+      -- TODO: send standard response headers, such as Server:, Date:
+    end
+    if data then
+      -- NB: no headers allowed after response body started
+      if self.send_header then
+        self.send_header = nil
+        -- end response headers
+        c:send("\r\n")
+      end
+      -- chunked transfer encoding
+      c:send(("%X\r\n"):format(#data))
+      c:send(data)
+      c:send("\r\n")
+    end
+  end
+  local send_header = function(self, name, value)
+    local c = self.conn
+    -- NB: quite a naive implementation
+    c:send(name)
+    c:send(": ")
+    c:send(value)
+    c:send("\r\n")
+  end
+  -- finalize request, optionally sending data
+  local finish = function(self, data, status)
+    local c = self.conn
+    -- NB: req.send takes care of response headers
+    if data then
+      self:send(data, status)
+    end
+    -- finalize chunked transfer encoding
+    c:send("0\r\n\r\n")
+    -- close connection
+    c:close()
+  end
+  --
+  local make_res = function(conn)
+    local res = {
+      conn = conn,
+    }
+    -- return setmetatable(res, {
+    --  send_header = send_header,
+    --  send = send,
+    --  finish = finish,
+    -- })
+    res.send_header = send_header
+    res.send = send
+    res.finish = finish
+    return res
+  end
+
+    ------------------------------------------------------------------------------
+  -- HTTP parser
+  ------------------------------------------------------------------------------
+  local http_handler = function(handler)
+    return function(conn)
+      local req, res
+      local buf = ""
+      local method, url
+      local ondisconnect = function(conn)
+        collectgarbage("collect")
+      end
+      -- header parser
+      local cnt_len = 0
+      local onheader = function(conn, k, v)
+        -- TODO: look for Content-Type: header
+        -- to help parse body
+        -- parse content length to know body length
+        if k == "content-length" then
+          cnt_len = tonumber(v)
+        end
+        if k == "expect" and v == "100-continue" then
+          conn:send("HTTP/1.1 100 Continue\r\n")
+        end
+        -- delegate to request object
+        if req and req.onheader then
+          req:onheader(k, v)
+        end
+      end
+      -- body data handler
+      local body_len = 0
+      local ondata = function(conn, chunk)
+        -- NB: do not reset node in case of lengthy requests
+        tmr.wdclr()
+        -- feed request data to request handler
+        if not req or not req.ondata then return end
+        req:ondata(chunk)
+        -- NB: once length of seen chunks equals Content-Length:
+        --   onend(conn) is called
+        body_len = body_len + #chunk
+        -- print("-B", #chunk, body_len, cnt_len, node.heap())
+        if body_len >= cnt_len then
+          req:ondata()
+        end
+      end
+      local onreceive = function(conn, chunk)
+        -- merge chunks in buffer
+        if buf then
+          buf = buf .. chunk
+        else
+          buf = chunk
+        end
+        -- consume buffer line by line
+        while #buf > 0 do
+          -- extract line
+          local e = buf:find("\r\n", 1, true)
+          if not e then break end
+          local line = buf:sub(1, e - 1)
+          buf = buf:sub(e + 2)
+          -- method, url?
+          if not method then
+            local i
+            -- NB: just version 1.1 assumed
+            _, i, method, url = line:find("^([A-Z]+) (.-) HTTP/1.1$")
+            if method then
+              -- make request and response objects
+              req = make_req(conn, method, url)
+              res = make_res(conn)
+            end
+          -- header line?
+          elseif #line > 0 then
+            -- parse header
+            local _, _, k, v = line:find("^([%w-]+):%s*(.+)")
+            -- header seems ok?
+            if k then
+              k = k:lower()
+              onheader(conn, k, v)
+            end
+          -- headers end
+          else
+            -- spawn request handler
+            -- NB: do not reset in case of lengthy requests
+            tmr.wdclr()
+            handler(req, res)
+            tmr.wdclr()
+            -- NB: we feed the rest of the buffer as starting chunk of body
+            ondata(conn, buf)
+            -- buffer no longer needed
+            buf = nil
+            -- NB: we explicitly reassign receive handler so that
+            --   next received chunks go directly to body handler
+            conn:on("receive", ondata)
+            -- parser done
+            break
+          end
+        end
+      end
+      conn:on("receive", onreceive)
+      conn:on("disconnection", ondisconnect)
+    end
+  end
+
+  ------------------------------------------------------------------------------
+  -- HTTP server
+  ------------------------------------------------------------------------------
+  local srv
+  local createServer = function(port, handler)
+    -- NB: only one server at a time
+    if srv then srv:close() end
+    srv = net.createServer(net.TCP, 15)
+    -- listen
+    srv:listen(port, http_handler(handler))
+    return srv
+  end
+
+  ------------------------------------------------------------------------------
+  -- HTTP server methods
+  ------------------------------------------------------------------------------
+  http = {
+    createServer = createServer,
+  }
+end
+
+return http

+ 24 - 0
lua_modules/si7021/si7021-example.lua

@@ -0,0 +1,24 @@
+
+tmr.alarm(0, 60000, 1, function()
+
+	SDA_PIN = 6 -- sda pin, GPIO12
+	SCL_PIN = 5 -- scl pin, GPIO14
+
+	si7021 = require("si7021")
+	si7021.init(SDA_PIN, SCL_PIN)
+	si7021.read(OSS)
+	h = si7021.getHumidity()
+	t = si7021.getTemperature()
+
+	-- pressure in differents units
+	print("Humidity: "..(h / 100).."."..(h % 100).." %")
+
+	-- temperature in degrees Celsius  and Farenheit
+	print("Temperature: "..(t/100).."."..(t%100).." deg C")
+	print("Temperature: "..(9 * t / 500 + 32).."."..(9 * t / 50 % 10).." deg F")
+
+	-- release module
+	si7021 = nil
+	package.loaded["si7021"]=nil
+
+end)

+ 41 - 0
lua_modules/si7021/si7021-lewei.lua

@@ -0,0 +1,41 @@
+
+    --创建一个定时器
+    tmr.alarm(0, 60000, 1, function()
+
+		SDA_PIN = 6 -- sda pin, GPIO12
+		SCL_PIN = 5 -- scl pin, GPIO14
+
+		si7021 = require("si7021")
+		si7021.init(SDA_PIN, SCL_PIN)
+		si7021.read(OSS)
+		Hum = si7021.getHumidity()
+		Temp = si7021.getTemperature()
+
+    	--定义数据变量格式
+    	PostData = "[{\"Name\":\"T\",\"Value\":\"" .. (Temp/100).."."..(Temp%100) .. "\"},{\"Name\":\"H\",\"Value\":\"" .. (Hum/100).."."..(Hum%100) .. "\"}]"
+    	--创建一个TCP连接
+    	socket=net.createConnection(net.TCP, 0)
+    	--域名解析IP地址并赋值
+    	socket:dns("www.lewei50.com", function(conn, ip)
+    		ServerIP = ip
+    		print("Connection IP:" .. ServerIP)
+    		end)
+    	--开始连接服务器
+    	socket:connect(80, ServerIP)
+    	socket:on("connection", function(sck) end)
+    	--HTTP请求头定义
+    	socket:send("POST /api/V1/gateway/UpdateSensors/yourID HTTP/1.1\r\n" ..
+    				"Host: www.lewei50.com\r\n" ..
+    				"Content-Length: " .. string.len(PostData) .. "\r\n" ..
+    				"userkey: yourKEY\r\n\r\n" ..
+    				PostData .. "\r\n")
+    	--HTTP响应内容
+    	socket:on("receive", function(sck, response)
+    		print(response)
+    		end)
+
+		-- release module
+		si7021 = nil
+		package.loaded["si7021"]=nil
+
+	    end)

+ 131 - 0
lua_modules/si7021/si7021.EN.md

@@ -0,0 +1,131 @@
+# si7021 module
+
+##Require
+```lua
+si7021 = require("si7021")
+```
+## Release
+```lua
+si7021 = nil
+package.loaded["si7021"]=nil
+```
+<a id="si7021_init"></a>
+##init()
+####Description
+Setting the i2c pin of si7021.<br />
+
+####Syntax
+init(sda, scl)
+
+####Parameters
+sda: 1~12, IO index.<br />
+scl: 1~12, IO index.<br />
+
+####Returns
+nil
+
+####Example
+```lua
+si7021 = require("si7021")
+gpio5 = 1
+gpio4 = 2
+sda = gpio5
+scl = gpio4
+si7021.init(sda, scl)
+-- Don't forget to release it after use
+si7021 = nil
+package.loaded["si7021"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="si7021_read"></a>
+##read()
+####Description
+Read temperature and humidity from si7021.<br />
+
+####Syntax
+read()
+
+####Parameters
+nil.<br />
+
+####Returns
+nil(Why?).<br />
+
+####Example
+```lua
+si7021 = require("si7021")
+sda = 1
+scl = 2
+si7021.init(sda, scl)
+r = si7021.read()
+print(r)
+-- Don't forget to release it after use
+si7021 = nil
+package.loaded["si7021"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="si7021_getHumidity"></a>
+##getHumidity()
+####Description
+Get humidity from si7021.<br />
+
+####Syntax
+getHumidity()
+
+####Parameters
+nil.<br />
+
+####Returns
+h: Integer, humidity from si7021.
+
+####Example
+```lua
+si7021 = require("si7021")
+sda = 1
+scl = 2
+si7021.init(sda, scl)
+h = si7021.getHumidity()
+print(h)
+-- Don't forget to release it after use
+si7021 = nil
+package.loaded["si7021"]=nil
+```
+
+####See also
+**-**   []()
+
+<a id="si7021_getTemperature"></a>
+##getTemperature()
+####Description
+Get temperature from si7021.<br />
+
+####Syntax
+getTemperature()
+
+####Parameters
+nil.<br />
+
+####Returns
+t: Integer, temperature from si7021.
+
+####Example
+```lua
+si7021 = require("si7021")
+sda = 1
+scl = 2
+si7021.init(sda, scl)
+t = si7021.getTemperature()
+print(t)
+-- Don't forget to release it after use
+si7021 = nil
+package.loaded["si7021"]=nil
+```
+
+####See also
+**-**   []()

+ 104 - 0
lua_modules/si7021/si7021.lua

@@ -0,0 +1,104 @@
+-- ***************************************************************************
+-- SI7021 module for ESP8266 with nodeMCU
+-- Si7021 compatible tested 2015-1-22
+--
+-- Written by VIP6
+--
+-- MIT license, http://opensource.org/licenses/MIT
+-- ***************************************************************************
+
+local moduleName = ...
+local M = {}
+_G[moduleName] = M
+
+--I2C slave address of Si70xx
+local Si7021_ADDR = 0x40
+
+--Commands
+local CMD_MEASURE_HUMIDITY_HOLD = 0xE5
+local CMD_MEASURE_HUMIDITY_NO_HOLD = 0xF5
+local CMD_MEASURE_TEMPERATURE_HOLD = 0xE3
+local CMD_MEASURE_TEMPERATURE_NO_HOLD = 0xF3
+
+
+-- temperature and pressure
+local t,h
+
+local init = false
+
+-- i2c interface ID
+local id = 0
+
+-- 16-bit  two's complement
+-- value: 16-bit integer
+local function twoCompl(value)
+ if value > 32767 then value = -(65535 - value + 1)
+ end
+ return value
+end
+
+
+
+-- read data from si7021
+-- ADDR: slave address
+-- commands: Commands of si7021
+-- length: bytes to read
+local function read_data(ADDR, commands, length)
+  i2c.start(id)
+  i2c.address(id, ADDR, i2c.TRANSMITTER)
+  i2c.write(id, commands)
+  i2c.stop(id)
+  i2c.start(id)
+  i2c.address(id, ADDR,i2c.RECEIVER)
+  tmr.delay(20000)
+  c = i2c.read(id, length)
+  i2c.stop(id)
+  return c
+end
+
+-- initialize module
+-- sda: SDA pin
+-- scl SCL pin
+function M.init(sda, scl)
+  i2c.setup(id, sda, scl, i2c.SLOW)
+  --print("i2c ok..")
+  init = true
+end
+
+-- read humidity from si7021
+local function read_humi()
+  dataH = read_data(Si7021_ADDR, CMD_MEASURE_HUMIDITY_HOLD, 2)
+  UH = string.byte(dataH, 1) * 256 + string.byte(dataH, 2)
+  h = ((UH*12500+65536/2)/65536 - 600)
+  return(h)
+end
+
+-- read temperature from si7021
+local function read_temp()
+  dataT = read_data(Si7021_ADDR, CMD_MEASURE_TEMPERATURE_HOLD, 2)
+  UT = string.byte(dataT, 1) * 256 + string.byte(dataT, 2)
+  t = ((UT*17572+65536/2)/65536 - 4685)
+  return(t)
+end
+
+-- read temperature and humidity from si7021
+function M.read()
+  if (not init) then
+     print("init() must be called before read.")
+  else
+	 read_humi()
+	 read_temp()
+  end
+end;
+
+-- get humidity
+function M.getHumidity()
+  return h
+end
+
+-- get temperature
+function M.getTemperature()
+  return t
+end
+
+return M

+ 0 - 0
pre_build/0.9.5/nodemcu_latest.bin → pre_build/0.9.5/nodemcu_20150108.bin


BIN
pre_build/0.9.5/nodemcu_20150118.bin


BIN
pre_build/0.9.5/nodemcu_20150123.bin


BIN
pre_build/0.9.5/nodemcu_20150126.bin


BIN
pre_build/latest/nodemcu_latest.bin


+ 11 - 0
tools/.gitattributes

@@ -0,0 +1,11 @@
+# Enforce Unix newlines
+*.css   text eol=lf
+*.html  text eol=lf
+*.js    text eol=lf
+*.json  text eol=lf
+*.less  text eol=lf
+*.md    text eol=lf
+*.svg   text eol=lf
+*.yml   text eol=lf
+*.py	text eol=lf
+*.sh	text eol=lf