diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs
index 5f18488a..11153dfd 100644
--- a/.settings/org.eclipse.cdt.core.prefs
+++ b/.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
diff --git a/Makefile b/Makefile
index 58aaab83..6b4a545b 100644
--- a/Makefile
+++ b/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
diff --git a/README.md b/README.md
index 27cab97e..674c44e4 100644
--- a/README.md
+++ b/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)
+Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)
Lua core based on [eLua project](http://www.eluaproject.net/)
File system based on [spiffs](https://github.com/pellepl/spiffs)
Open source development kit for NodeMCU [nodemcu-devkit](https://github.com/nodemcu/nodemcu-devkit)
Flash tool for NodeMCU [nodemcu-flasher](https://github.com/nodemcu/nodemcu-flasher)
wiki: [nodemcu wiki](https://github.com/nodemcu/nodemcu-firmware/wiki)
+api: [nodemcu api](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en)
home: [nodemcu.com](http://www.nodemcu.com)
-bbs: [中文论坛Chinese bbs](http://bbs.nodemcu.com)
-Tencent QQ group QQ群: 309957875
+bbs: [Chinese bbs](http://bbs.nodemcu.com)
+Tencent QQ group: 309957875
# 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
+support floating point LUA.
+use macro LUA_NUMBER_INTEGRAL in user_config.h control this feature.
+LUA_NUMBER_INTEGRAL to disable floating point support,
+// LUA_NUMBER_INTEGRAL to enable floating point support.
+fix tmr.time(). #132
+fix filesystem length. #113
+fix ssl reboots. #134
+build pre_build bin.
+
+2015-01-26
+applied sdk095_patch1 to sdk 0.9.5.
+added LUA examples and modules [by dvv](https://github.com/dvv).
+added node.readvdd33() API [by alonewolfx2](https://github.com/alonewolfx2).
+build pre_build bin.
+
+2015-01-24
+migrate to sdk 0.9.5 release.
+tmr.time() now return second(not precise yet).
+build pre_build bin.
+
+2015-01-23
+merge mqtt branch to master.
+build pre_build bin.
+
+2015-01-18
+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).
+merge spi module from iabdalkader:spi.
+fix #110,set local port to random in client mode.
+modify gpio.read to NOT set pin to input mode automatic.
+add PATH env with C:\MinGW\bin;C:\MinGW\msys\1.0\bin;C:\Python27 in eclipse project. resolve #103.
+
2015-01-08
fix net.socket:send() issue when multi sends are called.
*NOTE*: if data length is bigger than 1460, send next packet AFTER "sent" callback is called.
fix file.read() api, take 0xFF as a regular byte, not EOF.
pre_build/latest/nodemcu_512k_latest.bin is removed. use pre_build/latest/nodemcu_latest.bin instead.
-2015-01-07
-retrive more ram back.
-add api file.format() to rebuild file system.
-rename "NodeMcu" to "NodeMCU" in firmware.
-add some check for file system op.
-
-[more change log](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en#change_log)
-[更多变更日志](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_cn#change_log)
+[more change log](https://github.com/nodemcu/nodemcu-firmware/wiki)
##GPIO NEW TABLE ( Build 20141219 and later)
@@ -75,39 +102,6 @@ add some check for file system op.
#### [*] D0(GPIO16) can only be used as gpio read/write. no interrupt supported. no pwm/i2c/ow supported.
-##GPIO OLD TABLE (Before build 20141212)
-
-
-
-
- IO index | ESP8266 pin | IO index | ESP8266 pin |
-
-
- 0 | GPIO12 | 8 | GPIO0 |
-
-
- 1 | GPIO13 | 9 | GPIO2 |
-
-
- 2 | GPIO14 | 10 | GPIO4 |
-
-
- 3 | GPIO15 | 11 | GPIO5 |
-
-
- 4 | GPIO3 | | |
-
-
- 5 | GPIO1 | | |
-
-
- 6 | GPIO9 | | |
-
-
- 7 | GPIO10 | |
-
-
-
#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.
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.
-eagle.app.v6.flash.bin: 0x00000
-eagle.app.v6.irom0text.bin: 0x10000
-esp_init_data_default.bin: 0x7c000
-blank.bin: 0x7e000
+0x00000.bin: 0x00000
+0x10000.bin: 0x10000
*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)
diff --git a/app/Makefile b/app/Makefile
index 753595d6..15ff75c4 100644
--- a/app/Makefile
+++ b/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
diff --git a/app/driver/i2c_master.c b/app/driver/i2c_master.c
index 24128eaa..772be691 100644
--- a/app/driver/i2c_master.c
+++ b/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
diff --git a/app/driver/pwm.c b/app/driver/pwm.c
index 7e1728fd..cc147d05 100644
--- a/app/driver/pwm.c
+++ b/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
diff --git a/app/driver/spi.c b/app/driver/spi.c
index a45b2d64..12c32b54 100644
--- a/app/driver/spi.c
+++ b/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<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)< 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) */
diff --git a/app/libc/c_math.h b/app/libc/c_math.h
index 65e31afe..ef18ee79 100644
--- a/app/libc/c_math.h
+++ b/app/libc/c_math.h
@@ -1,6 +1,10 @@
#ifndef _C_MATH_H_
#define _C_MATH_H_
#include
+
+double floor(double);
+double pow(double, double);
+
#if 0
#ifndef HUGE_VAL
#define HUGE_VAL (1.0e99)
diff --git a/app/libc/c_stdio.c b/app/libc/c_stdio.c
index 0d52d29c..43d7bd24 100644
--- a/app/libc/c_stdio.c
+++ b/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,
+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
diff --git a/app/libc/c_stdio.h b/app/libc/c_stdio.h
index d8302a38..88c368f6 100644
--- a/app/libc/c_stdio.h
+++ b/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]; \
diff --git a/app/libc/c_stdlib.c b/app/libc/c_stdlib.c
index 7115914d..fffd47b5 100644
--- a/app/libc/c_stdlib.c
+++ b/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
+#include
+//#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){
diff --git a/app/libc/c_stdlib.h b/app/libc/c_stdlib.h
index c290ee2e..3757c135 100644
--- a/app/libc/c_stdlib.h
+++ b/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);
diff --git a/app/lua/luaconf.h b/app/lua/luaconf.h
index 90da40dc..08c50c59 100644
--- a/app/lua/luaconf.h
+++ b/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 */
diff --git a/app/lua/lundump.c b/app/lua/lundump.c
index 92aa5b4f..b036e7a5 100644
--- a/app/lua/lundump.c
+++ b/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);
}
}
diff --git a/app/lua/lvm.c b/app/lua/lvm.c
index fe0243e2..06147856 100644
--- a/app/lua/lvm.c
+++ b/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
diff --git a/app/lwip/app/espconn_tcp.c b/app/lwip/app/espconn_tcp.c
index 9cc7129d..91843887 100644
--- a/app/lwip/app/espconn_tcp.c
+++ b/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);
diff --git a/app/modules/Makefile b/app/modules/Makefile
index 1d9f19d9..fb170792 100644
--- a/app/modules/Makefile
+++ b/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
diff --git a/app/modules/auxmods.h b/app/modules/auxmods.h
index d8166643..6ab6ef46 100644
--- a/app/modules/auxmods.h
+++ b/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 );
diff --git a/app/modules/modules.h b/app/modules/modules.h
index e58ca748..f28775d5 100644
--- a/app/modules/modules.h
+++ b/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 \
diff --git a/app/modules/mqtt.c b/app/modules/mqtt.c
new file mode 100644
index 00000000..332a9e87
--- /dev/null
+++ b/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
+}
diff --git a/app/modules/net.c b/app/modules/net.c
index dba4fc7e..92514c9b 100644
--- a/app/modules/net.c
+++ b/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);
}
diff --git a/app/modules/node.c b/app/modules/node.c
index 929aedd2..11b7b6b6 100644
--- a/app/modules/node.c
+++ b/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
diff --git a/app/modules/spi.c b/app/modules/spi.c
new file mode 100644
index 00000000..90d9468c
--- /dev/null
+++ b/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 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
+}
+
diff --git a/app/modules/tmr.c b/app/modules/tmr.c
index 7d67d6be..bd68503e 100644
--- a/app/modules/tmr.c
+++ b/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
diff --git a/app/modules/wifi.c b/app/modules/wifi.c
index e1bf6ea4..4acdd304 100644
--- a/app/modules/wifi.c
+++ b/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;
diff --git a/app/mqtt/Makefile b/app/mqtt/Makefile
new file mode 100644
index 00000000..3fd35717
--- /dev/null
+++ b/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
+
diff --git a/app/mqtt/mqtt_msg.c b/app/mqtt/mqtt_msg.c
new file mode 100644
index 00000000..5e49bfb1
--- /dev/null
+++ b/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
+#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);
+}
diff --git a/app/mqtt/mqtt_msg.h b/app/mqtt/mqtt_msg.h
new file mode 100644
index 00000000..225ba642
--- /dev/null
+++ b/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 */
+
diff --git a/app/platform/cpu_esp8266.h b/app/platform/cpu_esp8266.h
index 46689510..6e98e18a 100644
--- a/app/platform/cpu_esp8266.h
+++ b/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
diff --git a/app/platform/platform.c b/app/platform/platform.c
index 9db3f9f6..8480a3bb 100644
--- a/app/platform/platform.c
+++ b/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
diff --git a/app/platform/platform.h b/app/platform/platform.h
index 286dab2d..78452e3f 100644
--- a/app/platform/platform.h
+++ b/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 );
diff --git a/app/spiffs/spiffs.c b/app/spiffs/spiffs.c
index dc913754..4795ae5a 100644
--- a/app/spiffs/spiffs.c
+++ b/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);
diff --git a/app/upgrade/upgrade.c b/app/upgrade/upgrade.c
index 321a7328..8edc8486 100644
--- a/app/upgrade/upgrade.c
+++ b/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
diff --git a/app/user/user_main.c b/app/user/user_main.c
index 77c7939e..7d470e2c 100644
--- a/app/user/user_main.c
+++ b/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);
+}
diff --git a/examples/fragment.lua b/examples/fragment.lua
index 196232c1..b4fb10dd 100644
--- a/examples/fragment.lua
+++ b/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)
+
diff --git a/include/at_custom.h b/include/at_custom.h
new file mode 100644
index 00000000..a9b05c4c
--- /dev/null
+++ b/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 .
+ */
+
+#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
diff --git a/include/c_types.h b/include/c_types.h
index 88822345..55bffd46 100644
--- a/include/c_types.h
+++ b/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 */
diff --git a/include/espconn.h b/include/espconn.h
index 3fc3cb7e..2af5cf77 100644
--- a/include/espconn.h
+++ b/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
diff --git a/include/ip_addr.h b/include/ip_addr.h
index bd757a49..728a75c4 100644
--- a/include/ip_addr.h
+++ b/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), \
diff --git a/include/osapi.h b/include/osapi.h
index 055085f0..5fbdf0da 100644
--- a/include/osapi.h
+++ b/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
diff --git a/include/ping.h b/include/ping.h
new file mode 100644
index 00000000..4ecd032b
--- /dev/null
+++ b/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__ */
diff --git a/include/smartconfig.h b/include/smartconfig.h
new file mode 100644
index 00000000..02a1e317
--- /dev/null
+++ b/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
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 5918c6b3..12dd6e17 100644
--- a/include/spi_flash.h
+++ b/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);
diff --git a/include/user_interface.h b/include/user_interface.h
index 1306dfce..1f5a9352 100644
--- a/include/user_interface.h
+++ b/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
diff --git a/ld/eagle.app.v6.ld b/ld/eagle.app.v6.ld
index 608fafbd..3234dc02 100644
--- a/ld/eagle.app.v6.ld
+++ b/ld/eagle.app.v6.ld
@@ -5,7 +5,7 @@ MEMORY
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
- irom0_0_seg : org = 0x40210000, len = 0x50000
+ irom0_0_seg : org = 0x40210000, len = 0x51000
}
PHDRS
diff --git a/ld/eagle.rom.addr.v6.ld b/ld/eagle.rom.addr.v6.ld
index 0ca83963..076a240d 100644
--- a/ld/eagle.rom.addr.v6.ld
+++ b/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 );
diff --git a/lib/libat.a b/lib/libat.a
new file mode 100644
index 00000000..e1db9fa8
Binary files /dev/null and b/lib/libat.a differ
diff --git a/lib/libjson.a b/lib/libjson.a
index a9492522..f32c329d 100644
Binary files a/lib/libjson.a and b/lib/libjson.a differ
diff --git a/lib/liblwip.a b/lib/liblwip.a
index 04dd604a..6ef795bb 100644
Binary files a/lib/liblwip.a and b/lib/liblwip.a differ
diff --git a/lib/libmain.a b/lib/libmain.a
index 271a35fd..b0b90f98 100644
Binary files a/lib/libmain.a and b/lib/libmain.a differ
diff --git a/lib/libnet80211.a b/lib/libnet80211.a
index 7bcb84f0..5ae2da5c 100644
Binary files a/lib/libnet80211.a and b/lib/libnet80211.a differ
diff --git a/lib/libphy.a b/lib/libphy.a
index 5679e419..1598f206 100644
Binary files a/lib/libphy.a and b/lib/libphy.a differ
diff --git a/lib/libpp.a b/lib/libpp.a
index bf1a397d..17466205 100644
Binary files a/lib/libpp.a and b/lib/libpp.a differ
diff --git a/lib/libsmartconfig.a b/lib/libsmartconfig.a
new file mode 100644
index 00000000..f402b5f3
Binary files /dev/null and b/lib/libsmartconfig.a differ
diff --git a/lib/libssl.a b/lib/libssl.a
index 3fd56320..36b78fe2 100644
Binary files a/lib/libssl.a and b/lib/libssl.a differ
diff --git a/lib/libupgrade.a b/lib/libupgrade.a
index a4206383..051d683b 100644
Binary files a/lib/libupgrade.a and b/lib/libupgrade.a differ
diff --git a/lib/libwpa.a b/lib/libwpa.a
index 85f334ef..abd611b4 100644
Binary files a/lib/libwpa.a and b/lib/libwpa.a differ
diff --git a/lua_examples/irsend.lua b/lua_examples/irsend.lua
new file mode 100644
index 00000000..4ccd2ebb
--- /dev/null
+++ b/lua_examples/irsend.lua
@@ -0,0 +1,74 @@
+------------------------------------------------------------------------------
+-- IR send module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov
+--
+-- 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
diff --git a/lua_examples/tcp2uart.lua b/lua_examples/tcp2uart.lua
new file mode 100644
index 00000000..638a2d77
--- /dev/null
+++ b/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)
diff --git a/lua_examples/yet-another-dht22.lua b/lua_examples/yet-another-dht22.lua
new file mode 100644
index 00000000..1bf65458
--- /dev/null
+++ b/lua_examples/yet-another-dht22.lua
@@ -0,0 +1,84 @@
+------------------------------------------------------------------------------
+-- DHT11/22 query module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov
+--
+-- 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
diff --git a/lua_examples/yet-another-ds18b20.lua b/lua_examples/yet-another-ds18b20.lua
new file mode 100644
index 00000000..edcbe2d1
--- /dev/null
+++ b/lua_examples/yet-another-ds18b20.lua
@@ -0,0 +1,65 @@
+------------------------------------------------------------------------------
+-- DS18B20 query module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov
+--
+-- 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
diff --git a/lua_modules/bh1750/bh1750.lua b/lua_modules/bh1750/bh1750.lua
new file mode 100644
index 00000000..99131131
--- /dev/null
+++ b/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
diff --git a/lua_modules/bh1750/bh1750_CN.md b/lua_modules/bh1750/bh1750_CN.md
new file mode 100644
index 00000000..42815985
--- /dev/null
+++ b/lua_modules/bh1750/bh1750_CN.md
@@ -0,0 +1,104 @@
+# BH1750 模块
+
+##引用
+```lua
+bh1750 = require("bh1750")
+```
+## 释放
+```lua
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+##init()
+####描述
+设置BH1750所在的I2C引脚
+
+####语法
+init(sda, scl)
+
+####参数
+sda: 1~12, IO index.
+scl: 1~12, IO index.
+
+####返回值
+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
+```
+
+####参见
+**-** []()
+
+
+##read()
+####描述
+从bh1750中读取光线传感器数据(Lux勒克斯).
+
+####语法
+read()
+
+####参数
+nil.
+
+####返回值
+nil.
+
+####示例
+```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
+```
+
+####参见
+**-** []()
+
+
+##getlux()
+####描述
+从BH1750中提取数据.
+
+####语法
+getlux()
+
+####参数
+nil.
+
+####返回值
+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
+```
+
+####参见
+**-** []()
diff --git a/lua_modules/bh1750/bh1750_EN.md b/lua_modules/bh1750/bh1750_EN.md
new file mode 100644
index 00000000..5e2a5ece
--- /dev/null
+++ b/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
+```
+
+##init()
+####Description
+Setting the I2C pin of bh1750.
+
+####Syntax
+init(sda, scl)
+
+####Parameters
+sda: 1~12, IO index.
+scl: 1~12, IO index.
+
+####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
+**-** []()
+
+
+##read()
+####Description
+Read Lux data from bh1750.
+
+####Syntax
+read()
+
+####Parameters
+nil.
+
+####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)
+bh1750.read()
+
+-- release module
+bh1750 = nil
+package.loaded["bh1750"]=nil
+```
+
+####See also
+**-** []()
+
+
+##getlux()
+####Description
+Get lux from bh1750.
+
+####Syntax
+getlux()
+
+####Parameters
+nil.
+
+####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
+**-** []()
diff --git a/lua_modules/bh1750/bh1750_Example1.lua b/lua_modules/bh1750/bh1750_Example1.lua
new file mode 100644
index 00000000..911aa8fc
--- /dev/null
+++ b/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)
diff --git a/lua_modules/bh1750/bh1750_Example2.lua b/lua_modules/bh1750/bh1750_Example2.lua
new file mode 100644
index 00000000..48acceac
--- /dev/null
+++ b/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)
+
+
+
diff --git a/lua_modules/bmp085/bmp085.EN.md b/lua_modules/bmp085/bmp085.EN.md
new file mode 100644
index 00000000..4811429e
--- /dev/null
+++ b/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
+```
+
+##init()
+####Description
+Setting the i2c pin of bmp085.
+
+####Syntax
+init(sda, scl)
+
+####Parameters
+sda: 1~12, IO index.
+scl: 1~12, IO index.
+
+####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
+**-** []()
+
+
+##getUP()
+####Description
+Get calibrated data of pressure from bmp085.
+
+####Syntax
+getUP(oss)
+
+####Parameters
+oss: Over sampling setting, which is 0,1,2,3. Default value is 0.
+
+####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
+**-** []()
+
+
+##getUP_raw()
+####Description
+Get raw data of pressure from bmp085.
+
+####Syntax
+getUP_raw(oss)
+
+####Parameters
+oss: Over sampling setting, which is 0,1,2,3. Default value is 0.
+
+####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
+**-** []()
+
+
+##getUT()
+####Description
+Get temperature from bmp085.
+
+####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.
+
+####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.
+
+####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
+**-** []()
+
+
+##getAL()
+####Description
+Get estimated data of altitude from bmp085.
+
+####Syntax
+getAL(oss)
+
+####Parameters
+oss: over sampling setting, which is 0,1,2,3. Default value is 0.
+
+####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
+
+####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
+**-** []()
diff --git a/lua_modules/bmp085.lua b/lua_modules/bmp085/bmp085.lua
similarity index 100%
rename from lua_modules/bmp085.lua
rename to lua_modules/bmp085/bmp085.lua
diff --git a/lua_modules/dht22/README.md b/lua_modules/dht22/README.md
new file mode 100644
index 00000000..99ea9ff2
--- /dev/null
+++ b/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
+
diff --git a/lua_modules/dht22/dht22.lua b/lua_modules/dht22/dht22.lua
new file mode 100644
index 00000000..d2374050
--- /dev/null
+++ b/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
diff --git a/lua_modules/ds18b20/ds18b20.CN.md b/lua_modules/ds18b20/ds18b20.ZH.md
similarity index 100%
rename from lua_modules/ds18b20/ds18b20.CN.md
rename to lua_modules/ds18b20/ds18b20.ZH.md
diff --git a/lua_modules/ds18b20/ds18b20.lua b/lua_modules/ds18b20/ds18b20.lua
index 3857c941..bc1b1c99 100644
--- a/lua_modules/ds18b20/ds18b20.lua
+++ b/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
\ No newline at end of file
+return M
diff --git a/lua_modules/ds3231/ds3231-example.lua b/lua_modules/ds3231/ds3231-example.lua
new file mode 100644
index 00000000..5f3fb90c
--- /dev/null
+++ b/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
diff --git a/lua_modules/ds3231/ds3231-web.lua b/lua_modules/ds3231/ds3231-web.lua
new file mode 100644
index 00000000..5a28e51f
--- /dev/null
+++ b/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" ..
+ "" ..
+ "" ..
+ "ESP8266" ..
+ "Time and Date: " .. prettyTime .. "
" ..
+ "Node ChipID : " .. node.chipid() .. "
" ..
+ "Node MAC : " .. wifi.sta.getmac() .. "
" ..
+ "Node Heap : " .. node.heap() .. "
" ..
+ "Timer Ticks : " .. tmr.now() .. "
" ..
+ "")
+ conn:on("sent",function(conn) conn:close() end)
+ end
+)
\ No newline at end of file
diff --git a/lua_modules/ds3231/ds3231.EN.md b/lua_modules/ds3231/ds3231.EN.md
new file mode 100644
index 00000000..32b62527
--- /dev/null
+++ b/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
+```
+
+##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
+**-** []()
+
+
+
+## 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
+**-** []()
+
+
+
+## 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
+**-** []()
\ No newline at end of file
diff --git a/lua_modules/ds3231/ds3231.lua b/lua_modules/ds3231/ds3231.lua
new file mode 100644
index 00000000..48b0fd86
--- /dev/null
+++ b/lua_modules/ds3231/ds3231.lua
@@ -0,0 +1,75 @@
+--------------------------------------------------------------------------------
+-- DS3231 I2C module for NODEMCU
+-- NODEMCU TEAM
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Tobie Booth
+--------------------------------------------------------------------------------
+
+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
diff --git a/lua_modules/http/http-example.lua b/lua_modules/http/http-example.lua
new file mode 100644
index 00000000..5d3788e8
--- /dev/null
+++ b/lua_modules/http/http-example.lua
@@ -0,0 +1,39 @@
+------------------------------------------------------------------------------
+-- HTTP server Hello world example
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov
+------------------------------------------------------------------------------
+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)
diff --git a/lua_modules/http/http.lua b/lua_modules/http/http.lua
new file mode 100644
index 00000000..9f1e3f25
--- /dev/null
+++ b/lua_modules/http/http.lua
@@ -0,0 +1,212 @@
+------------------------------------------------------------------------------
+-- HTTP server module
+--
+-- LICENCE: http://opensource.org/licenses/MIT
+-- Vladimir Dronnikov
+------------------------------------------------------------------------------
+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
diff --git a/lua_modules/si7021/si7021-example.lua b/lua_modules/si7021/si7021-example.lua
new file mode 100644
index 00000000..5c6ed6cc
--- /dev/null
+++ b/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)
diff --git a/lua_modules/si7021/si7021-lewei.lua b/lua_modules/si7021/si7021-lewei.lua
new file mode 100644
index 00000000..28ac9189
--- /dev/null
+++ b/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)
diff --git a/lua_modules/si7021/si7021.EN.md b/lua_modules/si7021/si7021.EN.md
new file mode 100644
index 00000000..983bb978
--- /dev/null
+++ b/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
+```
+
+##init()
+####Description
+Setting the i2c pin of si7021.
+
+####Syntax
+init(sda, scl)
+
+####Parameters
+sda: 1~12, IO index.
+scl: 1~12, IO index.
+
+####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
+**-** []()
+
+
+##read()
+####Description
+Read temperature and humidity from si7021.
+
+####Syntax
+read()
+
+####Parameters
+nil.
+
+####Returns
+nil(Why?).
+
+####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
+**-** []()
+
+
+##getHumidity()
+####Description
+Get humidity from si7021.
+
+####Syntax
+getHumidity()
+
+####Parameters
+nil.
+
+####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
+**-** []()
+
+
+##getTemperature()
+####Description
+Get temperature from si7021.
+
+####Syntax
+getTemperature()
+
+####Parameters
+nil.
+
+####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
+**-** []()
diff --git a/lua_modules/si7021/si7021.lua b/lua_modules/si7021/si7021.lua
new file mode 100644
index 00000000..161e57d2
--- /dev/null
+++ b/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
diff --git a/pre_build/0.9.5/nodemcu_latest.bin b/pre_build/0.9.5/nodemcu_20150108.bin
similarity index 100%
rename from pre_build/0.9.5/nodemcu_latest.bin
rename to pre_build/0.9.5/nodemcu_20150108.bin
diff --git a/pre_build/0.9.5/nodemcu_20150118.bin b/pre_build/0.9.5/nodemcu_20150118.bin
new file mode 100644
index 00000000..3fd92e0b
Binary files /dev/null and b/pre_build/0.9.5/nodemcu_20150118.bin differ
diff --git a/pre_build/0.9.5/nodemcu_20150123.bin b/pre_build/0.9.5/nodemcu_20150123.bin
new file mode 100644
index 00000000..05966712
Binary files /dev/null and b/pre_build/0.9.5/nodemcu_20150123.bin differ
diff --git a/pre_build/0.9.5/nodemcu_20150126.bin b/pre_build/0.9.5/nodemcu_20150126.bin
new file mode 100644
index 00000000..4e3e63a7
Binary files /dev/null and b/pre_build/0.9.5/nodemcu_20150126.bin differ
diff --git a/pre_build/latest/nodemcu_latest.bin b/pre_build/latest/nodemcu_latest.bin
index f72815c2..17112015 100644
Binary files a/pre_build/latest/nodemcu_latest.bin and b/pre_build/latest/nodemcu_latest.bin differ
diff --git a/tools/.gitattributes b/tools/.gitattributes
new file mode 100644
index 00000000..b93363f7
--- /dev/null
+++ b/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