Merge pull request #470 from nodemcu/dev096

* Update SDK to 0.9.6
* Fix some bugs
* Update examples
* Add crypto module by @creationix
This commit is contained in:
Vowstar 2015-06-17 11:31:13 +08:00
commit dceed526c9
80 changed files with 5113 additions and 1049 deletions

View File

@ -103,9 +103,15 @@ OIMAGES := $(GEN_IMAGES:%=$(IMAGEODIR)/%)
BINODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/bin
OBINS := $(GEN_BINS:%=$(BINODIR)/%)
#
# Note:
# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
# If you add global optimize options like "-O2" here
# they will override "-Os" defined above.
# "-Os" should be used to reduce code size
#
CCFLAGS += \
-g \
-O2 \
-Wpointer-arith \
-Wundef \
-Werror \

View File

@ -36,6 +36,12 @@ Tencent QQ group: 309957875<br />
- cross compiler (done)
# Change log
2015-03-31<br />
polish mqtt module, add queue for mqtt module.<br />
add reconnect option to mqtt.connect api, :connect( host, port, secure, auto_reconnect, function(client) )<br />
move node.readvdd33 to adc.readvdd33.<br />
tools/esptool.py supported NodeMCU devkit automatic flash.
2015-03-18<br />
update u8glib.<br />
merge everything to master.
@ -225,8 +231,10 @@ m:on("message", function(conn, topic, data)
end
end)
-- for secure: m:connect("192.168.11.118", 1880, 1)
m:connect("192.168.11.118", 1880, 0, function(conn) print("connected") end)
-- m:connect( host, port, secure, auto_reconnect, function(client) )
-- for secure: m:connect("192.168.11.118", 1880, 1, 0)
-- for auto-reconnect: m:connect("192.168.11.118", 1880, 0, 1)
m:connect("192.168.11.118", 1880, 0, 0, function(conn) print("connected") end)
-- subscribe topic with qos = 0
m:subscribe("/topic",0, function(conn) print("subscribe success") end)
@ -235,7 +243,7 @@ m:subscribe("/topic",0, function(conn) print("subscribe success") end)
-- publish a message with data = hello, QoS = 0, retain = 0
m:publish("/topic","hello",0,0, function(conn) print("sent") end)
m:close();
m:close(); -- if auto-reconnect == 1, will disable auto-reconnect and then disconnect from host.
-- you can call m:connect again
```
@ -402,7 +410,8 @@ u8glib comes with a wide range of fonts for small displays. Since they need to b
They'll be available as `u8g.<font_name>` in Lua.
#####Bitmaps
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. See `lua_examples/u8glib/u8g_bitmaps.lua`. Binary files can be uploaded with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader).
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. See `lua_examples/u8glib/u8g_bitmaps.lua`.
In contrast to the source code based inclusion of XBMs into u8glib, it's required to provide precompiled binary files. This can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader).
#####Unimplemented functions
- [ ] Cursor handling
@ -417,6 +426,7 @@ Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This
- [ ] setPrintPos()
- [ ] setHardwareBackup()
- [ ] setRGB()
- [ ] setDefaultMidColor()
####Control a WS2812 based light strip

View File

@ -37,7 +37,8 @@ SUBDIRS= \
wofs \
modules \
spiffs \
cjson
cjson \
crypto \
endif # } PDIR
@ -86,6 +87,7 @@ COMPONENTS_eagle.app.v6 = \
wofs/wofs.a \
spiffs/spiffs.a \
cjson/libcjson.a \
crypto/libcrypto.a \
modules/libmodules.a
LINKFLAGS_eagle.app.v6 = \

View File

@ -46,7 +46,7 @@ int strbuf_init(strbuf_t *s, int len)
s->reallocs = 0;
s->debug = 0;
s->buf = c_malloc(size);
s->buf = (char *)c_malloc(size);
if (!s->buf){
NODE_ERR("not enough memory\n");
return -1;
@ -60,7 +60,7 @@ strbuf_t *strbuf_new(int len)
{
strbuf_t *s;
s = c_malloc(sizeof(strbuf_t));
s = (strbuf_t *)c_malloc(sizeof(strbuf_t));
if (!s){
NODE_ERR("not enough memory\n");
return NULL;

44
app/crypto/Makefile Normal file
View File

@ -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 = libcrypto.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

171
app/crypto/digests.c Normal file
View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2015, DiUS Computing Pty Ltd (jmattsson@dius.com.au)
* 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 contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 AUTHOR OR CONTRIBUTOR(S) 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 "digests.h"
#include "user_config.h"
#include "rom.h"
#include "lwip/mem.h"
#include <string.h>
#include <c_errno.h>
#ifdef MD2_ENABLE
#include "ssl/ssl_crypto.h"
#endif
#ifdef SHA2_ENABLE
#include "sha2.h"
#endif
typedef char ensure_int_and_size_t_same[(sizeof(int)==sizeof(size_t)) ? 0 : -1];
/* None of the functions match the prototype fully due to the void *, and in
some cases also the int vs size_t len, so wrap declarations in a macro. */
#define MECH(pfx, u, ds, bs) \
{ #pfx, \
(create_ctx_fn)pfx ## u ## Init, \
(update_ctx_fn)pfx ## u ## Update, \
(finalize_ctx_fn)pfx ## u ## Final, \
sizeof(pfx ## _CTX), \
ds, \
bs }
static const digest_mech_info_t hash_mechs[] ICACHE_RODATA_ATTR =
{
#ifdef MD2_ENABLE
MECH(MD2, _ , MD2_SIZE, 16),
#endif
MECH(MD5, , MD5_DIGEST_LENGTH, 64)
,MECH(SHA1, , SHA1_DIGEST_LENGTH, 64)
#ifdef SHA2_ENABLE
,MECH(SHA256, _ , SHA256_DIGEST_LENGTH, SHA256_BLOCK_LENGTH)
,MECH(SHA384, _ , SHA384_DIGEST_LENGTH, SHA384_BLOCK_LENGTH)
,MECH(SHA512, _ , SHA512_DIGEST_LENGTH, SHA512_BLOCK_LENGTH)
#endif
};
#undef MECH
const digest_mech_info_t *ICACHE_FLASH_ATTR crypto_digest_mech (const char *mech)
{
if (!mech)
return 0;
size_t i;
for (i = 0; i < (sizeof (hash_mechs) / sizeof (digest_mech_info_t)); ++i)
{
const digest_mech_info_t *mi = hash_mechs + i;
if (strcasecmp (mech, mi->name) == 0)
return mi;
}
return 0;
}
const char crypto_hexbytes[] = "0123456789abcdef";
// note: supports in-place encoding
void ICACHE_FLASH_ATTR crypto_encode_asciihex (const char *bin, size_t binlen, char *outbuf)
{
size_t aidx = binlen * 2 -1;
int i;
for (i = binlen -1; i >= 0; --i)
{
outbuf[aidx--] = crypto_hexbytes[bin[i] & 0xf];
outbuf[aidx--] = crypto_hexbytes[bin[i] >> 4];
}
}
int ICACHE_FLASH_ATTR crypto_hash (const digest_mech_info_t *mi,
const char *data, size_t data_len,
uint8_t *digest)
{
if (!mi)
return EINVAL;
void *ctx = os_malloc (mi->ctx_size);
if (!ctx)
return ENOMEM;
mi->create (ctx);
mi->update (ctx, data, data_len);
mi->finalize (digest, ctx);
os_free (ctx);
return 0;
}
int ICACHE_FLASH_ATTR crypto_hmac (const digest_mech_info_t *mi,
const char *data, size_t data_len,
const char *key, size_t key_len,
uint8_t *digest)
{
if (!mi)
return EINVAL;
void *ctx = os_malloc (mi->ctx_size);
if (!ctx)
return ENOMEM;
// If key too long, it needs to be hashed before use
if (key_len > mi->block_size)
{
mi->create (ctx);
mi->update (ctx, key, key_len);
mi->finalize (digest, ctx);
key = digest;
key_len = mi->block_size;
}
const size_t bs = mi->block_size;
uint8_t k_ipad[bs];
uint8_t k_opad[bs];
os_memset (k_ipad, 0x36, bs);
os_memset (k_opad, 0x5c, bs);
size_t i;
for (i = 0; i < key_len; ++i)
{
k_ipad[i] ^= key[i];
k_opad[i] ^= key[i];
}
mi->create (ctx);
mi->update (ctx, k_ipad, bs);
mi->update (ctx, data, data_len);
mi->finalize (digest, ctx);
mi->create (ctx);
mi->update (ctx, k_opad, bs);
mi->update (ctx, digest, mi->digest_size);
mi->finalize (digest, ctx);
os_free (ctx);
return 0;
}

85
app/crypto/digests.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef _CRYPTO_DIGESTS_H_
#define _CRYPTO_DIGESTS_H_
#include <c_types.h>
typedef void (*create_ctx_fn)(void *ctx);
typedef void (*update_ctx_fn)(void *ctx, const uint8_t *msg, int len);
typedef void (*finalize_ctx_fn)(uint8_t *digest, void *ctx);
/**
* Description of a message digest mechanism.
*
* Typical usage (if not using the crypto_xxxx() functions below):
* digest_mech_info_t *mi = crypto_digest_mech (chosen_algorithm);
* void *ctx = os_malloc (mi->ctx_size);
* mi->create (ctx);
* mi->update (ctx, data, len);
* ...
* uint8_t *digest = os_malloc (mi->digest_size);
* mi->finalize (digest, ctx);
* ...
* os_free (ctx);
* os_free (digest);
*/
typedef struct
{
/* Note: All entries are 32bit to enable placement using ICACHE_RODATA_ATTR.*/
const char * name;
create_ctx_fn create;
update_ctx_fn update;
finalize_ctx_fn finalize;
uint32_t ctx_size;
uint32_t digest_size;
uint32_t block_size;
} digest_mech_info_t;
/**
* Looks up the mech data for a specified digest algorithm.
* @param mech The name of the algorithm, e.g. "MD5", "SHA256"
* @returns The mech data, or null if the mech is unknown.
*/
const digest_mech_info_t *crypto_digest_mech (const char *mech);
/**
* Wrapper function for performing a one-in-all hashing operation.
* @param mi A mech from @c crypto_digest_mech(). A null pointer @c mi
* is harmless, but will of course result in an error return.
* @param data The data to create a digest for.
* @param data_len Number of bytes at @c data to digest.
* @param digest Output buffer, must be at least @c mi->digest_size in size.
* @return 0 on success, non-zero on error.
*/
int crypto_hash (const digest_mech_info_t *mi, const char *data, size_t data_len, uint8_t *digest);
/**
* Generate a HMAC signature.
* @param mi A mech from @c crypto_digest_mech(). A null pointer @c mi
* is harmless, but will of course result in an error return.
* @param data The data to generate a signature for.
* @param data_len Number of bytes at @c data to process.
* @param key The key to use.
* @param key_len Number of bytes the @c key comprises.
* @param digest Output buffer, must be at least @c mi->digest_size in size.
* @return 0 on success, non-zero on error.
*/
int crypto_hmac (const digest_mech_info_t *mi, const char *data, size_t data_len, const char *key, size_t key_len, uint8_t *digest);
/**
* Perform ASCII Hex encoding. Does not null-terminate the buffer.
*
* @param bin The buffer to ascii-hex encode.
* @param bin_len Number of bytes in @c bin to encode.
* @param outbuf Output buffer, must be at least @c bin_len*2 bytes in size.
* Note that in-place encoding is supported, and as such
* bin==outbuf is safe, provided the buffer is large enough.
*/
void crypto_encode_asciihex (const char *bin, size_t bin_len, char *outbuf);
/** Text string "0123456789abcdef" */
const char crypto_hexbytes[17];
#endif

913
app/crypto/sha2.c Normal file
View File

@ -0,0 +1,913 @@
/*
* FILE: sha2.c
* AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* Copyright (c) 2015, DiUS Computing Pty Ltd (jmattsson@dius.com.au)
* 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 contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 AUTHOR OR CONTRIBUTOR(S) 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 "user_config.h"
#ifdef SHA2_ENABLE
#include "sha2.h"
#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
#define assert(x) do {} while (0)
/*
* ASSERT NOTE:
* Some sanity checking code is included using assert(). On my FreeBSD
* system, this additional code can be removed by compiling with NDEBUG
* defined. Check your own systems manpage on assert() to see how to
* compile WITHOUT the sanity checking code on your system.
*
* UNROLLED TRANSFORM LOOP NOTE:
* You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
* loop version for the hash transform rounds (defined using macros
* later in this file). Either define on the command line, for example:
*
* cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
*
* or define below:
*
* #define SHA2_UNROLL_TRANSFORM
*
*/
typedef uint8_t sha2_byte; /* Exactly 1 byte */
typedef uint32_t sha2_word32; /* Exactly 4 bytes */
typedef uint64_t sha2_word64; /* Exactly 8 bytes */
/*** SHA-256/384/512 Various Length Definitions ***********************/
#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16)
#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
/*** ENDIAN REVERSAL MACROS *******************************************/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define REVERSE32(w,x) { \
sha2_word32 tmp = (w); \
tmp = (tmp >> 16) | (tmp << 16); \
(x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
}
#define REVERSE64(w,x) { \
sha2_word64 tmp = (w); \
tmp = (tmp >> 32) | (tmp << 32); \
tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
((tmp & 0x00ff00ff00ff00ffULL) << 8); \
(x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
((tmp & 0x0000ffff0000ffffULL) << 16); \
}
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
/*
* Macro for incrementally adding the unsigned 64-bit integer n to the
* unsigned 128-bit integer (represented using a two-element array of
* 64-bit words):
*/
#define ADDINC128(w,n) { \
(w)[0] += (sha2_word64)(n); \
if ((w)[0] < (n)) { \
(w)[1]++; \
} \
}
/*
* Macros for copying blocks of memory and for zeroing out ranges
* of memory. Using these macros makes it easy to switch from
* using memset()/memcpy() and using bzero()/bcopy().
*
* Please define either SHA2_USE_MEMSET_MEMCPY or define
* SHA2_USE_BZERO_BCOPY depending on which function set you
* choose to use:
*/
#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY)
/* Default to memset()/memcpy() if no option is specified */
#define SHA2_USE_MEMSET_MEMCPY 1
#endif
#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY)
/* Abort with an error if BOTH options are defined */
#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both!
#endif
#ifdef SHA2_USE_MEMSET_MEMCPY
#define MEMSET_BZERO(p,l) memset((p), 0, (l))
#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l))
#endif
#ifdef SHA2_USE_BZERO_BCOPY
#define MEMSET_BZERO(p,l) bzero((p), (l))
#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l))
#endif
/*** THE SIX LOGICAL FUNCTIONS ****************************************/
/*
* Bit shifting and rotation (used by the six SHA-XYZ logical functions:
*
* NOTE: The naming of R and S appears backwards here (R is a SHIFT and
* S is a ROTATION) because the SHA-256/384/512 description document
* (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
* same "backwards" definition.
*/
/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
#define R(b,x) ((x) >> (b))
/* 32-bit Rotate-right (used in SHA-256): */
#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
/* Four of six logical functions used in SHA-256: */
#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
/* Four of six logical functions used in SHA-384 and SHA-512: */
#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
/*** INTERNAL FUNCTION PROTOTYPES *************************************/
/* NOTE: These should not be accessed directly from outside this
* library -- they are intended for private internal visibility/use
* only.
*/
void SHA512_Last(SHA512_CTX*);
void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
void SHA512_Transform(SHA512_CTX*, const sha2_word64*);
/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
/* Hash constant words K for SHA-256: */
const static sha2_word32 K256[64] ICACHE_RODATA_ATTR = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};
/* Initial hash value H for SHA-256: */
const static sha2_word32 sha256_initial_hash_value[8] ICACHE_RODATA_ATTR = {
0x6a09e667UL,
0xbb67ae85UL,
0x3c6ef372UL,
0xa54ff53aUL,
0x510e527fUL,
0x9b05688cUL,
0x1f83d9abUL,
0x5be0cd19UL
};
/* Hash constant words K for SHA-384 and SHA-512: */
const static sha2_word64 K512[80] ICACHE_RODATA_ATTR = {
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
};
/* Initial hash value H for SHA-384 */
const static sha2_word64 sha384_initial_hash_value[8] ICACHE_RODATA_ATTR = {
0xcbbb9d5dc1059ed8ULL,
0x629a292a367cd507ULL,
0x9159015a3070dd17ULL,
0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL,
0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL,
0x47b5481dbefa4fa4ULL
};
/* Initial hash value H for SHA-512 */
const static sha2_word64 sha512_initial_hash_value[8] ICACHE_RODATA_ATTR = {
0x6a09e667f3bcc908ULL,
0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL,
0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL,
0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL,
0x5be0cd19137e2179ULL
};
/*** SHA-256: *********************************************************/
void ICACHE_FLASH_ATTR SHA256_Init(SHA256_CTX* context) {
if (context == (SHA256_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH);
context->bitcount = 0;
}
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-256 round macros: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
REVERSE32(*data++, W256[j]); \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
K256[j] + W256[j]; \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
K256[j] + (W256[j] = *data++); \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND256(a,b,c,d,e,f,g,h) \
s0 = W256[(j+1)&0x0f]; \
s0 = sigma0_256(s0); \
s1 = W256[(j+14)&0x0f]; \
s1 = sigma1_256(s1); \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
void ICACHE_FLASH_ATTR SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
sha2_word32 T1, *W256;
int j;
W256 = (sha2_word32*)context->buffer;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
/* Rounds 0 to 15 (unrolled): */
ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds to 64: */
do {
ROUND256(a,b,c,d,e,f,g,h);
ROUND256(h,a,b,c,d,e,f,g);
ROUND256(g,h,a,b,c,d,e,f);
ROUND256(f,g,h,a,b,c,d,e);
ROUND256(e,f,g,h,a,b,c,d);
ROUND256(d,e,f,g,h,a,b,c);
ROUND256(c,d,e,f,g,h,a,b);
ROUND256(b,c,d,e,f,g,h,a);
} while (j < 64);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
sha2_word32 T1, T2, *W256;
int j;
W256 = (sha2_word32*)context->buffer;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Copy data while converting to host byte order */
REVERSE32(*data++,W256[j]);
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
/* Apply the SHA-256 compression function to update a..h with copy */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W256[(j+1)&0x0f];
s0 = sigma0_256(s0);
s1 = W256[(j+14)&0x0f];
s1 = sigma1_256(s1);
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 64);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
unsigned int freespace, usedspace;
if (len == 0) {
/* Calling with no data is valid - we do nothing */
return;
}
/* Sanity check: */
assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0);
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA256_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
context->bitcount += freespace << 3;
len -= freespace;
data += freespace;
SHA256_Transform(context, (sha2_word32*)context->buffer);
} else {
/* The buffer is not yet full */
MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
context->bitcount += len << 3;
/* Clean up: */
usedspace = freespace = 0;
return;
}
}
while (len >= SHA256_BLOCK_LENGTH) {
/* Process as many complete blocks as we can */
SHA256_Transform(context, (sha2_word32*)data);
context->bitcount += SHA256_BLOCK_LENGTH << 3;
len -= SHA256_BLOCK_LENGTH;
data += SHA256_BLOCK_LENGTH;
}
if (len > 0) {
/* There's left-overs, so save 'em */
MEMCPY_BCOPY(context->buffer, data, len);
context->bitcount += len << 3;
}
/* Clean up: */
usedspace = freespace = 0;
}
void ICACHE_FLASH_ATTR SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
sha2_word32 *d = (sha2_word32*)digest;
unsigned int usedspace;
/* Sanity check: */
assert(context != (SHA256_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Convert FROM host byte order */
REVERSE64(context->bitcount,context->bitcount);
#endif
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace);
} else {
if (usedspace < SHA256_BLOCK_LENGTH) {
MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA256_Transform(context, (sha2_word32*)context->buffer);
/* And set-up for the last transform: */
MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
}
} else {
/* Set-up for the last transform: */
MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Set the bit count: */
*(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount;
/* Final transform: */
SHA256_Transform(context, (sha2_word32*)context->buffer);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 8; j++) {
REVERSE32(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH);
#endif
}
/* Clean up state data: */
MEMSET_BZERO(context, sizeof(SHA256_CTX));
usedspace = 0;
}
/*** SHA-512: *********************************************************/
void ICACHE_FLASH_ATTR SHA512_Init(SHA512_CTX* context) {
if (context == (SHA512_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-512 round macros: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_
#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
REVERSE64(*data++, W512[j]); \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
K512[j] + W512[j]; \
(d) += T1, \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
j++
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
K512[j] + (W512[j] = *data++); \
(d) += T1; \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
j++
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
#define ROUND512(a,b,c,d,e,f,g,h) \
s0 = W512[(j+1)&0x0f]; \
s0 = sigma0_512(s0); \
s1 = W512[(j+14)&0x0f]; \
s1 = sigma1_512(s1); \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
j++
void ICACHE_FLASH_ATTR SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
sha2_word64 T1, *W512 = (sha2_word64*)context->buffer;
int j;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds up to 79: */
do {
ROUND512(a,b,c,d,e,f,g,h);
ROUND512(h,a,b,c,d,e,f,g);
ROUND512(g,h,a,b,c,d,e,f);
ROUND512(f,g,h,a,b,c,d,e);
ROUND512(e,f,g,h,a,b,c,d);
ROUND512(d,e,f,g,h,a,b,c);
ROUND512(c,d,e,f,g,h,a,b);
ROUND512(b,c,d,e,f,g,h,a);
} while (j < 80);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer;
int j;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Convert TO host byte order */
REVERSE64(*data++, W512[j]);
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
#else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
/* Apply the SHA-512 compression function to update a..h with copy */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN_ */
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W512[(j+1)&0x0f];
s0 = sigma0_512(s0);
s1 = W512[(j+14)&0x0f];
s1 = sigma1_512(s1);
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 80);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
void ICACHE_FLASH_ATTR SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
unsigned int freespace, usedspace;
if (len == 0) {
/* Calling with no data is valid - we do nothing */
return;
}
/* Sanity check: */
assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA512_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
ADDINC128(context->bitcount, freespace << 3);
len -= freespace;
data += freespace;
SHA512_Transform(context, (sha2_word64*)context->buffer);
} else {
/* The buffer is not yet full */
MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
ADDINC128(context->bitcount, len << 3);
/* Clean up: */
usedspace = freespace = 0;
return;
}
}
while (len >= SHA512_BLOCK_LENGTH) {
/* Process as many complete blocks as we can */
SHA512_Transform(context, (sha2_word64*)data);
ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
len -= SHA512_BLOCK_LENGTH;
data += SHA512_BLOCK_LENGTH;
}
if (len > 0) {
/* There's left-overs, so save 'em */
MEMCPY_BCOPY(context->buffer, data, len);
ADDINC128(context->bitcount, len << 3);
}
/* Clean up: */
usedspace = freespace = 0;
}
void ICACHE_FLASH_ATTR SHA512_Last(SHA512_CTX* context) {
unsigned int usedspace;
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Convert FROM host byte order */
REVERSE64(context->bitcount[0],context->bitcount[0]);
REVERSE64(context->bitcount[1],context->bitcount[1]);
#endif
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
} else {
if (usedspace < SHA512_BLOCK_LENGTH) {
MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA512_Transform(context, (sha2_word64*)context->buffer);
/* And set-up for the last transform: */
MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2);
}
} else {
/* Prepare for final transform: */
MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Store the length of input data (in bits): */
*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
/* Final transform: */
SHA512_Transform(context, (sha2_word64*)context->buffer);
}
void ICACHE_FLASH_ATTR SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
assert(context != (SHA512_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
SHA512_Last(context);
/* Save the hash data for output: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 8; j++) {
REVERSE64(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);
#endif
}
/* Zero out state data */
MEMSET_BZERO(context, sizeof(SHA512_CTX));
}
/*** SHA-384: *********************************************************/
void ICACHE_FLASH_ATTR SHA384_Init(SHA384_CTX* context) {
if (context == (SHA384_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
void ICACHE_FLASH_ATTR SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
SHA512_Update((SHA512_CTX*)context, data, len);
}
void ICACHE_FLASH_ATTR SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
assert(context != (SHA384_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
SHA512_Last((SHA512_CTX*)context);
/* Save the hash data for output: */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 6; j++) {
REVERSE64(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH);
#endif
}
/* Zero out state data */
MEMSET_BZERO(context, sizeof(SHA384_CTX));
}
#endif // SHA2_ENABLE

47
app/crypto/sha2.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef __SHA2_H__
#define __SHA2_H__
#include <c_types.h>
/**************************************************************************
* SHA256/384/512 declarations
**************************************************************************/
#define SHA256_BLOCK_LENGTH 64
#define SHA256_DIGEST_LENGTH 32
typedef struct
{
uint32_t state[8];
uint64_t bitcount;
uint8_t buffer[SHA256_BLOCK_LENGTH];
} SHA256_CTX;
void SHA256_Init(SHA256_CTX *);
void SHA256_Update(SHA256_CTX *, const uint8_t *msg, size_t len);
void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
#define SHA384_BLOCK_LENGTH 128
#define SHA384_DIGEST_LENGTH 48
typedef struct
{
uint64_t state[8];
uint64_t bitcount[2];
uint8_t buffer[SHA384_BLOCK_LENGTH];
} SHA384_CTX;
void SHA384_Init(SHA384_CTX*);
void SHA384_Update(SHA384_CTX*, const uint8_t *msg, size_t len);
void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);
#define SHA512_BLOCK_LENGTH 128
#define SHA512_DIGEST_LENGTH 64
typedef SHA384_CTX SHA512_CTX;
void SHA512_Init(SHA512_CTX*);
void SHA512_Update(SHA512_CTX*, const uint8_t *msg, size_t len);
void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
#endif

View File

@ -365,7 +365,7 @@ pwm_init(uint16 freq, uint16 *duty)
for (i = 0; i < PWM_CHANNEL; i++) {
// pwm_gpio |= (1 << pwm_out_io_num[i]);
pwm_gpio = 0;
pwm.duty[0] = 0;
pwm.duty[i] = 0;
}
pwm_set_freq(500, 0);

39
app/include/rom.h Normal file
View File

@ -0,0 +1,39 @@
// Headers to the various functions in the rom (as we discover them)
// SHA1 is assumed to match the netbsd sha1.h headers
#define SHA1_DIGEST_LENGTH 20
#define SHA1_DIGEST_STRING_LENGTH 41
typedef struct {
uint32_t state[5];
uint32_t count[2];
uint8_t buffer[64];
} SHA1_CTX;
extern void SHA1Transform(uint32_t[5], const uint8_t[64]);
extern void SHA1Init(SHA1_CTX *);
extern void SHA1Final(uint8_t[SHA1_DIGEST_LENGTH], SHA1_CTX *);
extern void SHA1Update(SHA1_CTX *, const uint8_t *, unsigned int);
// MD5 is assumed to match the NetBSD md5.h header
#define MD5_DIGEST_LENGTH 16
typedef struct
{
uint32_t state[5];
uint32_t count[2];
uint8_t buffer[64];
} MD5_CTX;
extern void MD5Init(MD5_CTX *);
extern void MD5Update(MD5_CTX *, const unsigned char *, unsigned int);
extern void MD5Final(unsigned char[MD5_DIGEST_LENGTH], MD5_CTX *);
// base64_encode/decode derived by Cal
// Appears to match base64.h from netbsd wpa utils.
extern unsigned char * base64_encode(const unsigned char *src, size_t len, size_t *out_len);
extern unsigned char * base64_decode(const unsigned char *src, size_t len, size_t *out_len);
// Unfortunately it that seems to require the ROM memory management to be
// initialized because it uses mem_malloc
extern void mem_init(void * start_addr);

View File

@ -41,6 +41,8 @@
#define CLIENT_SSL_ENABLE
#define GPIO_INTERRUPT_ENABLE
//#define MD2_ENABLE
#define SHA2_ENABLE
// #define BUILD_WOFS 1
#define BUILD_SPIFFS 1

View File

@ -31,6 +31,9 @@
#define LUA_USE_MODULES_U8G
#define LUA_USE_MODULES_WS2812
#define LUA_USE_MODULES_CJSON
#define LUA_USE_MODULES_CRYPTO
#define LUA_USE_MODULES_RC
#endif /* LUA_USE_MODULES */
#endif /* __USER_MODULES_H__ */

View File

@ -3,10 +3,10 @@
#define NODE_VERSION_MAJOR 0U
#define NODE_VERSION_MINOR 9U
#define NODE_VERSION_REVISION 5U
#define NODE_VERSION_REVISION 6U
#define NODE_VERSION_INTERNAL 0U
#define NODE_VERSION "NodeMCU 0.9.5"
#define BUILD_DATE "build 20150318"
#define NODE_VERSION "NodeMCU 0.9.6"
#define BUILD_DATE "build 20150617"
#endif /* __USER_VERSION_H__ */

View File

@ -47,9 +47,9 @@ extern int c_stderr;
#define SEEK_END 2 /* set file offset to EOF plus offset */
#endif
#define c_malloc os_malloc
#define c_zalloc os_zalloc
#define c_free os_free
// #define c_malloc os_malloc
// #define c_zalloc os_zalloc
// #define c_free os_free
extern void output_redirect(const char *str);
#define c_puts output_redirect

View File

@ -29,9 +29,9 @@
#define os_realloc(p, s) mem_realloc((p), (s))
#endif
// #define c_free os_free
// #define c_malloc os_malloc
// #define c_zalloc os_zalloc
#define c_free os_free
#define c_malloc os_malloc
#define c_zalloc os_zalloc
#define c_realloc os_realloc
#define c_abs abs
@ -47,9 +47,9 @@
// c_getenv() get env "LUA_INIT" string for lua initialization.
const char *c_getenv(const char *__string);
void *c_malloc(size_t __size);
void *c_zalloc(size_t __size);
void c_free(void *);
// void *c_malloc(size_t __size);
// void *c_zalloc(size_t __size);
// void c_free(void *);
// int c_rand(void);
// void c_srand(unsigned int __seed);

View File

@ -336,7 +336,7 @@ const LUA_REG_TYPE math_map[] = {
{LSTRKEY("floor"), LFUNCVAL(math_floor)},
// {LSTRKEY("fmod"), LFUNCVAL(math_fmod)},
#if LUA_OPTIMIZE_MEMORY > 0 && defined(LUA_COMPAT_MOD)
{LSTRKEY("mod"), LFUNCVAL(math_fmod)},
// {LSTRKEY("mod"), LFUNCVAL(math_fmod)},
#endif
// {LSTRKEY("frexp"), LFUNCVAL(math_frexp)},
// {LSTRKEY("ldexp"), LFUNCVAL(math_ldexp)},

View File

@ -541,8 +541,12 @@ extern int readline4lua(const char *prompt, char *buffer, int length);
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
** Attention: This value should probably not be set higher than 1K.
** The size has direct impact on the C stack size needed be auxlib functions.
** For example: If set to 4K a call to string.gsub will need more than
** 5k C stack space.
*/
#define LUAL_BUFFERSIZE ((BUFSIZ)*4)
#define LUAL_BUFFERSIZE BUFSIZ
/* }================================================================== */

10
app/lwip/app/dummy.c Normal file
View File

@ -0,0 +1,10 @@
/******************************************************************************
* FunctionName : espconn_init
* Description : dummy the espconn_init
* Parameters : none
* Returns : none
*******************************************************************************/
void espconn_init()
{
// dummy function, do nothing.
}

View File

@ -8,6 +8,7 @@
#include "lrotable.h"
#include "c_types.h"
#include "user_interface.h"
// Lua: read(id) , return system adc
static int adc_sample( lua_State* L )
@ -19,12 +20,38 @@ static int adc_sample( lua_State* L )
return 1;
}
// Lua: readvdd33()
static int adc_readvdd33( lua_State* L )
{
uint32_t vdd33 = 0;
if(STATION_MODE == wifi_get_opmode())
{
// Bug fix
if (wifi_station_get_connect_status()!=0)
{
return luaL_error( L, "Can't read vdd33 while station is connected" );
}
else
{
vdd33 = readvdd33();
}
}
else
{
vdd33 = readvdd33();
}
lua_pushinteger(L, vdd33);
return 1;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE adc_map[] =
{
{ LSTRKEY( "read" ), LFUNCVAL( adc_sample ) },
{ LSTRKEY( "readvdd33" ), LFUNCVAL( adc_readvdd33) },
#if LUA_OPTIMIZE_MEMORY > 0
#endif

View File

@ -80,7 +80,7 @@ LUALIB_API int ( luaopen_file )( lua_State *L );
LUALIB_API int ( luaopen_ow )( lua_State *L );
#define AUXLIB_CJSON "cjson"
LUALIB_API int ( luaopen_ow )( lua_State *L );
LUALIB_API int ( luaopen_cjson )( lua_State *L );
// Helper macros
#define MOD_CHECK_ID( mod, id )\

183
app/modules/crypto.c Normal file
View File

@ -0,0 +1,183 @@
// Module for cryptography
//#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
#include "c_types.h"
#include "c_stdlib.h"
#include "../crypto/digests.h"
#include "user_interface.h"
#include "rom.h"
/**
* hash = crypto.sha1(input)
*
* Calculates raw SHA1 hash of input string.
* Input is arbitrary string, output is raw 20-byte hash as string.
*/
static int crypto_sha1( lua_State* L )
{
SHA1_CTX ctx;
uint8_t digest[20];
// Read the string from lua (with length)
int len;
const char* msg = luaL_checklstring(L, 1, &len);
// Use the SHA* functions in the rom
SHA1Init(&ctx);
SHA1Update(&ctx, msg, len);
SHA1Final(digest, &ctx);
// Push the result as a lua string
lua_pushlstring(L, digest, 20);
return 1;
}
static const char* bytes64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* encoded = crypto.toBase64(raw)
*
* Encodes raw binary string as base64 string.
*/
static int crypto_base64_encode( lua_State* L )
{
int len;
const char* msg = luaL_checklstring(L, 1, &len);
int blen = (len + 2) / 3 * 4;
char* out = (char*)c_malloc(blen);
int j = 0, i;
for (i = 0; i < len; i += 3) {
int a = msg[i];
int b = (i + 1 < len) ? msg[i + 1] : 0;
int c = (i + 2 < len) ? msg[i + 2] : 0;
out[j++] = bytes64[a >> 2];
out[j++] = bytes64[((a & 3) << 4) | (b >> 4)];
out[j++] = (i + 1 < len) ? bytes64[((b & 15) << 2) | (c >> 6)] : 61;
out[j++] = (i + 2 < len) ? bytes64[(c & 63)] : 61;
}
lua_pushlstring(L, out, j);
c_free(out);
return 1;
}
/**
* encoded = crypto.toHex(raw)
*
* Encodes raw binary string as hex string.
*/
static int crypto_hex_encode( lua_State* L)
{
int len;
const char* msg = luaL_checklstring(L, 1, &len);
char* out = (char*)c_malloc(len * 2);
int i, j = 0;
for (i = 0; i < len; i++) {
out[j++] = crypto_hexbytes[msg[i] >> 4];
out[j++] = crypto_hexbytes[msg[i] & 0xf];
}
lua_pushlstring(L, out, len*2);
c_free(out);
return 1;
}
/**
* masked = crypto.mask(message, mask)
*
* Apply a mask (repeated if shorter than message) as XOR to each byte.
*/
static int crypto_mask( lua_State* L )
{
int len, mask_len;
const char* msg = luaL_checklstring(L, 1, &len);
const char* mask = luaL_checklstring(L, 2, &mask_len);
int i;
char* copy = (char*)c_malloc(len);
for (i = 0; i < len; i++) {
copy[i] = msg[i] ^ mask[i % 4];
}
lua_pushlstring(L, copy, len);
c_free(copy);
return 1;
}
static inline int bad_mech (lua_State *L) { return luaL_error (L, "unknown hash mech"); }
static inline int bad_mem (lua_State *L) { return luaL_error (L, "insufficient memory"); }
/* rawdigest = crypto.hash("MD5", str)
* strdigest = crypto.toHex(rawdigest)
*/
static int crypto_lhash (lua_State *L)
{
const digest_mech_info_t *mi = crypto_digest_mech (luaL_checkstring (L, 1));
if (!mi)
return bad_mech (L);
size_t len = 0;
const char *data = luaL_checklstring (L, 2, &len);
uint8_t digest[mi->digest_size];
if (crypto_hash (mi, data, len, digest) != 0)
return bad_mem (L);
lua_pushlstring (L, digest, sizeof (digest));
return 1;
}
/* rawsignature = crypto.hmac("SHA1", str, key)
* strsignature = crypto.toHex(rawsignature)
*/
static int crypto_lhmac (lua_State *L)
{
const digest_mech_info_t *mi = crypto_digest_mech (luaL_checkstring (L, 1));
if (!mi)
return bad_mech (L);
size_t len = 0;
const char *data = luaL_checklstring (L, 2, &len);
size_t klen = 0;
const char *key = luaL_checklstring (L, 3, &klen);
uint8_t digest[mi->digest_size];
if (crypto_hmac (mi, data, len, key, klen, digest) != 0)
return bad_mem (L);
lua_pushlstring (L, digest, sizeof (digest));
return 1;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE crypto_map[] =
{
{ LSTRKEY( "sha1" ), LFUNCVAL( crypto_sha1 ) },
{ LSTRKEY( "toBase64" ), LFUNCVAL( crypto_base64_encode ) },
{ LSTRKEY( "toHex" ), LFUNCVAL( crypto_hex_encode ) },
{ LSTRKEY( "mask" ), LFUNCVAL( crypto_mask ) },
{ LSTRKEY( "hash" ), LFUNCVAL( crypto_lhash ) },
{ LSTRKEY( "hmac" ), LFUNCVAL( crypto_lhmac ) },
#if LUA_OPTIMIZE_MEMORY > 0
#endif
{ LNILKEY, LNILVAL }
};
LUALIB_API int luaopen_crypto( lua_State *L )
{
#if LUA_OPTIMIZE_MEMORY > 0
return 0;
#else // #if LUA_OPTIMIZE_MEMORY > 0
luaL_register( L, AUXLIB_CRYPTO, crypto_map );
// Add constants
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}

View File

@ -146,6 +146,82 @@ static int lgpio_write( lua_State* L )
return 0;
}
#define DELAY_TABLE_MAX_LEN 256
#define noInterrupts os_intr_lock
#define interrupts os_intr_unlock
#define delayMicroseconds os_delay_us
#define DIRECT_WRITE(pin, level) (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level))
// Lua: serout( pin, firstLevel, delay_table, [repeatNum] )
// -- serout( pin, firstLevel, delay_table, [repeatNum] )
// gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
// gpio.serout(1,1,{30,30,60,60,30,30}) -- serial one byte, b10110010
// gpio.serout(1,1,{30,70},8) -- serial 30% pwm 10k, lasts 8 cycles
// gpio.serout(1,1,{3,7},8) -- serial 30% pwm 100k, lasts 8 cycles
// gpio.serout(1,1,{0,0},8) -- serial 50% pwm as fast as possible, lasts 8 cycles
// gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
// gpio.serout(1,0,{20,10,10,20,10,10,10,100}) -- sim uart one byte 0x5A at about 100kbps
// gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
static int lgpio_serout( lua_State* L )
{
unsigned level;
unsigned pin;
unsigned table_len = 0;
unsigned repeat = 0;
int delay_table[DELAY_TABLE_MAX_LEN];
pin = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( gpio, pin );
level = luaL_checkinteger( L, 2 );
if ( level!=HIGH && level!=LOW )
return luaL_error( L, "wrong arg type" );
if( lua_istable( L, 3 ) )
{
table_len = lua_objlen( L, 3 );
if (table_len <= 0 || table_len>DELAY_TABLE_MAX_LEN)
return luaL_error( L, "wrong arg range" );
int i;
for( i = 0; i < table_len; i ++ )
{
lua_rawgeti( L, 3, i + 1 );
delay_table[i] = ( int )luaL_checkinteger( L, -1 );
lua_pop( L, 1 );
if( delay_table[i] < 0 || delay_table[i] > 1000000 ) // can not delay more than 1000000 us
return luaL_error( L, "delay must < 1000000 us" );
}
} else {
return luaL_error( L, "wrong arg range" );
}
if(lua_isnumber(L, 4))
repeat = lua_tointeger( L, 4 );
if( repeat < 0 || repeat > DELAY_TABLE_MAX_LEN )
return luaL_error( L, "delay must < 256" );
if(repeat==0)
repeat = 1;
int j;
bool skip_loop = true;
do
{
if(skip_loop){ // skip the first loop.
skip_loop = false;
continue;
}
for(j=0;j<table_len;j++){
noInterrupts();
// platform_gpio_write(pin, level);
DIRECT_WRITE(pin, level);
interrupts();
delayMicroseconds(delay_table[j]);
level=!level;
}
repeat--;
} while (repeat>0);
return 0;
}
#undef DELAY_TABLE_MAX_LEN
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
@ -154,6 +230,7 @@ const LUA_REG_TYPE gpio_map[] =
{ LSTRKEY( "mode" ), LFUNCVAL( lgpio_mode ) },
{ LSTRKEY( "read" ), LFUNCVAL( lgpio_read ) },
{ LSTRKEY( "write" ), LFUNCVAL( lgpio_write ) },
{ LSTRKEY( "serout" ), LFUNCVAL( lgpio_serout ) },
#ifdef GPIO_INTERRUPT_ENABLE
{ LSTRKEY( "trig" ), LFUNCVAL( lgpio_trig ) },
#endif

View File

@ -149,6 +149,22 @@
#define ROM_MODULES_CJSON
#endif
#if defined(LUA_USE_MODULES_CRYPTO)
#define MODULES_CRYPTO "crypto"
#define ROM_MODULES_CRYPTO \
_ROM(MODULES_CRYPTO, luaopen_crypto, crypto_map)
#else
#define ROM_MODULES_CRYPTO
#endif
#if defined(LUA_USE_MODULES_RC)
#define MODULES_RC "rc"
#define ROM_MODULES_RC \
_ROM(MODULES_RC, luaopen_rc, rc_map)
#else
#define ROM_MODULES_RC
#endif
#define LUA_MODULES_ROM \
ROM_MODULES_GPIO \
ROM_MODULES_PWM \
@ -167,7 +183,8 @@
ROM_MODULES_OW \
ROM_MODULES_BIT \
ROM_MODULES_WS2812 \
ROM_MODULES_CJSON
ROM_MODULES_CJSON \
ROM_MODULES_CRYPTO \
ROM_MODULES_RC
#endif

File diff suppressed because it is too large Load Diff

View File

@ -204,13 +204,12 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
NODE_DBG("self_ref null.\n");
return;
}
/* original
if(ipaddr == NULL)
{
NODE_ERR( "DNS Fail!\n" );
goto end;
}
// ipaddr->addr is a uint32_t ip
char ip_str[20];
c_memset(ip_str, 0, sizeof(ip_str));
@ -220,9 +219,30 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
}
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua
//lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua
lua_pushstring(gL, ip_str); // the ip para
lua_call(gL, 2, 0);
*/
// "enhanced"
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function
if(ipaddr == NULL)
{
NODE_DBG( "DNS Fail!\n" );
lua_pushnil(gL);
}else{
// ipaddr->addr is a uint32_t ip
char ip_str[20];
c_memset(ip_str, 0, sizeof(ip_str));
if(host_ip.addr == 0 && ipaddr->addr != 0)
{
c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr)));
}
lua_pushstring(gL, ip_str); // the ip para
}
// "enhanced" end
lua_call(gL, 1, 0);
end:
if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0)
@ -1119,6 +1139,71 @@ static int net_dns( lua_State* L, const char* mt )
return 0;
}
// Lua: net.dns.resolve( domain, function(ip) )
static int net_dns_static( lua_State* L )
{
const char *mt = "net.socket";
if (!lua_isstring( L, 1 ))
return luaL_error( L, "wrong parameter type (domain)" );
int rfunc = LUA_NOREF; //save reference to func
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION){
rfunc = luaL_ref(L, LUA_REGISTRYINDEX);
}
int rdom = luaL_ref(L, LUA_REGISTRYINDEX); //save reference to domain
lua_settop(L,0); //empty stack
lua_getfield(L, LUA_GLOBALSINDEX, "net");
lua_getfield(L, -1, "createConnection");
lua_remove(L, -2); //remove "net" from stack
lua_pushinteger(L, UDP); // we are going to create a new dummy UDP socket
lua_call(L,1,1);// after this the stack should have a socket
lua_rawgeti(gL, LUA_REGISTRYINDEX, rdom); // load domain back to the stack
lua_rawgeti(gL, LUA_REGISTRYINDEX, rfunc); // load the callback function back to the stack
luaL_unref(L, LUA_REGISTRYINDEX, rdom); //free reference
luaL_unref(L, LUA_REGISTRYINDEX, rfunc); //free reference
bool isserver = false;
struct espconn *pesp_conn = NULL;
lnet_userdata *nud;
size_t l;
nud = (lnet_userdata *)luaL_checkudata(L, 1, mt);
luaL_argcheck(L, nud, 1, "Server/Socket expected");
if(nud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
}
if(nud->pesp_conn == NULL){
NODE_DBG("nud->pesp_conn is NULL.\n");
return 0;
}
pesp_conn = nud->pesp_conn;
lua_pushvalue(L, 1); // copy to the top of stack
if(nud->self_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, nud->self_ref);
nud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
const char *domain = luaL_checklstring( L, 2, &l );
if (l>128 || domain == NULL)
return luaL_error( L, "need <128 domain" );
if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION){
lua_pushvalue(L, 3); // copy argument (func) to the top of stack
if(nud->cb_dns_found_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_dns_found_ref);
nud->cb_dns_found_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
host_ip.addr = 0;
espconn_gethostbyname(pesp_conn, domain, &host_ip, net_dns_found);
return 0;
}
// Lua: s = net.createServer(type, function(server))
static int net_createServer( lua_State* L )
{
@ -1332,6 +1417,48 @@ static int net_multicastLeave( lua_State* L )
}
// Lua: s = net.dns.setdnsserver(ip_addr, [index])
static int net_setdnsserver( lua_State* L )
{
size_t l;
u32_t ip32;
const char *server = luaL_checklstring( L, 1, &l );
if (l>16 || server == NULL || (ip32 = ipaddr_addr(server)) == IPADDR_NONE || ip32 == IPADDR_ANY)
return luaL_error( L, "invalid dns server ip" );
int numdns = luaL_optint(L, 2, 0);
if (numdns >= DNS_MAX_SERVERS)
return luaL_error( L, "server index out of range [0-%d]", DNS_MAX_SERVERS - 1);
ip_addr_t ipaddr;
ip4_addr_set_u32(&ipaddr, ip32);
dns_setserver(numdns,&ipaddr);
return 0;
}
// Lua: s = net.dns.getdnsserver([index])
static int net_getdnsserver( lua_State* L )
{
int numdns = luaL_optint(L, 1, 0);
if (numdns >= DNS_MAX_SERVERS)
return luaL_error( L, "server index out of range [0-%d]", DNS_MAX_SERVERS - 1);
ip_addr_t ipaddr;
dns_getserver(numdns,&ipaddr);
if ( ip_addr_isany(&ipaddr) ) {
lua_pushnil( L );
} else {
char temp[20] = {0};
c_sprintf(temp, IPSTR, IP2STR( &ipaddr ) );
lua_pushstring( L, temp );
}
return 1;
}
#if 0
static int net_array_index( lua_State* L )
{
@ -1402,6 +1529,15 @@ static const LUA_REG_TYPE net_array_map[] =
{ LNILKEY, LNILVAL }
};
#endif
static const LUA_REG_TYPE net_dns_map[] =
{
{ LSTRKEY( "setdnsserver" ), LFUNCVAL ( net_setdnsserver ) },
{ LSTRKEY( "getdnsserver" ), LFUNCVAL ( net_getdnsserver ) },
{ LSTRKEY( "resolve" ), LFUNCVAL ( net_dns_static ) },
{ LNILKEY, LNILVAL }
};
const LUA_REG_TYPE net_map[] =
{
{ LSTRKEY( "createServer" ), LFUNCVAL ( net_createServer ) },
@ -1409,6 +1545,7 @@ const LUA_REG_TYPE net_map[] =
{ LSTRKEY( "multicastJoin"), LFUNCVAL( net_multicastJoin ) },
{ LSTRKEY( "multicastLeave"), LFUNCVAL( net_multicastLeave ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "dns" ), LROVAL( net_dns_map ) },
{ LSTRKEY( "TCP" ), LNUMVAL( TCP ) },
{ LSTRKEY( "UDP" ), LNUMVAL( UDP ) },
@ -1471,6 +1608,12 @@ LUALIB_API int luaopen_net( lua_State *L )
// Setup the methods inside metatable
luaL_register( L, NULL, net_array_map );
#endif
lua_settop(L, n);
lua_newtable( L );
luaL_register( L, NULL, net_dns_map );
lua_setfield( L, -2, "dns" );
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}

View File

@ -100,13 +100,15 @@ static int node_chipid( lua_State* L )
lua_pushinteger(L, id);
return 1;
}
// deprecated, moved to adc module
// Lua: readvdd33()
static int node_readvdd33( lua_State* L )
{
uint32_t vdd33 = readvdd33();
lua_pushinteger(L, vdd33);
return 1;
}
// static int node_readvdd33( lua_State* L )
// {
// uint32_t vdd33 = readvdd33();
// lua_pushinteger(L, vdd33);
// return 1;
// }
// Lua: flashid()
static int node_flashid( lua_State* L )
@ -430,7 +432,8 @@ const LUA_REG_TYPE node_map[] =
#endif
{ LSTRKEY( "input" ), LFUNCVAL( node_input ) },
{ LSTRKEY( "output" ), LFUNCVAL( node_output ) },
{ LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) },
// Moved to adc module, use adc.readvdd33()
// { LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) },
{ LSTRKEY( "compile" ), LFUNCVAL( node_compile) },
{ LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) },
{ LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) },

96
app/modules/rc.c Normal file
View File

@ -0,0 +1,96 @@
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
//#include "driver/easygpio.h"
//static Ping_Data pingA;
#define defPulseLen 185
#define defProtocol 1
#define defRepeat 10
#define defBits 24
void transmit(int pin, int pulseLen, int nHighPulses, int nLowPulses) {
platform_gpio_write(pin, 1);
os_delay_us(pulseLen*nHighPulses);
platform_gpio_write(pin, 0);
os_delay_us(pulseLen*nLowPulses);
}
//rc.send(0,267715,24,185,1) --GPIO, code, bits, pulselen, protocol
static int ICACHE_FLASH_ATTR rc_send(lua_State* L) {
const uint8_t pin = luaL_checkinteger(L, 1);
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
//platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
//platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLDOWN);
platform_gpio_write(pin, 0);
long code = luaL_checklong(L, 2);
//const uint8_t bits = luaL_checkinteger(L, 3);
uint8_t bits = luaL_checkinteger(L, 3);
const uint8_t pulseLen = luaL_checkinteger(L, 4);
const uint8_t Protocol = luaL_checkinteger(L, 5);
const uint8_t repeat = luaL_checkinteger(L, 6);
NODE_ERR("pulseLen:%d\n",pulseLen);
NODE_ERR("Protocol:%d\n",Protocol);
NODE_ERR("repeat:%d\n",repeat);
NODE_ERR("send:");
int c,k,nRepeat;
bits = bits-1;
for (c = bits; c >= 0; c--)
{
k = code >> c;
if (k & 1)
NODE_ERR("1");
else
NODE_ERR("0");
}
NODE_ERR("\n");
for (nRepeat=0; nRepeat<repeat; nRepeat++) {
for (c = bits; c >= 0; c--)
{
k = code >> c;
if (k & 1){
//send1
if(Protocol==1){
transmit(pin,pulseLen,3,1);
}else if(Protocol==2){
transmit(pin,pulseLen,2,1);
}else if(Protocol==3){
transmit(pin,pulseLen,9,6);
}
}
else{
//send0
if(Protocol==1){
transmit(pin,pulseLen,1,3);
}else if(Protocol==2){
transmit(pin,pulseLen,1,2);
}else if(Protocol==3){
transmit(pin,pulseLen,4,11);
}
}
}
//sendSync();
if(Protocol==1){
transmit(pin,pulseLen,1,31);
}else if(Protocol==2){
transmit(pin,pulseLen,1,10);
}else if(Protocol==3){
transmit(pin,pulseLen,1,71);
}
}
return 1;
}
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE rc_map[] =
{
{ LSTRKEY( "send" ), LFUNCVAL( rc_send )},
{ LNILKEY, LNILVAL}
};
//LUALIB_API int luaopen_ultra(lua_State *L) {
LUALIB_API int luaopen_rc(lua_State *L) {
// TODO: Make sure that the GPIO system is initialized
LREGISTER(L, "rc", rc_map);
return 1;
}

View File

@ -11,11 +11,18 @@
static os_timer_t alarm_timer[NUM_TMR];
static int alarm_timer_cb_ref[NUM_TMR] = {LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF,LUA_NOREF};
static bool alarm_timer_repeat[NUM_TMR]= {0,0,0,0,0,0,0};
void alarm_timer_common(lua_State* L, unsigned id){
if(alarm_timer_cb_ref[id] == LUA_NOREF)
return;
lua_rawgeti(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]);
if(alarm_timer_repeat[id]==0)
{
if(alarm_timer_cb_ref[id] != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]);
}
lua_call(L, 0, 0);
}
@ -118,6 +125,7 @@ static int tmr_alarm( lua_State* L )
stack++;
if ( repeat != 1 && repeat != 0 )
return luaL_error( L, "wrong arg type" );
alarm_timer_repeat[id]=repeat;
}
// luaL_checkanyfunction(L, stack);
@ -141,6 +149,9 @@ static int tmr_stop( lua_State* L )
MOD_CHECK_ID( tmr, id );
os_timer_disarm(&(alarm_timer[id]));
if(alarm_timer_cb_ref[id] != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]);
return 0;
}

View File

@ -760,6 +760,39 @@ static int lu8g_getHeight( lua_State *L )
return 1;
}
// Lua: width = u8g.getStrWidth( self, string )
static int lu8g_getStrWidth( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
const char *s = luaL_checkstring( L, 2 );
if (s == NULL)
return 0;
lua_pushinteger( L, u8g_GetStrWidth( LU8G, s ) );
return 1;
}
// Lua: u8g.setFontLineSpacingFactor( self, factor )
static int lu8g_setFontLineSpacingFactor( lua_State *L )
{
lu8g_userdata_t *lud;
if ((lud = get_lud( L )) == NULL)
return 0;
u8g_uint_t factor = luaL_checkinteger( L, 2 );
u8g_SetFontLineSpacingFactor( LU8G, factor );
return 0;
}
// ------------------------------------------------------------
// comm functions
//
@ -916,7 +949,7 @@ uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, voi
case U8G_COM_MSG_WRITE_BYTE:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_stop( ESP_I2C_ID ), 0;
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 )
; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
@ -1140,53 +1173,55 @@ static int lu8g_pcd8544_84x48( lua_State *L )
static const LUA_REG_TYPE lu8g_display_map[] =
{
{ LSTRKEY( "begin" ), LFUNCVAL( lu8g_begin ) },
{ LSTRKEY( "setFont" ), LFUNCVAL( lu8g_setFont ) },
{ LSTRKEY( "setFontRefHeightAll" ), LFUNCVAL( lu8g_setFontRefHeightAll ) },
{ LSTRKEY( "setFontRefHeightExtendedText" ), LFUNCVAL( lu8g_setFontRefHeightExtendedText ) },
{ LSTRKEY( "setFontRefHeightText" ), LFUNCVAL( lu8g_setFontRefHeightText ) },
{ LSTRKEY( "setDefaultBackgroundColor" ), LFUNCVAL( lu8g_setDefaultBackgroundColor ) },
{ LSTRKEY( "setDefaultForegroundColor" ), LFUNCVAL( lu8g_setDefaultForegroundColor ) },
{ LSTRKEY( "setFontPosBaseline" ), LFUNCVAL( lu8g_setFontPosBaseline ) },
{ LSTRKEY( "setFontPosBottom" ), LFUNCVAL( lu8g_setFontPosBottom ) },
{ LSTRKEY( "setFontPosCenter" ), LFUNCVAL( lu8g_setFontPosCenter ) },
{ LSTRKEY( "setFontPosTop" ), LFUNCVAL( lu8g_setFontPosTop ) },
{ LSTRKEY( "getFontAscent" ), LFUNCVAL( lu8g_getFontAscent ) },
{ LSTRKEY( "getFontDescent" ), LFUNCVAL( lu8g_getFontDescent ) },
{ LSTRKEY( "getFontLineSpacing" ), LFUNCVAL( lu8g_getFontLineSpacing ) },
{ LSTRKEY( "getMode" ), LFUNCVAL( lu8g_getMode ) },
{ LSTRKEY( "setColorIndex" ), LFUNCVAL( lu8g_setColorIndex ) },
{ LSTRKEY( "getColorIndex" ), LFUNCVAL( lu8g_getColorIndex ) },
{ LSTRKEY( "drawBitmap" ), LFUNCVAL( lu8g_drawBitmap ) },
{ LSTRKEY( "drawBox" ), LFUNCVAL( lu8g_drawBox ) },
{ LSTRKEY( "drawCircle" ), LFUNCVAL( lu8g_drawCircle ) },
{ LSTRKEY( "drawDisc" ), LFUNCVAL( lu8g_drawDisc ) },
{ LSTRKEY( "drawEllipse" ), LFUNCVAL( lu8g_drawEllipse ) },
{ LSTRKEY( "drawFilledEllipse" ), LFUNCVAL( lu8g_drawFilledEllipse ) },
{ LSTRKEY( "drawFrame" ), LFUNCVAL( lu8g_drawFrame ) },
{ LSTRKEY( "drawHLine" ), LFUNCVAL( lu8g_drawHLine ) },
{ LSTRKEY( "drawLine" ), LFUNCVAL( lu8g_drawLine ) },
{ LSTRKEY( "drawPixel" ), LFUNCVAL( lu8g_drawPixel ) },
{ LSTRKEY( "drawRBox" ), LFUNCVAL( lu8g_drawRBox ) },
{ LSTRKEY( "drawRFrame" ), LFUNCVAL( lu8g_drawRFrame ) },
{ LSTRKEY( "drawStr" ), LFUNCVAL( lu8g_drawStr ) },
{ LSTRKEY( "drawStr90" ), LFUNCVAL( lu8g_drawStr90 ) },
{ LSTRKEY( "drawStr180" ), LFUNCVAL( lu8g_drawStr180 ) },
{ LSTRKEY( "drawStr270" ), LFUNCVAL( lu8g_drawStr270 ) },
{ LSTRKEY( "drawBox" ), LFUNCVAL( lu8g_drawBox ) },
{ LSTRKEY( "drawLine" ), LFUNCVAL( lu8g_drawLine ) },
{ LSTRKEY( "drawTriangle" ), LFUNCVAL( lu8g_drawTriangle ) },
{ LSTRKEY( "drawRBox" ), LFUNCVAL( lu8g_drawRBox ) },
{ LSTRKEY( "drawFrame" ), LFUNCVAL( lu8g_drawFrame ) },
{ LSTRKEY( "drawRFrame" ), LFUNCVAL( lu8g_drawRFrame ) },
{ LSTRKEY( "drawDisc" ), LFUNCVAL( lu8g_drawDisc ) },
{ LSTRKEY( "drawCircle" ), LFUNCVAL( lu8g_drawCircle ) },
{ LSTRKEY( "drawEllipse" ), LFUNCVAL( lu8g_drawEllipse ) },
{ LSTRKEY( "drawFilledEllipse" ), LFUNCVAL( lu8g_drawFilledEllipse ) },
{ LSTRKEY( "drawPixel" ), LFUNCVAL( lu8g_drawPixel ) },
{ LSTRKEY( "drawHLine" ), LFUNCVAL( lu8g_drawHLine ) },
{ LSTRKEY( "drawVLine" ), LFUNCVAL( lu8g_drawVLine ) },
{ LSTRKEY( "drawBitmap" ), LFUNCVAL( lu8g_drawBitmap ) },
{ LSTRKEY( "drawXBM" ), LFUNCVAL( lu8g_drawXBM ) },
{ LSTRKEY( "setScale2x2" ), LFUNCVAL( lu8g_setScale2x2 ) },
{ LSTRKEY( "undoScale" ), LFUNCVAL( lu8g_undoScale ) },
{ LSTRKEY( "firstPage" ), LFUNCVAL( lu8g_firstPage ) },
{ LSTRKEY( "getColorIndex" ), LFUNCVAL( lu8g_getColorIndex ) },
{ LSTRKEY( "getFontAscent" ), LFUNCVAL( lu8g_getFontAscent ) },
{ LSTRKEY( "getFontDescent" ), LFUNCVAL( lu8g_getFontDescent ) },
{ LSTRKEY( "getFontLineSpacing" ), LFUNCVAL( lu8g_getFontLineSpacing ) },
{ LSTRKEY( "getHeight" ), LFUNCVAL( lu8g_getHeight ) },
{ LSTRKEY( "getMode" ), LFUNCVAL( lu8g_getMode ) },
{ LSTRKEY( "getStrWidth" ), LFUNCVAL( lu8g_getStrWidth ) },
{ LSTRKEY( "getWidth" ), LFUNCVAL( lu8g_getWidth ) },
{ LSTRKEY( "nextPage" ), LFUNCVAL( lu8g_nextPage ) },
{ LSTRKEY( "sleepOn" ), LFUNCVAL( lu8g_sleepOn ) },
{ LSTRKEY( "sleepOff" ), LFUNCVAL( lu8g_sleepOff ) },
{ LSTRKEY( "setColorIndex" ), LFUNCVAL( lu8g_setColorIndex ) },
{ LSTRKEY( "setDefaultBackgroundColor" ), LFUNCVAL( lu8g_setDefaultBackgroundColor ) },
{ LSTRKEY( "setDefaultForegroundColor" ), LFUNCVAL( lu8g_setDefaultForegroundColor ) },
{ LSTRKEY( "setFont" ), LFUNCVAL( lu8g_setFont ) },
{ LSTRKEY( "setFontLineSpacingFactor" ), LFUNCVAL( lu8g_setFontLineSpacingFactor ) },
{ LSTRKEY( "setFontPosBaseline" ), LFUNCVAL( lu8g_setFontPosBaseline ) },
{ LSTRKEY( "setFontPosBottom" ), LFUNCVAL( lu8g_setFontPosBottom ) },
{ LSTRKEY( "setFontPosCenter" ), LFUNCVAL( lu8g_setFontPosCenter ) },
{ LSTRKEY( "setFontPosTop" ), LFUNCVAL( lu8g_setFontPosTop ) },
{ LSTRKEY( "setFontRefHeightAll" ), LFUNCVAL( lu8g_setFontRefHeightAll ) },
{ LSTRKEY( "setFontRefHeightExtendedText" ), LFUNCVAL( lu8g_setFontRefHeightExtendedText ) },
{ LSTRKEY( "setFontRefHeightText" ), LFUNCVAL( lu8g_setFontRefHeightText ) },
{ LSTRKEY( "setRot90" ), LFUNCVAL( lu8g_setRot90 ) },
{ LSTRKEY( "setRot180" ), LFUNCVAL( lu8g_setRot180 ) },
{ LSTRKEY( "setRot270" ), LFUNCVAL( lu8g_setRot270 ) },
{ LSTRKEY( "setScale2x2" ), LFUNCVAL( lu8g_setScale2x2 ) },
{ LSTRKEY( "sleepOff" ), LFUNCVAL( lu8g_sleepOff ) },
{ LSTRKEY( "sleepOn" ), LFUNCVAL( lu8g_sleepOn ) },
{ LSTRKEY( "undoRotation" ), LFUNCVAL( lu8g_undoRotation ) },
{ LSTRKEY( "getWidth" ), LFUNCVAL( lu8g_getWidth ) },
{ LSTRKEY( "getHeight" ), LFUNCVAL( lu8g_getHeight ) },
{ LSTRKEY( "undoScale" ), LFUNCVAL( lu8g_undoScale ) },
{ LSTRKEY( "__gc" ), LFUNCVAL( lu8g_close_display ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "__index" ), LROVAL ( lu8g_display_map ) },

View File

@ -8,6 +8,7 @@
#include "lrotable.h"
#include "c_string.h"
#include "c_stdlib.h"
#include "c_types.h"
#include "user_interface.h"
@ -15,6 +16,7 @@
#include "smartconfig.h"
static int wifi_smart_succeed = LUA_NOREF;
static uint8 getap_output_format=0;
static void wifi_smart_succeed_cb(void *arg){
NODE_DBG("wifi_smart_succeed_cb is called.\n");
@ -70,22 +72,35 @@ static void wifi_scan_done(void *arg, STATUS status)
{
c_memcpy(ssid, bss_link->ssid, 32);
}
c_sprintf(temp,"%d,%d,"MACSTR",%d", bss_link->authmode, bss_link->rssi,
MAC2STR(bss_link->bssid),bss_link->channel);
lua_pushstring(gL, temp);
lua_setfield( gL, -2, ssid );
// NODE_DBG(temp);
if(getap_output_format==1) //use new format(BSSID : SSID, RSSI, Authmode, Channel)
{
c_sprintf(temp,"%s,%d,%d,%d", ssid, bss_link->rssi, bss_link->authmode, bss_link->channel);
lua_pushstring(gL, temp);
NODE_DBG(MACSTR" : %s\n",MAC2STR(bss_link->bssid) , temp);
c_sprintf(temp,MACSTR, MAC2STR(bss_link->bssid));
lua_setfield( gL, -2, temp);
}
else//use old format(SSID : Authmode, RSSI, BSSID, Channel)
{
c_sprintf(temp,"%d,%d,"MACSTR",%d", bss_link->authmode, bss_link->rssi, MAC2STR(bss_link->bssid),bss_link->channel);
lua_pushstring(gL, temp);
lua_setfield( gL, -2, ssid );
NODE_DBG("%s : %s\n", ssid, temp);
}
bss_link = bss_link->next.stqe_next;
}
}
else
{
lua_pushnil(gL);
lua_newtable( gL );
}
lua_call(gL, 1, 0);
if(wifi_scan_succeed != LUA_NOREF)
{
luaL_unref(gL, LUA_REGISTRYINDEX, wifi_scan_succeed);
wifi_scan_succeed = LUA_NOREF;
}
}
// Lua: smart(channel, function succeed_cb)
@ -149,6 +164,7 @@ static int wifi_setmode( lua_State* L )
}
// Lua: realmode = getmode()
static int wifi_getmode( lua_State* L )
{
unsigned mode;
@ -156,7 +172,77 @@ static int wifi_getmode( lua_State* L )
lua_pushinteger( L, mode );
return 1;
}
/**
* wifi.getchannel()
* Description:
* Get current wifi Channel
*
* Syntax:
* wifi.getchannel()
* Parameters:
* nil
*
* Returns:
* Current wifi channel
*/
static int wifi_getchannel( lua_State* L )
{
unsigned channel;
channel = (unsigned)wifi_get_channel();
lua_pushinteger( L, channel );
return 1;
}
/**
* wifi.setphymode()
* Description:
* Set wifi physical mode802.11 b/g/n
* Note SoftAP only supports 802.11 b/g.
* Syntax:
* wifi.setphymode(mode)
* Parameters:
* mode:
* wifi.PHYMODE_B
* wifi.PHYMODE_G
* wifi.PHYMODE_N
* Returns:
* Current physical mode after setup
*/
static int wifi_setphymode( lua_State* L )
{
unsigned mode;
mode = luaL_checkinteger( L, 1 );
if ( mode != PHY_MODE_11B && mode != PHY_MODE_11G && mode != PHY_MODE_11N )
return luaL_error( L, "wrong arg type" );
wifi_set_phy_mode( (uint8_t)mode);
mode = (unsigned)wifi_get_phy_mode();
lua_pushinteger( L, mode );
return 1;
}
/**
* wifi.getphymode()
* Description:
* Get wifi physical mode802.11 b/g/n
* Syntax:
* wifi.getphymode()
* Parameters:
* nil
* Returns:
* Current physical mode.
*
*/
static int wifi_getphymode( lua_State* L )
{
unsigned mode;
mode = (unsigned)wifi_get_phy_mode();
lua_pushinteger( L, mode );
return 1;
}
// Lua: mac = wifi.xx.getmac()
static int wifi_getmac( lua_State* L, uint8_t mode )
@ -164,7 +250,7 @@ static int wifi_getmac( lua_State* L, uint8_t mode )
char temp[64];
uint8_t mac[6];
wifi_get_macaddr(mode, mac);
c_sprintf(temp, "%02X-%02X-%02X-%02X-%02X-%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
c_sprintf(temp, MACSTR, MAC2STR(mac));
lua_pushstring( L, temp );
return 1;
}
@ -172,11 +258,13 @@ static int wifi_getmac( lua_State* L, uint8_t mode )
// Lua: mac = wifi.xx.setmac()
static int wifi_setmac( lua_State* L, uint8_t mode )
{
uint8_t mac[6];
unsigned len = 0;
const char *mac = luaL_checklstring( L, 1, &len );
if(len!=6)
return luaL_error( L, "wrong arg type" );
const char *macaddr = luaL_checklstring( L, 1, &len );
if(len!=17)
return luaL_error( L, "wrong arg type" );
os_str2macaddr(mac, macaddr);
lua_pushboolean(L,wifi_set_macaddr(mode, (uint8 *)mac));
return 1;
}
@ -254,7 +342,7 @@ static int wifi_setip( lua_State* L, uint8_t mode )
pTempIp.netmask.addr = ip;
ip = parse_key(L, "gateway");
if(ip!=0)
if(mode==SOFTAP_IF || ip!=0)
pTempIp.gw.addr = ip;
if(STATION_IF == mode)
@ -317,36 +405,161 @@ static int wifi_station_getbroadcast( lua_State* L ){
return wifi_getbroadcast(L, STATION_IF);
}
// Lua: wifi.sta.config(ssid, password)
/**
* wifi.sta.getconfig()
* Description:
* Get current Station configuration.
* Note: if bssid_set==1 STATION is configured to connect to specified BSSID
* if bssid_set==0 specified BSSID address is irrelevant.
* Syntax:
* ssid, pwd, bssid_set, bssid=wifi.sta.getconfig()
* Parameters:
* none
* Returns:
* SSID, Password, BSSID_set, BSSID
*/
static int wifi_station_getconfig( lua_State* L )
{
struct station_config sta_conf;
char bssid[17];
wifi_station_get_config(&sta_conf);
if(sta_conf.ssid==0)
{
lua_pushnil(L);
return 1;
}
else
{
lua_pushstring( L, sta_conf.ssid );
lua_pushstring( L, sta_conf.password );
lua_pushinteger( L, sta_conf.bssid_set);
c_sprintf(bssid, MACSTR, MAC2STR(sta_conf.bssid));
lua_pushstring( L, bssid);
return 4;
}
}
/**
* wifi.sta.config()
* Description:
* Set current Station configuration.
* Note: If there are multiple APs with the same ssid, you can connect to a specific one by entering it's MAC address into the "bssid" field.
* Syntax:
* wifi.sta.getconfig(ssid, password) --Set STATION configuration, Auto-connect by default, Connects to any BSSID
* wifi.sta.getconfig(ssid, password, Auto_connect) --Set STATION configuration, Auto-connect(0 or 1), Connects to any BSSID
* wifi.sta.getconfig(ssid, password, bssid) --Set STATION configuration, Auto-connect by default, Connects to specific BSSID
* wifi.sta.getconfig(ssid, password, Auto_connect, bssid) --Set STATION configuration, Auto-connect(0 or 1), Connects to specific BSSID
* Parameters:
* ssid: string which is less than 32 bytes.
* Password: string which is less than 64 bytes.
* Auto_connect: 0 (disable Auto-connect) or 1 (to enable Auto-connect).
* bssid: MAC address of Access Point you would like to connect to.
* Returns:
* Nothing.
*
* Example:
--Connect to Access Point automatically when in range
wifi.sta.getconfig("myssid", "password")
--Connect to Access Point, User decides when to connect/disconnect to/from AP
wifi.sta.getconfig("myssid", "mypassword", 0)
wifi.sta.connect()
--do some wifi stuff
wifi.sta.disconnect()
--Connect to specific Access Point automatically when in range
wifi.sta.getconfig("myssid", "mypassword", "12:34:56:78:90:12")
--Connect to specific Access Point, User decides when to connect/disconnect to/from AP
wifi.sta.getconfig("myssid", "mypassword", 0)
wifi.sta.connect()
--do some wifi stuff
wifi.sta.disconnect()
*
*/
static int wifi_station_config( lua_State* L )
{
size_t sl, pl;
size_t sl, pl, ml;
struct station_config sta_conf;
int i;
int auto_connect=0;
const char *ssid = luaL_checklstring( L, 1, &sl );
if (sl>32 || ssid == NULL)
return luaL_error( L, "ssid:<32" );
const char *password = luaL_checklstring( L, 2, &pl );
if (pl>64 || password == NULL)
return luaL_error( L, "pwd:<64" );
if (pl!=0 && (pl<8 || pl>64) || password == NULL)
return luaL_error( L, "pwd:0,8~64" );
if(lua_isnumber(L, 3))
{
auto_connect=luaL_checkinteger( L, 3 );;
if ( auto_connect != 0 && auto_connect != 1)
return luaL_error( L, "wrong arg type" );
}
else if (lua_isstring(L, 3)&& !(lua_isnumber(L, 3)))
{
lua_pushnil(L);
lua_insert(L, 3);
auto_connect=1;
}
else
{
if(lua_isnil(L, 3))
return luaL_error( L, "wrong arg type" );
auto_connect=1;
}
if(lua_isnumber(L, 4))
{
sta_conf.bssid_set = 0;
c_memset(sta_conf.bssid, 0, 6);
}
else
{
if (lua_isstring(L, 4))
{
const char *macaddr = luaL_checklstring( L, 4, &ml );
if (ml!=17)
return luaL_error( L, "MAC:FF:FF:FF:FF:FF:FF" );
c_memset(sta_conf.bssid, 0, 6);
os_str2macaddr(sta_conf.bssid, macaddr);
sta_conf.bssid_set = 1;
}
else
{
sta_conf.bssid_set = 0;
c_memset(sta_conf.bssid, 0, 6);
}
}
c_memset(sta_conf.ssid, 0, 32);
c_memset(sta_conf.password, 0, 64);
c_memset(sta_conf.bssid, 0, 6);
c_memcpy(sta_conf.ssid, ssid, sl);
c_memcpy(sta_conf.password, password, pl);
sta_conf.bssid_set = 0;
NODE_DBG(sta_conf.ssid);
NODE_DBG(" %d\n", sl);
NODE_DBG(sta_conf.password);
NODE_DBG(" %d\n", pl);
NODE_DBG(" %d\n", sta_conf.bssid_set);
NODE_DBG( MACSTR, MAC2STR(sta_conf.bssid));
NODE_DBG("\n");
wifi_station_set_config(&sta_conf);
wifi_station_set_auto_connect(true);
wifi_station_disconnect();
wifi_station_connect();
// station_check_connect(0);
if(auto_connect==0)
{
wifi_station_set_auto_connect(false);
}
else
{
wifi_station_set_auto_connect(true);
wifi_station_connect();
}
// station_check_connect(0);
return 0;
}
@ -380,6 +593,42 @@ static int wifi_station_setauto( lua_State* L )
return 0;
}
/**
* wifi.sta.listap()
* Description:
* scan and get ap list as a lua table into callback function.
* Syntax:
* wifi.sta.getap(function(table))
* wifi.sta.getap(format, function(table))
* wifi.sta.getap(cfg, function(table))
* wifi.sta.getap(cfg, format, function(table))
* Parameters:
* cfg: table that contains scan configuration
* Format:Select output table format.
* 0 for the old format (SSID : Authmode, RSSI, BSSID, Channel) (Default)
* 1 for the new format (BSSID : SSID, RSSI, Authmode, Channel)
* function(table): a callback function to receive ap table when scan is done
this function receive a table, the key is the ssid,
value is other info in format: authmode,rssi,bssid,channel
* Returns:
* nil
*
* Example:
--original function left intact to preserve backward compatibility
wifi.sta.getap(function(T) for k,v in pairs(T) do print(k..":"..v) end end)
--if no scan configuration is desired cfg can be set to nil or previous example can be used
wifi.sta.getap(nil, function(T) for k,v in pairs(T) do print(k..":"..v) end end)
--scan configuration
scan_cfg={}
scan_cfg.ssid="myssid" --if set to nil, ssid is not filtered
scan_cfg.bssid="AA:AA:AA:AA:AA:AA" --if set to nil, MAC address is not filtered
scan_cfg.channel=0 --if set to nil, channel will default to 0(scans all channels), if set scan will be faster
scan_cfg.show_hidden=1 --if set to nil, show_hidden will default to 0
wifi.sta.getap(scan_cfg, function(T) for k,v in pairs(T) do print(k..":"..v) end end)
*/
static int wifi_station_listap( lua_State* L )
{
if(wifi_get_opmode() == SOFTAP_MODE)
@ -387,14 +636,146 @@ static int wifi_station_listap( lua_State* L )
return luaL_error( L, "Can't list ap in SOFTAP mode" );
}
gL = L;
// luaL_checkanyfunction(L, 1);
if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION){
lua_pushvalue(L, 1); // copy argument (func) to the top of stack
struct scan_config scan_cfg;
getap_output_format=0;
if (lua_type(L, 1)==LUA_TTABLE)
{
char ssid[32];
char bssid[6];
uint8 channel=0;
uint8 show_hidden=0;
size_t len;
lua_getfield(L, 1, "ssid");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the ssid string
{
const char *ssidstr = luaL_checklstring( L, -1, &len );
if(len>32)
return luaL_error( L, "ssid:<32" );
c_memset(ssid, 0, 32);
c_memcpy(ssid, ssidstr, len);
scan_cfg.ssid=ssid;
NODE_DBG(scan_cfg.ssid);
NODE_DBG("\n");
}
else
return luaL_error( L, "wrong arg type" );
}
else
scan_cfg.ssid=NULL;
lua_getfield(L, 1, "bssid");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the ssid string
{
const char *macaddr = luaL_checklstring( L, -1, &len );
if(len!=17)
return luaL_error( L, "bssid: FF:FF:FF:FF:FF:FF" );
c_memset(bssid, 0, 6);
os_str2macaddr(bssid, macaddr);
scan_cfg.bssid=bssid;
NODE_DBG(MACSTR, MAC2STR(scan_cfg.bssid));
NODE_DBG("\n");
}
else
return luaL_error( L, "wrong arg type" );
}
else
scan_cfg.bssid=NULL;
lua_getfield(L, 1, "channel");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isnumber(L, -1) ) // deal with the ssid string
{
channel = luaL_checknumber( L, -1);
if(!(channel>=0 && channel<=13))
return luaL_error( L, "channel: 0 or 1-13" );
scan_cfg.channel=channel;
NODE_DBG("%d\n", scan_cfg.channel);
}
else
return luaL_error( L, "wrong arg type" );
}
else
scan_cfg.channel=0;
lua_getfield(L, 1, "show_hidden");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isnumber(L, -1) ) // deal with the ssid string
{
show_hidden = luaL_checknumber( L, -1);
if(show_hidden!=0 && show_hidden!=1)
return luaL_error( L, "show_hidden: 0 or 1" );
scan_cfg.show_hidden=show_hidden;
NODE_DBG("%d\n", scan_cfg.show_hidden);
}
else
return luaL_error( L, "wrong arg type" );
}
else
scan_cfg.show_hidden=0;
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION)
{
lua_pushnil(L);
lua_insert(L, 2);
}
lua_pop(L, -4);
}
else if (lua_type(L, 1) == LUA_TNUMBER)
{
lua_pushnil(L);
lua_insert(L, 1);
}
else if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION)
{
lua_pushnil(L);
lua_insert(L, 1);
lua_pushnil(L);
lua_insert(L, 1);
}
else if(lua_isnil(L, 1))
{
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION)
{
lua_pushnil(L);
lua_insert(L, 2);
}
}
else
{
return luaL_error( L, "wrong arg type" );
}
if (lua_type(L, 2) == LUA_TNUMBER) //this section changes the output format
{
getap_output_format=luaL_checkinteger( L, 2 );
if ( getap_output_format != 0 && getap_output_format != 1)
return luaL_error( L, "wrong arg type" );
}
NODE_DBG("Use alternate output format: %d\n", getap_output_format);
if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION)
{
lua_pushvalue(L, 3); // copy argument (func) to the top of stack
if(wifi_scan_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed);
wifi_scan_succeed = luaL_ref(L, LUA_REGISTRYINDEX);
wifi_station_scan(NULL,wifi_scan_done);
} else {
if (lua_type(L, 1)==LUA_TTABLE)
{
wifi_station_scan(&scan_cfg,wifi_scan_done);
}
else
{
wifi_station_scan(NULL,wifi_scan_done);
}
}
else
{
if(wifi_scan_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed);
wifi_scan_succeed = LUA_NOREF;
@ -437,44 +818,46 @@ static int wifi_ap_getbroadcast( lua_State* L ){
// Lua: wifi.ap.config(table)
static int wifi_ap_config( lua_State* L )
{
struct softap_config config;
size_t len;
wifi_softap_get_config(&config);
if (!lua_istable(L, 1))
return luaL_error( L, "wrong arg type" );
struct softap_config config;
wifi_softap_get_config(&config);
size_t len;
lua_getfield(L, 1, "ssid");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the ssid string
{
const char *ssid = luaL_checklstring( L, -1, &len );
if(len>32)
return luaL_error( L, "ssid:<32" );
if(len<1 || len>32 || ssid == NULL)
return luaL_error( L, "ssid:1~32" );
c_memset(config.ssid, 0, 32);
c_memcpy(config.ssid, ssid, len);
config.ssid_len = len;
config.ssid_hidden = 0;
NODE_DBG(config.ssid);
NODE_DBG("\n");
config.ssid_len = len;
config.ssid_hidden = 0;
}
else
return luaL_error( L, "wrong arg type" );
}
else
return luaL_error( L, "wrong arg type" );
return luaL_error( L, "ssid required" );
lua_getfield(L, 1, "pwd");
if (!lua_isnil(L, -1)){ /* found? */
if( lua_isstring(L, -1) ) // deal with the password string
{
const char *pwd = luaL_checklstring( L, -1, &len );
if(len>64)
return luaL_error( L, "pwd:<64" );
if(len<8 || len>64 || pwd == NULL)
return luaL_error( L, "pwd:8~64" );
c_memset(config.password, 0, 64);
c_memcpy(config.password, pwd, len);
config.authmode = AUTH_WPA_WPA2_PSK;
NODE_DBG(config.password);
NODE_DBG("\n");
config.authmode = AUTH_WPA_WPA2_PSK;
}
else
return luaL_error( L, "wrong arg type" );
@ -483,11 +866,158 @@ static int wifi_ap_config( lua_State* L )
config.authmode = AUTH_OPEN;
}
config.max_connection = 4;
lua_getfield(L, 1, "auth");
if (!lua_isnil(L, -1))
{
config.authmode = (uint8_t)luaL_checkinteger(L, -1);
NODE_DBG("%d\n", config.authmode);
}
else
{
// keep whatever value resulted from "pwd" logic above
}
lua_getfield(L, 1, "channel");
if (!lua_isnil(L, -1))
{
unsigned channel = luaL_checkinteger(L, -1);
if (channel < 1 || channel > 13)
return luaL_error( L, "channel:1~13" );
config.channel = (uint8_t)channel;
NODE_DBG("%d\n", config.channel);
}
else
{
config.channel = 6;
}
lua_getfield(L, 1, "hidden");
if (!lua_isnil(L, -1))
{
config.ssid_hidden = (uint8_t)luaL_checkinteger(L, -1);
NODE_DBG("%d\n", config.ssid_hidden);
NODE_DBG("\n");
}
else
{
config.ssid_hidden = 0;
}
lua_getfield(L, 1, "max");
if (!lua_isnil(L, -1))
{
unsigned max = luaL_checkinteger(L, -1);
if (max < 1 || max > 4)
return luaL_error( L, "max:1~4" );
config.max_connection = (uint8_t)max;
NODE_DBG("%d\n", config.max_connection);
}
else
{
config.max_connection = 4;
}
lua_getfield(L, 1, "beacon");
if (!lua_isnil(L, -1))
{
unsigned beacon = luaL_checkinteger(L, -1);
if (beacon < 100 || beacon > 60000)
return luaL_error( L, "beacon:100~60000" );
config.beacon_interval = (uint16_t)beacon;
NODE_DBG("%d\n", config.beacon_interval);
}
else
{
config.beacon_interval = 100;
}
wifi_softap_set_config(&config);
// system_restart();
return 0;
return 0;
}
// Lua: table = wifi.ap.getclient()
static int wifi_ap_listclient( lua_State* L )
{
if (wifi_get_opmode() == STATION_MODE)
{
return luaL_error( L, "Can't list client in STATION_MODE mode" );
}
char temp[64];
lua_newtable(L);
struct station_info * station = wifi_softap_get_station_info();
struct station_info * next_station;
while (station != NULL)
{
c_sprintf(temp, IPSTR, IP2STR(&station->ip));
lua_pushstring(L, temp);
c_sprintf(temp, MACSTR, MAC2STR(station->bssid));
lua_setfield(L, -2, temp);
next_station = STAILQ_NEXT(station, next);
c_free(station);
station = next_station;
}
return 1;
}
// Lua: ip = wifi.ap.dhcp.config()
static int wifi_ap_dhcp_config( lua_State* L )
{
if (!lua_istable(L, 1))
return luaL_error( L, "wrong arg type" );
struct dhcps_lease lease;
uint32_t ip;
ip = parse_key(L, "start");
if (ip == 0)
return luaL_error( L, "wrong arg type" );
lease.start_ip = ip;
NODE_DBG(IPSTR, IP2STR(&lease.start_ip));
NODE_DBG("\n");
// use configured max_connection to determine end
struct softap_config config;
wifi_softap_get_config(&config);
lease.end_ip = lease.start_ip;
ip4_addr4(&lease.end_ip) += config.max_connection - 1;
char temp[64];
c_sprintf(temp, IPSTR, IP2STR(&lease.start_ip));
lua_pushstring(L, temp);
c_sprintf(temp, IPSTR, IP2STR(&lease.end_ip));
lua_pushstring(L, temp);
// note: DHCP max range = 101 from start_ip to end_ip
wifi_softap_dhcps_stop();
wifi_softap_set_dhcps_lease(&lease);
wifi_softap_dhcps_start();
return 2;
}
// Lua: wifi.ap.dhcp.start()
static int wifi_ap_dhcp_start( lua_State* L )
{
lua_pushboolean(L, wifi_softap_dhcps_start());
return 1;
}
// Lua: wifi.ap.dhcp.stop()
static int wifi_ap_dhcp_stop( lua_State* L )
{
lua_pushboolean(L, wifi_softap_dhcps_stop());
return 1;
}
// Module function map
@ -495,6 +1025,7 @@ static int wifi_ap_config( lua_State* L )
#include "lrodefs.h"
static const LUA_REG_TYPE wifi_station_map[] =
{
{ LSTRKEY( "getconfig" ), LFUNCVAL ( wifi_station_getconfig ) },
{ LSTRKEY( "config" ), LFUNCVAL ( wifi_station_config ) },
{ LSTRKEY( "connect" ), LFUNCVAL ( wifi_station_connect4lua ) },
{ LSTRKEY( "disconnect" ), LFUNCVAL ( wifi_station_disconnect4lua ) },
@ -509,6 +1040,14 @@ static const LUA_REG_TYPE wifi_station_map[] =
{ LNILKEY, LNILVAL }
};
static const LUA_REG_TYPE wifi_ap_dhcp_map[] =
{
{ LSTRKEY( "config" ), LFUNCVAL( wifi_ap_dhcp_config ) },
{ LSTRKEY( "start" ), LFUNCVAL( wifi_ap_dhcp_start ) },
{ LSTRKEY( "stop" ), LFUNCVAL( wifi_ap_dhcp_stop ) },
{ LNILKEY, LNILVAL }
};
static const LUA_REG_TYPE wifi_ap_map[] =
{
{ LSTRKEY( "config" ), LFUNCVAL( wifi_ap_config ) },
@ -517,6 +1056,12 @@ static const LUA_REG_TYPE wifi_ap_map[] =
{ LSTRKEY( "getbroadcast" ), LFUNCVAL ( wifi_ap_getbroadcast) },
{ LSTRKEY( "getmac" ), LFUNCVAL ( wifi_ap_getmac ) },
{ LSTRKEY( "setmac" ), LFUNCVAL ( wifi_ap_setmac ) },
{ LSTRKEY( "getclient" ), LFUNCVAL ( wifi_ap_listclient ) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "dhcp" ), LROVAL( wifi_ap_dhcp_map ) },
// { LSTRKEY( "__metatable" ), LROVAL( wifi_ap_map ) },
#endif
{ LNILKEY, LNILVAL }
};
@ -524,6 +1069,9 @@ const LUA_REG_TYPE wifi_map[] =
{
{ LSTRKEY( "setmode" ), LFUNCVAL( wifi_setmode ) },
{ LSTRKEY( "getmode" ), LFUNCVAL( wifi_getmode ) },
{ LSTRKEY( "getchannel" ), LFUNCVAL( wifi_getchannel ) },
{ LSTRKEY( "setphymode" ), LFUNCVAL( wifi_setphymode ) },
{ LSTRKEY( "getphymode" ), LFUNCVAL( wifi_getphymode ) },
{ LSTRKEY( "startsmart" ), LFUNCVAL( wifi_start_smart ) },
{ LSTRKEY( "stopsmart" ), LFUNCVAL( wifi_exit_smart ) },
{ LSTRKEY( "sleeptype" ), LFUNCVAL( wifi_sleeptype ) },
@ -536,10 +1084,20 @@ const LUA_REG_TYPE wifi_map[] =
{ LSTRKEY( "SOFTAP" ), LNUMVAL( SOFTAP_MODE ) },
{ LSTRKEY( "STATIONAP" ), LNUMVAL( STATIONAP_MODE ) },
{ LSTRKEY( "PHYMODE_B" ), LNUMVAL( PHY_MODE_B ) },
{ LSTRKEY( "PHYMODE_G" ), LNUMVAL( PHY_MODE_G ) },
{ LSTRKEY( "PHYMODE_N" ), LNUMVAL( PHY_MODE_N ) },
{ LSTRKEY( "NONE_SLEEP" ), LNUMVAL( NONE_SLEEP_T ) },
{ LSTRKEY( "LIGHT_SLEEP" ), LNUMVAL( LIGHT_SLEEP_T ) },
{ LSTRKEY( "MODEM_SLEEP" ), LNUMVAL( MODEM_SLEEP_T ) },
{ LSTRKEY( "OPEN" ), LNUMVAL( AUTH_OPEN ) },
// { LSTRKEY( "WEP" ), LNUMVAL( AUTH_WEP ) },
{ LSTRKEY( "WPA_PSK" ), LNUMVAL( AUTH_WPA_PSK ) },
{ LSTRKEY( "WPA2_PSK" ), LNUMVAL( AUTH_WPA2_PSK ) },
{ LSTRKEY( "WPA_WPA2_PSK" ), LNUMVAL( AUTH_WPA_WPA2_PSK ) },
// { LSTRKEY( "STA_IDLE" ), LNUMVAL( STATION_IDLE ) },
// { LSTRKEY( "STA_CONNECTING" ), LNUMVAL( STATION_CONNECTING ) },
// { LSTRKEY( "STA_WRONGPWD" ), LNUMVAL( STATION_WRONG_PASSWORD ) },
@ -573,6 +1131,12 @@ LUALIB_API int luaopen_wifi( lua_State *L )
MOD_REG_NUMBER( L, "LIGHT_SLEEP", LIGHT_SLEEP_T );
MOD_REG_NUMBER( L, "MODEM_SLEEP", MODEM_SLEEP_T );
MOD_REG_NUMBER( L, "OPEN", AUTH_OPEN );
// MOD_REG_NUMBER( L, "WEP", AUTH_WEP );
MOD_REG_NUMBER( L, "WPA_PSK", AUTH_WPA_PSK );
MOD_REG_NUMBER( L, "WPA2_PSK", AUTH_WPA2_PSK );
MOD_REG_NUMBER( L, "WPA_WPA2_PSK", AUTH_WPA_WPA2_PSK );
// MOD_REG_NUMBER( L, "STA_IDLE", STATION_IDLE );
// MOD_REG_NUMBER( L, "STA_CONNECTING", STATION_CONNECTING );
// MOD_REG_NUMBER( L, "STA_WRONGPWD", STATION_WRONG_PASSWORD );
@ -589,6 +1153,11 @@ LUALIB_API int luaopen_wifi( lua_State *L )
luaL_register( L, NULL, wifi_ap_map );
lua_setfield( L, -2, "ap" );
// Setup the new table (dhcp) inside ap
lua_newtable( L );
luaL_register( L, NULL, wifi_ap_dhcp_map );
lua_setfield( L, -1, "dhcp" );
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
}

View File

@ -3,6 +3,8 @@
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
#include "c_stdlib.h"
#include "c_string.h"
/**
* All this code is mostly from http://www.esp8266.com/viewtopic.php?f=21&t=1143&sid=a620a377672cfe9f666d672398415fcb
* from user Markus Gritsch.
@ -26,16 +28,25 @@ static void ICACHE_FLASH_ATTR send_ws_1(uint8_t gpio) {
i = 6; while (i--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << gpio);
}
// Lua: ws2812.write(pin, "string")
// Lua: ws2812.writergb(pin, "string")
// Byte triples in the string are interpreted as R G B values and sent to the hardware as G R B.
// ws2812.write(4, string.char(255, 0, 0)) uses GPIO2 and sets the first LED red.
// ws2812.write(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue.
// ws2812.write(4, string.char(0, 255, 0, 255, 255, 255)) first LED green, second LED white.
// WARNING: this function scrambles the input buffer :
// a = string.char(255,0,128)
// ws212.writergb(3,a)
// =a.byte()
// (0,255,128)
// ws2812.writergb(4, string.char(255, 0, 0)) uses GPIO2 and sets the first LED red.
// ws2812.writergb(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue.
// ws2812.writergb(4, string.char(0, 255, 0, 255, 255, 255)) first LED green, second LED white.
static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
{
const uint8_t pin = luaL_checkinteger(L, 1);
size_t length;
char *buffer = (char *)luaL_checklstring(L, 2, &length); // Cast away the constness.
const char *rgb = luaL_checklstring(L, 2, &length);
// dont modify lua-internal lstring - make a copy instead
char *buffer = (char *)c_malloc(length);
c_memcpy(buffer, rgb, length);
// Initialize the output pin:
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
@ -58,6 +69,37 @@ static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
os_delay_us(1);
// Send the buffer:
os_intr_lock();
for (i = 0; i < length; i++) {
uint8_t mask = 0x80;
while (mask) {
(buffer[i] & mask) ? send_ws_1(pin_num[pin]) : send_ws_0(pin_num[pin]);
mask >>= 1;
}
}
os_intr_unlock();
c_free(buffer);
return 0;
}
// Lua: ws2812.write(pin, "string")
// Byte triples in the string are interpreted as G R B values.
// This function does not corrupt your buffer.
//
// ws2812.write(4, string.char(0, 255, 0)) uses GPIO2 and sets the first LED red.
// ws2812.write(3, string.char(0, 0, 255):rep(10)) uses GPIO0 and sets ten LEDs blue.
// ws2812.write(4, string.char(255, 0, 0, 255, 255, 255)) first LED green, second LED white.
static int ICACHE_FLASH_ATTR ws2812_writegrb(lua_State* L) {
const uint8_t pin = luaL_checkinteger(L, 1);
size_t length;
const char *buffer = luaL_checklstring(L, 2, &length);
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
platform_gpio_write(pin, 0);
os_delay_us(10);
os_intr_lock();
const char * const end = buffer + length;
while (buffer != end) {
@ -78,6 +120,7 @@ static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
const LUA_REG_TYPE ws2812_map[] =
{
{ LSTRKEY( "writergb" ), LFUNCVAL( ws2812_writergb )},
{ LSTRKEY( "write" ), LFUNCVAL( ws2812_writegrb )},
{ LNILKEY, LNILVAL}
};

View File

@ -29,7 +29,7 @@
*
*/
#include <string.h>
#include "c_string.h"
#include "mqtt_msg.h"
#define MQTT_MAX_FIXED_HEADER_SIZE 3
@ -61,7 +61,7 @@ static int append_string(mqtt_connection_t* connection, const char* string, int
connection->buffer[connection->message.length++] = len >> 8;
connection->buffer[connection->message.length++] = len & 0xff;
memcpy(connection->buffer + connection->message.length, string, len);
c_memcpy(connection->buffer + connection->message.length, string, len);
connection->message.length += len;
return len + 2;
@ -121,7 +121,7 @@ static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length)
{
memset(connection, 0, sizeof(connection));
c_memset(connection, 0, sizeof(connection));
connection->buffer = buffer;
connection->buffer_length = buffer_length;
}
@ -294,7 +294,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf
variable_header->lengthMsb = 0;
variable_header->lengthLsb = 4;
memcpy(variable_header->magic, "MQTT", 4);
c_memcpy(variable_header->magic, "MQTT", 4);
variable_header->version = 4;
variable_header->flags = 0;
variable_header->keepaliveMsb = info->keepalive >> 8;
@ -305,7 +305,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf
if(info->client_id != NULL && info->client_id[0] != '\0')
{
if(append_string(connection, info->client_id, strlen(info->client_id)) < 0)
if(append_string(connection, info->client_id, c_strlen(info->client_id)) < 0)
return fail_message(connection);
}
else
@ -313,10 +313,10 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf
if(info->will_topic != NULL && info->will_topic[0] != '\0')
{
if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0)
if(append_string(connection, info->will_topic, c_strlen(info->will_topic)) < 0)
return fail_message(connection);
if(append_string(connection, info->will_message, strlen(info->will_message)) < 0)
if(append_string(connection, info->will_message, c_strlen(info->will_message)) < 0)
return fail_message(connection);
variable_header->flags |= MQTT_CONNECT_FLAG_WILL;
@ -327,7 +327,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf
if(info->username != NULL && info->username[0] != '\0')
{
if(append_string(connection, info->username, strlen(info->username)) < 0)
if(append_string(connection, info->username, c_strlen(info->username)) < 0)
return fail_message(connection);
variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;
@ -335,7 +335,7 @@ mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_inf
if(info->password != NULL && info->password[0] != '\0')
{
if(append_string(connection, info->password, strlen(info->password)) < 0)
if(append_string(connection, info->password, c_strlen(info->password)) < 0)
return fail_message(connection);
variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;
@ -351,7 +351,7 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi
if(topic == NULL || topic[0] == '\0')
return fail_message(connection);
if(append_string(connection, topic, strlen(topic)) < 0)
if(append_string(connection, topic, c_strlen(topic)) < 0)
return fail_message(connection);
if(qos > 0)
@ -364,7 +364,7 @@ mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topi
if(connection->message.length + data_length > connection->buffer_length)
return fail_message(connection);
memcpy(connection->buffer + connection->message.length, data, data_length);
c_memcpy(connection->buffer + connection->message.length, data, data_length);
connection->message.length += data_length;
return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
@ -412,7 +412,7 @@ mqtt_message_t* mqtt_msg_subscribe(mqtt_connection_t* connection, const char* to
if((*message_id = append_message_id(connection, 0)) == 0)
return fail_message(connection);
if(append_string(connection, topic, strlen(topic)) < 0)
if(append_string(connection, topic, c_strlen(topic)) < 0)
return fail_message(connection);
if(connection->message.length + 1 > connection->buffer_length)
@ -432,7 +432,7 @@ mqtt_message_t* mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char*
if((*message_id = append_message_id(connection, 0)) == 0)
return fail_message(connection);
if(append_string(connection, topic, strlen(topic)) < 0)
if(append_string(connection, topic, c_strlen(topic)) < 0)
return fail_message(connection);
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);

82
app/mqtt/msg_queue.c Normal file
View File

@ -0,0 +1,82 @@
#include "c_string.h"
#include "c_stdlib.h"
#include "c_stdio.h"
#include "msg_queue.h"
msg_queue_t *msg_enqueue(msg_queue_t **head, mqtt_message_t *msg, uint16_t msg_id, int msg_type, int publish_qos){
if(!head){
return NULL;
}
if (!msg || !msg->data || msg->length == 0){
NODE_DBG("empty message\n");
return NULL;
}
msg_queue_t *node = (msg_queue_t *)c_zalloc(sizeof(msg_queue_t));
if(!node){
NODE_DBG("not enough memory\n");
return NULL;
}
node->msg.data = (uint8_t *)c_zalloc(msg->length);
if(!node->msg.data){
NODE_DBG("not enough memory\n");
c_free(node);
return NULL;
}
c_memcpy(node->msg.data, msg->data, msg->length);
node->msg.length = msg->length;
node->next = NULL;
node->msg_id = msg_id;
node->msg_type = msg_type;
node->publish_qos = publish_qos;
msg_queue_t *tail = *head;
if(tail){
while(tail->next!=NULL) tail = tail->next;
tail->next = node;
} else {
*head = node;
}
return node;
}
void msg_destroy(msg_queue_t *node){
if(!node) return;
if(node->msg.data){
c_free(node->msg.data);
node->msg.data = NULL;
}
c_free(node);
}
msg_queue_t * msg_dequeue(msg_queue_t **head){
if(!head || !*head){
return NULL;
}
msg_queue_t *node = *head; // fetch head.
*head = node->next; // update head.
node->next = NULL;
return node;
}
msg_queue_t * msg_peek(msg_queue_t **head){
if(!head || !*head){
return NULL;
}
return *head; // fetch head.
}
int msg_size(msg_queue_t **head){
if(!head || !*head){
return 0;
}
int i = 1;
msg_queue_t *tail = *head;
if(tail){
while(tail->next!=NULL){
tail = tail->next;
i++;
}
}
return i;
}

28
app/mqtt/msg_queue.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef _MSG_QUEUE_H
#define _MSG_QUEUE_H 1
#include "mqtt_msg.h"
#ifdef __cplusplus
extern "C" {
#endif
struct msg_queue_t;
typedef struct msg_queue_t {
struct msg_queue_t *next;
mqtt_message_t msg;
uint16_t msg_id;
int msg_type;
int publish_qos;
} msg_queue_t;
msg_queue_t * msg_enqueue(msg_queue_t **head, mqtt_message_t *msg, uint16_t msg_id, int msg_type, int publish_qos);
void msg_destroy(msg_queue_t *node);
msg_queue_t * msg_dequeue(msg_queue_t **head);
msg_queue_t * msg_peek(msg_queue_t **head);
int msg_size(msg_queue_t **head);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -321,7 +321,7 @@ bool flash_init_data_written(void)
// FLASH SEC - 4
uint32_t data[2] ICACHE_STORE_ATTR;
#if defined(FLASH_SAFE_API)
if (SPI_FLASH_RESULT_OK == flash_safe_read((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data)))
if (SPI_FLASH_RESULT_OK == flash_safe_read((flash_safe_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data)))
#else
if (SPI_FLASH_RESULT_OK == spi_flash_read((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data)))
#endif // defined(FLASH_SAFE_API)
@ -369,8 +369,8 @@ bool flash_init_data_blank(void)
// It will init system config to blank!
bool result = false;
#if defined(FLASH_SAFE_API)
if ((SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_rom_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_rom_get_sec_num() - 1))))
if ((SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 1))))
#else
if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 2))) &&
(SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 1))))
@ -396,11 +396,25 @@ uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index)
NODE_DBG("aligned_array is not 4-byte aligned.\n");
return 0;
}
uint32_t v = ((uint32_t *)aligned_array)[ index / 4 ];
volatile uint32_t v = ((uint32_t *)aligned_array)[ index / 4 ];
uint8_t *p = (uint8_t *) (&v);
return p[ (index % 4) ];
}
uint16_t word_of_aligned_array(const uint16_t *aligned_array, uint32_t index)
{
if ( (((uint32_t)aligned_array) % 4) != 0 )
{
NODE_DBG("aligned_array is not 4-byte aligned.\n");
return 0;
}
volatile uint32_t v = ((uint32_t *)aligned_array)[ index / 2 ];
uint16_t *p = (uint16_t *) (&v);
return (index % 2 == 0) ? p[ 0 ] : p[ 1 ];
// return p[ (index % 2) ]; // -- why error???
// (byte_of_aligned_array((uint8_t *)aligned_array, index * 2 + 1) << 8) | byte_of_aligned_array((uint8_t *)aligned_array, index * 2);
}
// uint8_t flash_rom_get_checksum(void)
// {
// // SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR = flash_rom_getinfo();

View File

@ -107,6 +107,7 @@ bool flash_init_data_default(void);
bool flash_init_data_blank(void);
bool flash_self_destruct(void);
uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index);
uint16_t word_of_aligned_array(const uint16_t *aligned_array, uint32_t index);
// uint8_t flash_rom_get_checksum(void);
// uint8_t flash_rom_calc_checksum(void);

View File

@ -71,6 +71,9 @@
#define fs_rename myspiffs_rename
#define fs_size myspiffs_size
#define fs_mount myspiffs_mount
#define fs_unmount myspiffs_unmount
#define FS_NAME_MAX_LENGTH SPIFFS_OBJ_NAME_LEN
#endif

View File

@ -127,11 +127,19 @@ int smart_check(uint8_t *nibble, uint16_t len, uint8_t *dst, uint8_t *got){
return res;
}
void detect(uint8 *buf, uint16 len){
void detect(uint8 *arg, uint16 len){
uint16_t seq;
int16_t seq_delta = 0;
uint16_t byte_num = 0, bit_num = 0;
int16_t c = 0;
uint8 *buf = NULL;
if( len == 12 ){
return;
} else if (len >= 64){
buf = arg + sizeof(struct RxControl);
} else {
return;
}
if( ( (buf[0]) & TYPE_SUBTYPE_MASK) != TYPE_SUBTYPE_QOS_DATA){
return;
}

View File

@ -59,6 +59,40 @@ extern "C" {
#define STATION_CHECK_TIME (2*1000)
struct RxControl{
signed rssi:8;//表示该包的信号强度
unsigned rate:4;
unsigned is_group:1;
unsigned:1;
unsigned sig_mode:2;//表示该包是否是11n 的包0 表示非11n非0 表示11n
unsigned legacy_length:12;//如果不是11n 的包,它表示包的长度
unsigned damatch0:1;
unsigned damatch1:1;
unsigned bssidmatch0:1;
unsigned bssidmatch1:1;
unsigned MCS:7;//如果是11n 的包它表示包的调制编码序列有效值0-76
unsigned CWB:1;//如果是11n 的包它表示是否为HT40 的包
unsigned HT_length:16;//如果是11n 的包,它表示包的长度
unsigned Smoothing:1;
unsigned Not_Sounding:1;
unsigned:1;
unsigned Aggregation:1;
unsigned STBC:2;
unsigned FEC_CODING:1;//如果是11n 的包它表示是否为LDPC 的包
unsigned SGI:1;
unsigned rxend_state:8;
unsigned ampdu_cnt:8;
unsigned channel:4;//表示该包所在的信道
unsigned:12;
};
struct sniffer_buf{
struct RxControl rx_ctrl; // 12-bytes
u8 buf[48];//包含ieee80211 包头
u16 cnt;//包的个数
u16 len[1];//包的长度
};
struct _my_addr_map {
uint8 addr[ADDR_LENGTH*3];
uint8_t addr_len;

View File

@ -42,7 +42,7 @@ The small 4KB sectors allow for greater flexibility in applications th
********************/
void spiffs_mount() {
void myspiffs_mount() {
spiffs_config cfg;
cfg.phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL );
cfg.phys_addr += 0x3000;
@ -69,6 +69,10 @@ void spiffs_mount() {
NODE_DBG("mount res: %i\n", res);
}
void myspiffs_unmount() {
SPIFFS_unmount(&fs);
}
// FS formatting function
// Returns 1 if OK, 0 for error
int myspiffs_format( void )
@ -85,7 +89,7 @@ int myspiffs_format( void )
while( sect_first <= sect_last )
if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )
return 0;
spiffs_mount();
myspiffs_mount();
return 1;
}

View File

@ -477,6 +477,8 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
#if SPIFFS_CACHE
#endif
void myspiffs_mount();
void myspiffs_unmount();
int myspiffs_open(const char *name, int flags);
int myspiffs_close( int fd );
size_t myspiffs_write( int fd, const void* ptr, size_t len );

View File

@ -395,13 +395,11 @@ typedef struct __attribute(( packed )) {
// common page header
spiffs_page_header p_hdr;
// alignment
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
u8_t _align[4 - ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)==0 ? 4 : ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)];
// size of object
u32_t size;
// type of object
spiffs_obj_type type;
// alignment2
u8_t _align2[4 - (sizeof(spiffs_obj_type)&3)==0 ? 4 : (sizeof(spiffs_obj_type)&3)];
// name of object
u8_t name[SPIFFS_OBJ_NAME_LEN];
} spiffs_page_object_ix_header;

View File

@ -44,6 +44,7 @@ INCLUDES += -I ../libc
INCLUDES += -I ../platform
INCLUDES += -I ../lua
INCLUDES += -I ../wofs
INCLUDES += -I ../spiffs
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -14,8 +14,7 @@
#include "c_stdlib.h"
#include "c_stdio.h"
#include "romfs.h"
#include "flash_fs.h"
#include "user_interface.h"
#include "ets_sys.h"
@ -44,7 +43,6 @@ void task_init(void){
system_os_task(task_lua, USER_TASK_PRIO_0, taskQueue, TASK_QUEUE_LEN);
}
extern void spiffs_mount();
// extern void test_spiffs();
// extern int test_romfs();
@ -69,7 +67,16 @@ void nodemcu_init(void)
// Flash init data at FLASHSIZE - 0x04000 Byte.
flash_init_data_default();
// Flash blank data at FLASHSIZE - 0x02000 Byte.
flash_init_data_blank();
flash_init_data_blank();
if( !fs_format() )
{
NODE_ERR( "\ni*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
}
else{
NODE_ERR( "format done.\n" );
}
fs_unmount(); // mounted by format.
}
#endif // defined(FLASH_SAFE_API)
@ -94,7 +101,7 @@ void nodemcu_init(void)
// test_romfs();
#elif defined ( BUILD_SPIFFS )
spiffs_mount();
fs_mount();
// test_spiffs();
#endif
// endpoint_setup();

View File

@ -381,3 +381,141 @@ function TestDNSLeak()
tmr.alarm(1, 3000, 0, function() print("hack socket close, MEM: "..node.heap()) c:close() end) -- socket timeout hack
print("MEM: "..node.heap())
end
v="abc%0D%0Adef"
print(string.gsub(v, "%%(%x%x)", function(x) return string.char(tonumber(x, 16)) end))
function ex(x) string.find("abc%0Ddef","bc") return 's' end
string.gsub("abc%0Ddef", "%%(%x%x)", ex)
function ex(x) string.char(35) return 's' end
string.gsub("abc%0Ddef", "%%(%x%x)", ex) print("hello")
function ex(x) string.lower('Ab') return 's' end
string.gsub("abc%0Ddef", "%%(%x%x)", ex) print("hello")
v="abc%0D%0Adef"
pcall(function() print(string.gsub(v, "%%(%x%x)", function(x) return string.char(tonumber(x, 16)) end)) end)
mosca -v | bunyan
m=mqtt.Client()
m:connect("192.168.18.88",1883)
topic={}
topic["/topic1"]=0
topic["/topic2"]=0
m:subscribe(topic,function(m) print("sub done") end)
m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end )
m:publish("/topic1","hello",0,0)
m:publish("/topic3","hello",0,0) m:publish("/topic4","hello",0,0)
m=mqtt.Client()
m:connect("192.168.18.88",1883)
m:subscribe("/topic1",0,function(m) print("sub done") end)
m:subscribe("/topic2",0,function(m) print("sub done") end)
m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end )
m:publish("/topic1","hello",0,0)
m:publish("/topic3","hello",0,0) m:publish("/topic4","hello",0,0)
m:publish("/topic1","hello1",0,0) m:publish("/topic2","hello2",0,0)
m:publish("/topic1","hello",1,0)
m:subscribe("/topic3",0,function(m) print("sub done") end)
m:publish("/topic3","hello3",2,0)
m=mqtt.Client()
m:connect("192.168.18.88",1883, function(con) print("connected hello") end)
m=mqtt.Client()
m:on("connect",function(m) print("connection") end )
m:connect("192.168.18.88",1883)
m:on("offline",function(m) print("disconnection") end )
m=mqtt.Client()
m:on("connect",function(m) print("connection "..node.heap()) end )
m:on("offline", function(conn)
if conn == nil then print("conn is nil") end
print("Reconnect to broker...")
print(node.heap())
conn:connect("192.168.18.88",1883,0,1)
end)
m:connect("192.168.18.88",1883,0,1)
m=mqtt.Client()
m:on("connect",function(m) print("connection "..node.heap()) end )
m:on("offline", function(conn)
if conn == nil then print("conn is nil") end
print("Reconnect to broker...")
print(node.heap())
conn:connect("192.168.18.88",1883)
end)
m:connect("192.168.18.88",1883)
m:close()
m=mqtt.Client()
m:connect("192.168.18.88",1883)
m:on("message",function(m,t,pl) print(t..":") if pl~=nil then print(pl) end end )
m:subscribe("/topic1",0,function(m) print("sub done") end)
m:publish("/topic1","hello3",2,0) m:publish("/topic1","hello2",2,0)
m:publish("/topic1","hello3",0,0) m:publish("/topic1","hello2",2,0)
m:subscribe("/topic2",2,function(m) print("sub done") end)
m:publish("/topic2","hello3",0,0) m:publish("/topic2","hello2",2,0)
m=mqtt.Client()
m:on("connect",function(m)
print("connection "..node.heap())
m:subscribe("/topic1",0,function(m) print("sub done") end)
m:publish("/topic1","hello3",0,0) m:publish("/topic1","hello2",2,0)
end )
m:on("offline", function(conn)
print("disconnect to broker...")
print(node.heap())
end)
m:connect("192.168.18.88",1883,0,1)
-- serout( pin, firstLevel, delay_table, [repeatNum] )
gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
gpio.serout(1,1,{30,30,60,60,30,30}) -- serial one byte, b10110010
gpio.serout(1,1,{30,70},8) -- serial 30% pwm 10k, lasts 8 cycles
gpio.serout(1,1,{3,7},8) -- serial 30% pwm 100k, lasts 8 cycles
gpio.serout(1,1,{0,0},8) -- serial 50% pwm as fast as possible, lasts 8 cycles
gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
gpio.serout(1,0,{20,10,10,20,10,10,10,100}) -- sim uart one byte 0x5A at about 100kbps
gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
-- Lua: mqtt.Client(clientid, keepalive, user, pass)
-- test with cloudmqtt.com
m_dis={}
function dispatch(m,t,pl)
if pl~=nil and m_dis[t] then
m_dis[t](pl)
end
end
function topic1func(pl)
print("get1: "..pl)
end
function topic2func(pl)
print("get2: "..pl)
end
m_dis["/topic1"]=topic1func
m_dis["/topic2"]=topic2func
m=mqtt.Client("nodemcu1",60,"test","test123")
m:on("connect",function(m)
print("connection "..node.heap())
m:subscribe("/topic1",0,function(m) print("sub done") end)
m:subscribe("/topic2",0,function(m) print("sub done") end)
m:publish("/topic1","hello",0,0) m:publish("/topic2","world",0,0)
end )
m:on("offline", function(conn)
print("disconnect to broker...")
print(node.heap())
end)
m:on("message",dispatch )
m:connect("m11.cloudmqtt.com",11214,0,1)
-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) )
tmr.alarm(0,10000,1,function() local pl = "time: "..tmr.time()
m:publish("/topic1",pl,0,0)
end)

18
examples/init.lua Normal file
View File

@ -0,0 +1,18 @@
--init.lua, something like this
countdown = 3
tmr.alarm(0,1000,1,function()
print(countdown)
countdown = countdown-1
if countdown<1 then
tmr.stop(0)
countdown = nil
local s,err
if file.open("user.lc") then
file.close()
s,err = pcall(function() dofile("user.lc") end)
else
s,err = pcall(function() dofile("user.lua") end)
end
if not s then print(err) end
end
end)

1
examples/user.lua Normal file
View File

@ -0,0 +1 @@
print("hello NodeMCU")

View File

@ -1,392 +1,407 @@
#ifndef __ESPCONN_H__
#define __ESPCONN_H__
#include "lwip/ip_addr.h"
typedef sint8 err_t;
typedef void *espconn_handle;
typedef void (* espconn_connect_callback)(void *arg);
typedef void (* espconn_reconnect_callback)(void *arg, sint8 err);
/* Definitions for error constants. */
#define ESPCONN_OK 0 /* No error, everything OK. */
#define ESPCONN_MEM -1 /* Out of memory error. */
#define ESPCONN_TIMEOUT -3 /* Timeout. */
#define ESPCONN_RTE -4 /* Routing problem. */
#define ESPCONN_INPROGRESS -5 /* Operation in progress */
#define ESPCONN_ABRT -8 /* Connection aborted. */
#define ESPCONN_RST -9 /* Connection reset. */
#define ESPCONN_CLSD -10 /* Connection closed. */
#define ESPCONN_CONN -11 /* Not connected. */
#define ESPCONN_ARG -12 /* Illegal argument. */
#define ESPCONN_ISCONN -15 /* Already connected. */
/** Protocol family and type of the espconn */
enum espconn_type {
ESPCONN_INVALID = 0,
/* ESPCONN_TCP Group */
ESPCONN_TCP = 0x10,
/* ESPCONN_UDP Group */
ESPCONN_UDP = 0x20,
};
/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */
enum espconn_state {
ESPCONN_NONE,
ESPCONN_WAIT,
ESPCONN_LISTEN,
ESPCONN_CONNECT,
ESPCONN_WRITE,
ESPCONN_READ,
ESPCONN_CLOSE
};
typedef struct _esp_tcp {
int remote_port;
int local_port;
uint8 local_ip[4];
uint8 remote_ip[4];
espconn_connect_callback connect_callback;
espconn_reconnect_callback reconnect_callback;
espconn_connect_callback disconnect_callback;
} esp_tcp;
typedef struct _esp_udp {
int remote_port;
int local_port;
uint8 local_ip[4];
uint8 remote_ip[4];
} esp_udp;
typedef struct _remot_info{
enum espconn_state state;
int remote_port;
uint8 remote_ip[4];
}remot_info;
/** A callback prototype to inform about events for a espconn */
typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len);
typedef void (* espconn_sent_callback)(void *arg);
/** A espconn descriptor */
struct espconn {
/** type of the espconn (TCP, UDP) */
enum espconn_type type;
/** current state of the espconn */
enum espconn_state state;
union {
esp_tcp *tcp;
esp_udp *udp;
} proto;
/** A callback function that is informed about events for this espconn */
espconn_recv_callback recv_callback;
espconn_sent_callback sent_callback;
uint8 link_cnt;
void *reverse;
};
enum espconn_option{
ESPCONN_REUSEADDR = 1,
ESPCONN_NODELAY,
ESPCONN_END
};
/******************************************************************************
* FunctionName : espconn_connect
* Description : The function given as the connect
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 espconn_connect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_disconnect
* Description : disconnect with host
* Parameters : espconn -- the espconn used to disconnect the connection
* Returns : none
*******************************************************************************/
sint8 espconn_disconnect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_delete
* Description : disconnect with host
* Parameters : espconn -- the espconn used to disconnect the connection
* Returns : none
*******************************************************************************/
sint8 espconn_delete(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_accept
* Description : The function given as the listen
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 espconn_accept(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_create
* Description : sent data for client or server
* Parameters : espconn -- espconn to the data transmission
* Returns : result
*******************************************************************************/
sint8 espconn_create(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_tcp_get_max_con
* Description : get the number of simulatenously active TCP connections
* Parameters : none
* Returns : none
*******************************************************************************/
uint8 espconn_tcp_get_max_con(void);
/******************************************************************************
* FunctionName : espconn_tcp_set_max_con
* Description : set the number of simulatenously active TCP connections
* Parameters : num -- total number
* Returns : none
*******************************************************************************/
sint8 espconn_tcp_set_max_con(uint8 num);
/******************************************************************************
* FunctionName : espconn_tcp_get_max_con_allow
* Description : get the count of simulatenously active connections on the server
* Parameters : espconn -- espconn to get the count
* Returns : result
*******************************************************************************/
sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_tcp_set_max_con_allow
* Description : set the count of simulatenously active connections on the server
* Parameters : espconn -- espconn to set the count
* num -- support the connection number
* Returns : result
*******************************************************************************/
sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num);
/******************************************************************************
* FunctionName : espconn_regist_time
* Description : used to specify the time that should be called when don't recv data
* Parameters : espconn -- the espconn used to the connection
* interval -- the timer when don't recv data
* Returns : none
*******************************************************************************/
sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag);
/******************************************************************************
* FunctionName : espconn_get_connection_info
* Description : used to specify the function that should be called when disconnect
* Parameters : espconn -- espconn to set the err callback
* discon_cb -- err callback function to call when err
* Returns : none
*******************************************************************************/
sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags);
/******************************************************************************
* FunctionName : espconn_regist_sentcb
* Description : Used to specify the function that should be called when data
* has been successfully delivered to the remote host.
* Parameters : struct espconn *espconn -- espconn to set the sent callback
* espconn_sent_callback sent_cb -- sent callback function to
* call for this espconn when data is successfully sent
* Returns : none
*******************************************************************************/
sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb);
/******************************************************************************
* FunctionName : espconn_sent
* Description : sent data for client or server
* Parameters : espconn -- espconn to set for client or server
* psent -- data to send
* length -- length of data to send
* Returns : none
*******************************************************************************/
sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);
/******************************************************************************
* FunctionName : espconn_regist_connectcb
* Description : used to specify the function that should be called when
* connects to host.
* Parameters : espconn -- espconn to set the connect callback
* connect_cb -- connected callback function to call when connected
* Returns : none
*******************************************************************************/
sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb);
/******************************************************************************
* FunctionName : espconn_regist_recvcb
* Description : used to specify the function that should be called when recv
* data from host.
* Parameters : espconn -- espconn to set the recv callback
* recv_cb -- recv callback function to call when recv data
* Returns : none
*******************************************************************************/
sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb);
/******************************************************************************
* FunctionName : espconn_regist_reconcb
* Description : used to specify the function that should be called when connection
* because of err disconnect.
* Parameters : espconn -- espconn to set the err callback
* recon_cb -- err callback function to call when err
* Returns : none
*******************************************************************************/
sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb);
/******************************************************************************
* FunctionName : espconn_regist_disconcb
* Description : used to specify the function that should be called when disconnect
* Parameters : espconn -- espconn to set the err callback
* discon_cb -- err callback function to call when err
* Returns : none
*******************************************************************************/
sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb);
/******************************************************************************
* FunctionName : espconn_port
* Description : access port value for client so that we don't end up bouncing
* all connections at the same time .
* Parameters : none
* Returns : access port value
*******************************************************************************/
uint32 espconn_port(void);
/******************************************************************************
* FunctionName : espconn_set_opt
* Description : access port value for client so that we don't end up bouncing
* all connections at the same time .
* Parameters : none
* Returns : access port value
*******************************************************************************/
sint8 espconn_set_opt(struct espconn *espconn, uint8 opt);
/******************************************************************************
* TypedefName : dns_found_callback
* Description : Callback which is invoked when a hostname is found.
* Parameters : name -- pointer to the name that was looked up.
* ipaddr -- pointer to an ip_addr_t containing the IP address of
* the hostname, or NULL if the name could not be found (or on any
* other error).
* callback_arg -- a user-specified callback argument passed to
* dns_gethostbyname
*******************************************************************************/
typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
/******************************************************************************
* FunctionName : espconn_gethostbyname
* Description : Resolve a hostname (string) into an IP address.
* Parameters : pespconn -- espconn to resolve a hostname
* hostname -- the hostname that is to be queried
* addr -- pointer to a ip_addr_t where to store the address if
* it is already cached in the dns_table (only valid if ESPCONN_OK
* is returned!)
* found -- a callback function to be called on success, failure
* or timeout (only if ERR_INPROGRESS is returned!)
* Returns : err_t return code
* - ESPCONN_OK if hostname is a valid IP address string or the host
* name is already in the local names table.
* - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server
* for resolution if no errors are present.
* - ESPCONN_ARG: dns client not initialized or invalid hostname
*******************************************************************************/
err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found);
/******************************************************************************
* FunctionName : espconn_encry_connect
* Description : The function given as connection
* Parameters : espconn -- the espconn used to connect with the host
* Returns : none
*******************************************************************************/
sint8 espconn_secure_connect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_encry_disconnect
* Description : The function given as the disconnection
* Parameters : espconn -- the espconn used to disconnect with the host
* Returns : none
*******************************************************************************/
sint8 espconn_secure_disconnect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_encry_sent
* Description : sent data for client or server
* Parameters : espconn -- espconn to set for client or server
* psent -- data to send
* length -- length of data to send
* Returns : none
*******************************************************************************/
sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length);
/******************************************************************************
* FunctionName : espconn_secure_accept
* Description : The function given as the listen
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 espconn_secure_accept(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_igmp_join
* Description : join a multicast group
* Parameters : host_ip -- the ip address of udp server
* multicast_ip -- multicast ip given by user
* Returns : none
*******************************************************************************/
sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
/******************************************************************************
* FunctionName : espconn_igmp_leave
* Description : leave a multicast group
* Parameters : host_ip -- the ip address of udp server
* multicast_ip -- multicast ip given by user
* Returns : none
*******************************************************************************/
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
#ifndef __ESPCONN_H__
#define __ESPCONN_H__
#include "lwip/ip_addr.h"
typedef sint8 err_t;
typedef void *espconn_handle;
typedef void (* espconn_connect_callback)(void *arg);
typedef void (* espconn_reconnect_callback)(void *arg, sint8 err);
/* Definitions for error constants. */
#define ESPCONN_OK 0 /* No error, everything OK. */
#define ESPCONN_MEM -1 /* Out of memory error. */
#define ESPCONN_TIMEOUT -3 /* Timeout. */
#define ESPCONN_RTE -4 /* Routing problem. */
#define ESPCONN_INPROGRESS -5 /* Operation in progress */
#define ESPCONN_ABRT -8 /* Connection aborted. */
#define ESPCONN_RST -9 /* Connection reset. */
#define ESPCONN_CLSD -10 /* Connection closed. */
#define ESPCONN_CONN -11 /* Not connected. */
#define ESPCONN_ARG -12 /* Illegal argument. */
#define ESPCONN_ISCONN -15 /* Already connected. */
/** Protocol family and type of the espconn */
enum espconn_type {
ESPCONN_INVALID = 0,
/* ESPCONN_TCP Group */
ESPCONN_TCP = 0x10,
/* ESPCONN_UDP Group */
ESPCONN_UDP = 0x20,
};
/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */
enum espconn_state {
ESPCONN_NONE,
ESPCONN_WAIT,
ESPCONN_LISTEN,
ESPCONN_CONNECT,
ESPCONN_WRITE,
ESPCONN_READ,
ESPCONN_CLOSE
};
typedef struct _esp_tcp {
int remote_port;
int local_port;
uint8 local_ip[4];
uint8 remote_ip[4];
espconn_connect_callback connect_callback;
espconn_reconnect_callback reconnect_callback;
espconn_connect_callback disconnect_callback;
espconn_connect_callback write_finish_fn;
} esp_tcp;
typedef struct _esp_udp {
int remote_port;
int local_port;
uint8 local_ip[4];
uint8 remote_ip[4];
} esp_udp;
typedef struct _remot_info{
enum espconn_state state;
int remote_port;
uint8 remote_ip[4];
}remot_info;
/** A callback prototype to inform about events for a espconn */
typedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len);
typedef void (* espconn_sent_callback)(void *arg);
/** A espconn descriptor */
struct espconn {
/** type of the espconn (TCP, UDP) */
enum espconn_type type;
/** current state of the espconn */
enum espconn_state state;
union {
esp_tcp *tcp;
esp_udp *udp;
} proto;
/** A callback function that is informed about events for this espconn */
espconn_recv_callback recv_callback;
espconn_sent_callback sent_callback;
uint8 link_cnt;
void *reverse;
};
enum espconn_option{
ESPCONN_START = 0x00,
ESPCONN_REUSEADDR = 0x01,
ESPCONN_NODELAY = 0x02,
ESPCONN_COPY = 0x04,
ESPCONN_END
};
/******************************************************************************
* FunctionName : espconn_connect
* Description : The function given as the connect
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 espconn_connect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_disconnect
* Description : disconnect with host
* Parameters : espconn -- the espconn used to disconnect the connection
* Returns : none
*******************************************************************************/
sint8 espconn_disconnect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_delete
* Description : disconnect with host
* Parameters : espconn -- the espconn used to disconnect the connection
* Returns : none
*******************************************************************************/
sint8 espconn_delete(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_accept
* Description : The function given as the listen
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 espconn_accept(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_create
* Description : sent data for client or server
* Parameters : espconn -- espconn to the data transmission
* Returns : result
*******************************************************************************/
sint8 espconn_create(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_tcp_get_max_con
* Description : get the number of simulatenously active TCP connections
* Parameters : none
* Returns : none
*******************************************************************************/
uint8 espconn_tcp_get_max_con(void);
/******************************************************************************
* FunctionName : espconn_tcp_set_max_con
* Description : set the number of simulatenously active TCP connections
* Parameters : num -- total number
* Returns : none
*******************************************************************************/
sint8 espconn_tcp_set_max_con(uint8 num);
/******************************************************************************
* FunctionName : espconn_tcp_get_max_con_allow
* Description : get the count of simulatenously active connections on the server
* Parameters : espconn -- espconn to get the count
* Returns : result
*******************************************************************************/
sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_tcp_set_max_con_allow
* Description : set the count of simulatenously active connections on the server
* Parameters : espconn -- espconn to set the count
* num -- support the connection number
* Returns : result
*******************************************************************************/
sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num);
/******************************************************************************
* FunctionName : espconn_regist_time
* Description : used to specify the time that should be called when don't recv data
* Parameters : espconn -- the espconn used to the connection
* interval -- the timer when don't recv data
* Returns : none
*******************************************************************************/
sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag);
/******************************************************************************
* FunctionName : espconn_get_connection_info
* Description : used to specify the function that should be called when disconnect
* Parameters : espconn -- espconn to set the err callback
* discon_cb -- err callback function to call when err
* Returns : none
*******************************************************************************/
sint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags);
/******************************************************************************
* FunctionName : espconn_regist_sentcb
* Description : Used to specify the function that should be called when data
* has been successfully delivered to the remote host.
* Parameters : struct espconn *espconn -- espconn to set the sent callback
* espconn_sent_callback sent_cb -- sent callback function to
* call for this espconn when data is successfully sent
* Returns : none
*******************************************************************************/
sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb);
/******************************************************************************
* FunctionName : espconn_regist_sentcb
* Description : Used to specify the function that should be called when data
* has been successfully delivered to the remote host.
* Parameters : espconn -- espconn to set the sent callback
* sent_cb -- sent callback function to call for this espconn
* when data is successfully sent
* Returns : none
*******************************************************************************/
sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn);
/******************************************************************************
* FunctionName : espconn_sent
* Description : sent data for client or server
* Parameters : espconn -- espconn to set for client or server
* psent -- data to send
* length -- length of data to send
* Returns : none
*******************************************************************************/
sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);
/******************************************************************************
* FunctionName : espconn_regist_connectcb
* Description : used to specify the function that should be called when
* connects to host.
* Parameters : espconn -- espconn to set the connect callback
* connect_cb -- connected callback function to call when connected
* Returns : none
*******************************************************************************/
sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb);
/******************************************************************************
* FunctionName : espconn_regist_recvcb
* Description : used to specify the function that should be called when recv
* data from host.
* Parameters : espconn -- espconn to set the recv callback
* recv_cb -- recv callback function to call when recv data
* Returns : none
*******************************************************************************/
sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb);
/******************************************************************************
* FunctionName : espconn_regist_reconcb
* Description : used to specify the function that should be called when connection
* because of err disconnect.
* Parameters : espconn -- espconn to set the err callback
* recon_cb -- err callback function to call when err
* Returns : none
*******************************************************************************/
sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb);
/******************************************************************************
* FunctionName : espconn_regist_disconcb
* Description : used to specify the function that should be called when disconnect
* Parameters : espconn -- espconn to set the err callback
* discon_cb -- err callback function to call when err
* Returns : none
*******************************************************************************/
sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb);
/******************************************************************************
* FunctionName : espconn_port
* Description : access port value for client so that we don't end up bouncing
* all connections at the same time .
* Parameters : none
* Returns : access port value
*******************************************************************************/
uint32 espconn_port(void);
/******************************************************************************
* FunctionName : espconn_set_opt
* Description : access port value for client so that we don't end up bouncing
* all connections at the same time .
* Parameters : none
* Returns : access port value
*******************************************************************************/
sint8 espconn_set_opt(struct espconn *espconn, uint8 opt);
/******************************************************************************
* TypedefName : dns_found_callback
* Description : Callback which is invoked when a hostname is found.
* Parameters : name -- pointer to the name that was looked up.
* ipaddr -- pointer to an ip_addr_t containing the IP address of
* the hostname, or NULL if the name could not be found (or on any
* other error).
* callback_arg -- a user-specified callback argument passed to
* dns_gethostbyname
*******************************************************************************/
typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
/******************************************************************************
* FunctionName : espconn_gethostbyname
* Description : Resolve a hostname (string) into an IP address.
* Parameters : pespconn -- espconn to resolve a hostname
* hostname -- the hostname that is to be queried
* addr -- pointer to a ip_addr_t where to store the address if
* it is already cached in the dns_table (only valid if ESPCONN_OK
* is returned!)
* found -- a callback function to be called on success, failure
* or timeout (only if ERR_INPROGRESS is returned!)
* Returns : err_t return code
* - ESPCONN_OK if hostname is a valid IP address string or the host
* name is already in the local names table.
* - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server
* for resolution if no errors are present.
* - ESPCONN_ARG: dns client not initialized or invalid hostname
*******************************************************************************/
err_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found);
/******************************************************************************
* FunctionName : espconn_encry_connect
* Description : The function given as connection
* Parameters : espconn -- the espconn used to connect with the host
* Returns : none
*******************************************************************************/
sint8 espconn_secure_connect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_encry_disconnect
* Description : The function given as the disconnection
* Parameters : espconn -- the espconn used to disconnect with the host
* Returns : none
*******************************************************************************/
sint8 espconn_secure_disconnect(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_encry_sent
* Description : sent data for client or server
* Parameters : espconn -- espconn to set for client or server
* psent -- data to send
* length -- length of data to send
* Returns : none
*******************************************************************************/
sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length);
/******************************************************************************
* FunctionName : espconn_secure_accept
* Description : The function given as the listen
* Parameters : espconn -- the espconn used to listen the connection
* Returns : none
*******************************************************************************/
sint8 espconn_secure_accept(struct espconn *espconn);
/******************************************************************************
* FunctionName : espconn_igmp_join
* Description : join a multicast group
* Parameters : host_ip -- the ip address of udp server
* multicast_ip -- multicast ip given by user
* Returns : none
*******************************************************************************/
sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);
/******************************************************************************
* FunctionName : espconn_igmp_leave
* Description : leave a multicast group
* Parameters : host_ip -- the ip address of udp server
* multicast_ip -- multicast ip given by user
* Returns : none
*******************************************************************************/
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

View File

@ -89,6 +89,7 @@ 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);
uint16 system_get_vdd33(void);
const char *system_get_sdk_version(void);
@ -97,6 +98,7 @@ const char *system_get_sdk_version(void);
#define SOFTAP_MODE 0x02
#define STATIONAP_MODE 0x03
typedef enum _auth_mode {
AUTH_OPEN = 0,
AUTH_WEP,
@ -240,6 +242,10 @@ typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len);
void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
#define PHY_MODE_B 0x01
#define PHY_MODE_G 0x02
#define PHY_MODE_N 0x03
enum phy_mode {
PHY_MODE_11B = 1,
PHY_MODE_11G = 2,

View File

@ -5,7 +5,7 @@ MEMORY
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40210000, len = 0x5A000
irom0_0_seg : org = 0x40210000, len = 0x60000
}
PHDRS
@ -71,7 +71,6 @@ SECTIONS
_irom0_text_start = ABSOLUTE(.);
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
*(.literal.* .text.*)
*(.rodata2.text)
/* put font and progmem data into irom0 */
*(.u8g_progmem.*)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

43
lua_examples/adc_rgb.lua Normal file
View File

@ -0,0 +1,43 @@
--
-- Light sensor on ADC(0), RGB LED connected to gpio12(6) Green, gpio13(7) Blue & gpio15(8) Red.
-- This works out of the box on the typical ESP8266 evaluation boards with Battery Holder
--
-- It uses the input from the sensor to drive a "rainbow" effect on the RGB LED
-- Includes a very "pseudoSin" function
--
function led(r,Sg,b)
pwm.setduty(8,r)
pwm.setduty(6,g)
pwm.setduty(7,b)
end
-- this is perhaps the lightest weight sin function in existance
-- Given an integer from 0..128, 0..512 appximating 256 + 256 * sin(idx*Pi/256)
-- This is first order square approximation of sin, it's accurate around 0 and any multiple of 128 (Pi/2),
-- 92% accurate at 64 (Pi/4).
function pseudoSin (idx)
idx = idx % 128
lookUp = 32 - idx % 64
val = 256 - (lookUp * lookUp) / 4
if (idx > 64) then
val = - val;
end
return 256+val
end
pwm.setup(6,500,512)
pwm.setup(7,500,512)
pwm.setup(8,500,512)
pwm.start(6)
pwm.start(7)
pwm.start(8)
tmr.alarm(1,20,1,function()
idx = 3 * adc.read(0) / 2
r = pseudoSin(idx)
g = pseudoSin(idx + 43)
b = pseudoSin(idx + 85)
led(r,g,b)
idx = (idx + 1) % 128
end)

View File

@ -0,0 +1,121 @@
--
-- Simple NodeMCU web server (done is a not so nodeie fashion :-)
--
-- Highly modified by Bruce Meacham, based on work by Scott Beasley 2015
-- Open and free to change and use. Enjoy. [Beasley/Meacham 2015]
--
-- Meacham Update: I streamlined/improved the parsing to focus on simple HTTP GET request and their simple parameters
-- Also added the code to drive a servo/light. Comment out as you see fit.
--
-- Usage:
-- Change SSID and SSID_PASSPHRASE for your wifi network
-- Download to NodeMCU
-- node.compile("http_server.lua")
-- dofile("http_server.lc")
-- When the server is esablished it will output the IP address.
-- http://{ip address}/?s0=1200&light=1
-- s0 is the servo position (actually the PWM hertz), 500 - 2000 are all good values
-- light chanel high(1)/low(0), some evaluation boards have LEDs pre-wired in a "pulled high" confguration, so '0' ground the emitter and turns it on backwards.
--
-- Add to init.lua if you want it to autoboot.
--
-- Your Wifi connection data
local SSID = "YOUR WIFI SSID"
local SSID_PASSWORD = "YOUR SSID PASSPHRASE"
-- General setup
local pinLight = 2 -- this is GPIO4
gpio.mode(pinLight,gpio.OUTPUT)
gpio.write(pinLight,gpio.HIGH)
servo = {}
servo.pin = 4 --this is GPIO2
servo.value = 1500
servo.id = "servo"
gpio.mode(servo.pin, gpio.OUTPUT)
gpio.write(servo.pin, gpio.LOW)
-- This alarm drives the servo
tmr.alarm(0,10,1,function() -- 50Hz
if servo.value then -- generate pulse
gpio.write(servo.pin, gpio.HIGH)
tmr.delay(servo.value)
gpio.write(servo.pin, gpio.LOW)
end
end)
local function connect (conn, data)
local query_data
conn:on ("receive",
function (cn, req_data)
params = get_http_req (req_data)
cn:send("HTTP/1.1 200/OK\r\nServer: NodeLuau\r\nContent-Type: text/html\r\n\r\n")
cn:send ("<h1>ESP8266 Servo &amp; Light Server</h1>\r\n")
if (params["light"] ~= nil) then
if ("0" == params["light"]) then
gpio.write(pinLight, gpio.LOW)
else
gpio.write(pinLight, gpio.HIGH)
end
end
if (params["s0"] ~= nil) then
servo.value = tonumber(params["s0"]);
end
-- Close the connection for the request
cn:close ( )
end)
end
-- Build and return a table of the http request data
function get_http_req (instr)
local t = {}
local str = string.sub(instr, 0, 200)
local v = string.gsub(split(str, ' ')[2], '+', ' ')
parts = split(v, '?')
local params = {}
if (table.maxn(parts) > 1) then
for idx,part in ipairs(split(parts[2], '&')) do
parmPart = split(part, '=')
params[parmPart[1]] = parmPart[2]
end
end
return params
end
-- Source: http://lua-users.org/wiki/MakingLuaLikePhp
-- Credit: http://richard.warburton.it/
function split(str, splitOn)
if (splitOn=='') then return false end
local pos,arr = 0,{}
for st,sp in function() return string.find(str,splitOn,pos,true) end do
table.insert(arr,string.sub(str,pos,st-1))
pos = sp + 1
end
table.insert(arr,string.sub(str,pos))
return arr
end
-- Configure the ESP as a station (client)
wifi.setmode (wifi.STATION)
wifi.sta.config (SSID, SSID_PASSWORD)
wifi.sta.autoconnect (1)
-- Hang out until we get a wifi connection before the httpd server is started.
tmr.alarm (1, 800, 1, function ( )
if wifi.sta.getip ( ) == nil then
print ("Waiting for Wifi connection")
else
tmr.stop (1)
print ("Config done, IP is " .. wifi.sta.getip ( ))
end
end)
-- Create the httpd server
svr = net.createServer (net.TCP, 30)
-- Server listening on port 80, call connect function if a request is received
svr:listen (80, connect)

View File

@ -0,0 +1,98 @@
--[[
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]--
-- Your access point's SSID and password
local SSID = "xxxxxx"
local SSID_PASSWORD = "xxxxxx"
-- configure ESP as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)
local TWILIO_ACCOUNT_SID = "xxxxxx"
local TWILIO_TOKEN = "xxxxxx"
local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service
-- Please be sure to understand the security issues of using this relay app and use at your own risk.
local URI = "/twilio/Calls.json"
function build_post_request(host, uri, data_table)
local data = ""
for param,value in pairs(data_table) do
data = data .. param.."="..value.."&"
end
request = "POST "..uri.." HTTP/1.1\r\n"..
"Host: "..host.."\r\n"..
"Connection: close\r\n"..
"Content-Type: application/x-www-form-urlencoded\r\n"..
"Content-Length: "..string.len(data).."\r\n"..
"\r\n"..
data
print(request)
return request
end
local function display(sck,response)
print(response)
end
-- When using send_sms: the "from" number HAS to be your twilio number.
-- If you have a free twilio account the "to" number HAS to be your twilio verified number.
local function make_call(from,to,body)
local data = {
sid = TWILIO_ACCOUNT_SID,
token = TWILIO_TOKEN,
Body = string.gsub(body," ","+"),
From = from,
To = to
}
socket = net.createConnection(net.TCP,0)
socket:on("receive",display)
socket:connect(80,HOST)
socket:on("connection",function(sck)
local post_request = build_post_request(HOST,URI,data)
sck:send(post_request)
end)
end
function check_wifi()
local ip = wifi.sta.getip()
if(ip==nil) then
print("Connecting...")
else
tmr.stop(0)
print("Connected to AP!")
print(ip)
-- make a call with a voice message "your house is on fire"
make_call("15558976687","1334856679","Your house is on fire!")
end
end
tmr.alarm(0,2000,1,check_wifi)

View File

@ -0,0 +1,33 @@
-- test with cloudmqtt.com
m_dis={}
function dispatch(m,t,pl)
if pl~=nil and m_dis[t] then
m_dis[t](m,pl)
end
end
function topic1func(m,pl)
print("get1: "..pl)
end
function topic2func(m,pl)
print("get2: "..pl)
end
m_dis["/topic1"]=topic1func
m_dis["/topic2"]=topic2func
-- Lua: mqtt.Client(clientid, keepalive, user, pass)
m=mqtt.Client("nodemcu1",60,"test","test123")
m:on("connect",function(m)
print("connection "..node.heap())
m:subscribe("/topic1",0,function(m) print("sub done") end)
m:subscribe("/topic2",0,function(m) print("sub done") end)
m:publish("/topic1","hello",0,0) m:publish("/topic2","world",0,0)
end )
m:on("offline", function(conn)
print("disconnect to broker...")
print(node.heap())
end)
m:on("message",dispatch )
-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) )
m:connect("m11.cloudmqtt.com",11214,0,1)
tmr.alarm(0,10000,1,function() local pl = "time: "..tmr.time()
m:publish("/topic1",pl,0,0)
end)

View File

@ -0,0 +1,56 @@
-- test transfer files over mqtt.
m_dis={}
function dispatch(m,t,pl)
if pl~=nil and m_dis[t] then
m_dis[t](m,pl)
end
end
function pubfile(m,filename)
file.close()
file.open(filename)
repeat
local pl=file.read(1024)
if pl then m:publish("/topic2",pl,0,0) end
until not pl
file.close()
end
-- payload(json): {"cmd":xxx,"content":xxx}
function topic1func(m,pl)
print("get1: "..pl)
local pack = cjson.decode(pl)
if pack.content then
if pack.cmd == "open" then file.open(pack.content,"w+")
elseif pack.cmd == "write" then file.write(pack.content)
elseif pack.cmd == "close" then file.close()
elseif pack.cmd == "remove" then file.remove(pack.content)
elseif pack.cmd == "run" then dofile(pack.content)
elseif pack.cmd == "read" then pubfile(m, pack.content)
end
end
end
m_dis["/topic1"]=topic1func
-- Lua: mqtt.Client(clientid, keepalive, user, pass)
m=mqtt.Client()
m:on("connect",function(m)
print("connection "..node.heap())
m:subscribe("/topic1",0,function(m) print("sub done") end)
end )
m:on("offline", function(conn)
print("disconnect to broker...")
print(node.heap())
end)
m:on("message",dispatch )
-- Lua: mqtt:connect( host, port, secure, auto_reconnect, function(client) )
m:connect(192.168.18.88,1883,0,1)
-- usage:
-- another client(pc) subscribe to /topic2, will receive the test.lua content.
-- and publish below message to /topic1
-- {"cmd":"open","content":"test.lua"}
-- {"cmd":"write","content":"print([[hello world]])\n"}
-- {"cmd":"write","content":"print(\"hello2 world2\")\n"}
-- {"cmd":"write","content":"test.lua"}
-- {"cmd":"run","content":"test.lua"}
-- {"cmd":"read","content":"test.lua"}

View File

@ -0,0 +1,98 @@
--[[
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]--
-- Your access point's SSID and password
local SSID = "xxxxxx"
local SSID_PASSWORD = "xxxxxx"
-- configure ESP as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)
local TWILIO_ACCOUNT_SID = "xxxxxx"
local TWILIO_TOKEN = "xxxxxx"
local HOST = "iot-https-relay.appspot.com" -- visit http://iot-https-relay.appspot.com/ to learn more about this service
-- Please be sure to understand the security issues of using this relay app and use at your own risk.
local URI = "/twilio/Messages.json"
function build_post_request(host, uri, data_table)
local data = ""
for param,value in pairs(data_table) do
data = data .. param.."="..value.."&"
end
request = "POST "..uri.." HTTP/1.1\r\n"..
"Host: "..host.."\r\n"..
"Connection: close\r\n"..
"Content-Type: application/x-www-form-urlencoded\r\n"..
"Content-Length: "..string.len(data).."\r\n"..
"\r\n"..
data
print(request)
return request
end
local function display(sck,response)
print(response)
end
-- When using send_sms: the "from" number HAS to be your twilio number.
-- If you have a free twilio account the "to" number HAS to be your twilio verified number.
local function send_sms(from,to,body)
local data = {
sid = TWILIO_ACCOUNT_SID,
token = TWILIO_TOKEN,
Body = string.gsub(body," ","+"),
From = from,
To = to
}
socket = net.createConnection(net.TCP,0)
socket:on("receive",display)
socket:connect(80,HOST)
socket:on("connection",function(sck)
local post_request = build_post_request(HOST,URI,data)
sck:send(post_request)
end)
end
function check_wifi()
local ip = wifi.sta.getip()
if(ip==nil) then
print("Connecting...")
else
tmr.stop(0)
print("Connected to AP!")
print(ip)
-- send a text message with the text "Hello from your esp8266"
send_sms("15558889944","15559998845","Hello from your ESP8266")
end
end
tmr.alarm(0,7000,1,check_wifi)

View File

@ -2,9 +2,9 @@
-- setup I2c and connect display
function init_i2c_display()
-- SDA and SCL can be assigned freely to available GPIOs
sda = 5 -- GPIO14
scl = 6 -- GPIO12
sla = 0x3c
local sda = 5 -- GPIO14
local scl = 6 -- GPIO12
local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)
disp = u8g.ssd1306_128x64_i2c(sla)
end
@ -15,9 +15,9 @@ function init_spi_display()
-- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16
local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2
local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
disp = u8g.ssd1306_128x64_spi(cs, dc, res)

View File

@ -2,9 +2,9 @@
-- setup I2c and connect display
function init_i2c_display()
-- SDA and SCL can be assigned freely to available GPIOs
sda = 5 -- GPIO14
scl = 6 -- GPIO12
sla = 0x3c
local sda = 5 -- GPIO14
local scl = 6 -- GPIO12
local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)
disp = u8g.ssd1306_128x64_i2c(sla)
end
@ -15,9 +15,9 @@ function init_spi_display()
-- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16
local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2
local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
disp = u8g.ssd1306_128x64_spi(cs, dc, res)
@ -91,17 +91,6 @@ function ascii_1()
end
end
function ascii_2()
local x, y, s
disp:drawStr(0, 0, "ASCII page 2")
for y = 0, 5, 1 do
for x = 0, 15, 1 do
s = y*16 + x + 160
disp:drawStr(x*7, y*10+10, string.char(s))
end
end
end
function extra_page(a)
disp:drawStr(0, 12, "setScale2x2")
disp:setScale2x2()
@ -131,8 +120,6 @@ function draw(draw_state)
elseif (component == 6) then
ascii_1()
elseif (component == 7) then
ascii_2()
elseif (component == 8) then
extra_page(bit.band(draw_state, 7))
end
end

View File

@ -2,9 +2,9 @@
-- setup I2c and connect display
function init_i2c_display()
-- SDA and SCL can be assigned freely to available GPIOs
sda = 5 -- GPIO14
scl = 6 -- GPIO12
sla = 0x3c
local sda = 5 -- GPIO14
local scl = 6 -- GPIO12
local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)
disp = u8g.ssd1306_128x64_i2c(sla)
end
@ -15,9 +15,9 @@ function init_spi_display()
-- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16
local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2
local res = 0 -- GPIO16
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
disp = u8g.ssd1306_128x64_spi(cs, dc, res)

View File

@ -1,6 +1,8 @@
# DHTxx module
This module is compatible with DHT11, DHT21 and DHT22.
And is able to auto-select wheather you are using DHT11 or DHT2x
No need to use a resistor to connect the pin data of DHT22 to ESP8266.
##Integer Verison[When using DHT11, Float version is useless...]
@ -10,14 +12,13 @@ PIN = 4 -- data pin, GPIO2
DHT= require("dht_lib")
--dht.read11(PIN)
DHT.read22(PIN)
DHT.read(PIN)
t = DHT.getTemperature()
h = DHT.getHumidity()
if h == nil then
print("Error reading from DHT11/22")
print("Error reading from DHTxx")
else
-- temperature in degrees Celsius and Farenheit
@ -41,8 +42,7 @@ PIN = 4 -- data pin, GPIO2
DHT= require("dht_lib")
--dht.read11(PIN)
DHT.read22(PIN)
DHT.read(PIN)
t = DHT.getTemperature()
h = DHT.getHumidity()
@ -52,11 +52,12 @@ if h == nil then
else
-- temperature in degrees Celsius and Farenheit
-- floating point and integer version:
print("Temperature: "..t.." deg C")
print("Temperature: "..(t/10).." deg C")
print("Temperature: "..(9 * t / 50 + 32).." deg F")
-- humidity
print("Humidity: "..h.."%")
print("Humidity: "..(h/10).."%")
end
-- release module
@ -64,12 +65,10 @@ DHT = nil
package.loaded["dht_lib"]=nil
```
## Functions
### read11
read11(pin)
Read humidity and temperature from DHT11.
###read22
read22(pin)
Read humidity and temperature from DHT22/21.
###read
read(pin)
Read humidity and temperature from DHTxx(11,21,22...).
**Parameters:**
* pin - ESP8266 pin connect to data pin
@ -88,4 +87,3 @@ Returns the temperature of the last reading.
**Returns:**
* last temperature reading in(dht22) 0.1ºC (dht11)1ºC
*

View File

@ -8,10 +8,13 @@
-- ***************************************************************************
--Support list
--DHT11 Tested ->read11
--DHT21 Not Tested->read22
--DHT22 Tested->read22
--DHT11 Tested
--DHT21 Not Test yet
--DHT22(AM2302) Tested
--AM2320 Not Test yet
--Output format-> Real temperature times 10(or DHT22 will miss it float part in Int Version)
--==========================Module Part======================
local moduleName = ...
local M = {}
@ -37,8 +40,6 @@ local function read(pin)
bitStream[j] = 0
end
-- Step 1: send out start signal to DHT22
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
@ -57,7 +58,7 @@ local function read(pin)
while (gpio_read(pin) == 0 ) do end
c=0
while (gpio_read(pin) == 1 and c < 500) do c = c + 1 end
-- Step 3: DHT22 send data
for j = 1, 40, 1 do
while (gpio_read(pin) == 1 and bitlength < 10 ) do
@ -69,68 +70,79 @@ local function read(pin)
while (gpio_read(pin) == 0) do end
end
end
---------------------------Convert the bitStream into Number through DHT11 Ways--------------------------
function M.read11(pin)
--As for DHT11 40Bit is consisit of 5Bytes
--First byte->Humidity Data's Int part
--Sencond byte->Humidity Data's Float Part(Which should be empty)
--Third byte->Temp Data;s Intpart
--Forth byte->Temp Data's Float Part(Which should be empty)
--Fifth byte->SUM Byte, Humi+Temp
---------------------------Check out the data--------------------------
----Auto Select the DHT11/DHT22 By check the byte[1] && byte[3] -------
---------------Which is empty when using DHT11-------------------------
function M.read(pin)
read(pin)
local checksum = 0
local checksumTest
--DHT data acquired, process.
local byte_0 = 0
local byte_1 = 0
local byte_2 = 0
local byte_3 = 0
local byte_4 = 0
for i = 1, 8, 1 do -- Byte[0]
if (bitStream[i] > 3) then
humidity = humidity + 2 ^ (8 - i)
end
end
for i = 1, 8, 1 do -- Byte[2]
if (bitStream[i + 16] > 3) then
temperature = temperature + 2 ^ (8 - i)
end
end
for i = 1, 8, 1 do --Byte[4]
if (bitStream[i + 32] > 3) then
checksum = checksum + 2 ^ (8 - i)
byte_0 = byte_0 + 2 ^ (8 - i)
end
end
if(checksum ~= humidity+temperature) then
humidity = nil
temperature = nil
end
end
---------------------------Convert the bitStream into Number through DHT22 Ways--------------------------
function M.read22( pin )
--As for DHT22 40Bit is consisit of 5Bytes
--First byte->Humidity Data's High Bit
--Sencond byte->Humidity Data's Low Bit(And if over 0x8000, use complement)
--Third byte->Temp Data's High Bit
--Forth byte->Temp Data's Low Bit
--Fifth byte->SUM Byte
read(pin)
local checksum = 0
local checksumTest
--DHT data acquired, process.
for i = 1, 16, 1 do
if (bitStream[i] > 3) then
humidity = humidity + 2 ^ (16 - i)
for i = 1, 8, 1 do -- Byte[1]
if (bitStream[i+8] > 3) then
byte_1 = byte_1 + 2 ^ (8 - i)
end
end
for i = 1, 16, 1 do
if (bitStream[i + 16] > 3) then
temperature = temperature + 2 ^ (16 - i)
for i = 1, 8, 1 do -- Byte[2]
if (bitStream[i+16] > 3) then
byte_2 = byte_2 + 2 ^ (8 - i)
end
end
for i = 1, 8, 1 do
if (bitStream[i + 32] > 3) then
checksum = checksum + 2 ^ (8 - i)
for i = 1, 8, 1 do -- Byte[3]
if (bitStream[i+24] > 3) then
byte_2 = byte_2 + 2 ^ (8 - i)
end
end
for i = 1, 8, 1 do -- Byte[4]
if (bitStream[i+32] > 3) then
byte_4 = byte_4 + 2 ^ (8 - i)
end
end
if byte_1==0 and byte_3 == 0 then
---------------------------Convert the bitStream into Number through DHT11's Way--------------------------
--As for DHT11 40Bit is consisit of 5Bytes
--First byte->Humidity Data's Int part
--Sencond byte->Humidity Data's Float Part(Which should be empty)
--Third byte->Temp Data;s Intpart
--Forth byte->Temp Data's Float Part(Which should be empty)
--Fifth byte->SUM Byte, Humi+Temp
if(byte_4 ~= byte_0+byte_2) then
humidity = nil
temperature = nil
else
humidity = byte_0 *10 -- In order to universe with the DHT22
temperature = byte_2 *10
end
else ---------------------------Convert the bitStream into Number through DHT22's Way--------------------------
--As for DHT22 40Bit is consisit of 5Bytes
--First byte->Humidity Data's High Bit
--Sencond byte->Humidity Data's Low Bit(And if over 0x8000, use complement)
--Third byte->Temp Data's High Bit
--Forth byte->Temp Data's Low Bit
--Fifth byte->SUM Byte
humidity = byte_0 * 256 + byte_1
temperature = byte_2 * 256 + byte_3
checksum = byte_4
checksumTest = (bit.band(humidity, 0xFF) + bit.rshift(humidity, 8) + bit.band(temperature, 0xFF) + bit.rshift(temperature, 8))
checksumTest = bit.band(checksumTest, 0xFF)
@ -143,9 +155,18 @@ function M.read22( pin )
if (checksumTest - checksum >= 1) or (checksum - checksumTest >= 1) then
humidity = nil
end
end
---------------------------Check out the data--------------------------
end
byte_0 = nil
byte_1 = nil
byte_2 = nil
byte_3 = nil
byte_4 = nil
end
--------------API for geting the data out------------------
function M.getTemperature()
return temperature
end
@ -153,5 +174,5 @@ end
function M.getHumidity()
return humidity
end
-------------Return Index------------------------------------
return M

View File

@ -0,0 +1,98 @@
# LM92 module
This module adds basic support for the LM92 +-0.33C 12bit+sign temperature sensor. More details in the [datasheet](http://www.ti.com/lit/ds/symlink/lm92.pdf).
Works:
- getting the temperature
- entering the chip's to shutdown mode (350uA -> 5uA power consumption)
- waking up the chip from shutdown
##Require
```lua
LM92 = require("lm92")
```
## Release
```lua
LM92 = nil
package.loaded["lm92"]=nil
```
##init()
####Description
Setting the i2c pins and address for lm92.
####Syntax
init(sda, scl, address)
####Parameters
sda: 1~12, IO index.<br />
scl: 1~12, IO index.<br />
address: 0x48~0x4b, i2c address (depends on tha A0~A1 pins)
####Returns
nil
####Example
```lua
LM92 = require("lm92")
gpio0 = 3
gpio2 = 4
sda = gpio0
scl = gpio2
addr = 0x48
LM92.init(sda, scl,addr)
```
##getTemperature()
####Description
Returns the temperature register's content.
####Syntax
getTemperature()
####Parameters
-
####Returns
Temperature in degree Celsius.
####Example
```lua
t = LM92.getTemperature()
print("Got temperature: "..t.." C")
```
##wakeup()
####Description
Makes the chip exit the low power shutdown mode.
####Syntax
wakeup()
####Parameters
-
####Returns
-
####Example
```lua
LM92.wakeup()
tmr.delay( 1 * 1000 * 1000 )
```
##shutdown()
####Description
Makes the chip enter the low power shutdown mode.
####Syntax
shutdown()
####Parameters
-
####Returns
-
####Example
```lua
LM92.shutdown()
```
#### TODO:
- add full support of the features, including interrupt and critical alert support

94
lua_modules/lm92/lm92.lua Normal file
View File

@ -0,0 +1,94 @@
-- ******************************************************
-- LM92 module for ESP8266 with nodeMCU
--
-- Written by Levente Tamas <levente.tamas@navicron.com>
--
-- GNU LGPL, see https://www.gnu.org/copyleft/lesser.html
-- ******************************************************
-- Module Bits
local moduleName = ...
local M = {}
_G[moduleName] = M
-- Default ID
local id = 0
-- Local vars
local address = 0
-- read regs for len number of bytes
-- return table with data
local function read_reg(reg_addr, len)
local ret={}
local c
local x
i2c.start(id)
i2c.address(id, address ,i2c.TRANSMITTER)
i2c.write(id,reg_addr)
i2c.stop(id)
i2c.start(id)
i2c.address(id, address,i2c.RECEIVER)
c=i2c.read(id,len)
for x=1,len,1 do
tc=string.byte(c,x)
table.insert(ret,tc)
end
i2c.stop(id)
return ret
end
--write reg with data table
local function write_reg(reg_addr, data)
i2c.start(id)
i2c.address(id, address, i2c.TRANSMITTER)
i2c.write(id, reg_addr)
i2c.write(id, data)
i2c.stop(id)
end
-- initialize i2c
-- d: sda
-- c: scl
-- a: i2c addr 0x48|A1<<1|A0 (A0-A1: chip pins)
function M.init(d,c,a)
if (d ~= nil) and (c ~= nil) and (d >= 0) and (d <= 11) and (c >= 0) and ( c <= 11) and (d ~= l) and (a ~= nil) and (a >= 0x48) and (a <= 0x4b ) then
sda = d
scl = c
address = a
i2c.start(id)
res = i2c.address(id, address, i2c.TRANSMITTER) --verify that the address is valid
i2c.stop(id)
if (res == false) then
print("device not found")
return nil
end
else
print("i2c configuration failed") return nil
end
i2c.setup(id,sda,scl,i2c.SLOW)
end
-- Return the temperature data
function M.getTemperature()
local temperature
local tmp=read_reg(0x00,2) --read 2 bytes from the temperature register
temperature=bit.rshift(tmp[1]*256+tmp[2],3) --lower 3 bits are status bits
if (temperature>=0x1000) then
temperature= temperature-0x2000 --convert the two's complement
end
return temperature * 0.0625
end
-- Put the LM92 into shutdown mode
function M.shutdown()
write_reg(0x01,0x01)
end
-- Bring the LM92 out of shutdown mode
function M.wakeup()
write_reg(0x01,0x00)
end
return M

View File

@ -0,0 +1,25 @@
-- ***************************************************************************
-- Example for Yeelink Lib
--
-- Written by Martin
--
--
-- MIT license, http://opensource.org/licenses/MIT
-- ***************************************************************************
wifi.setmode(wifi.STATION) --Step1: Connect to Wifi
wifi.sta.config("SSID","Password")
dht = require("dht_lib") --Step2: "Require" the libs
yeelink = require("yeelink_lib")
yeelink.init(23333,23333,"You api-key",function() --Step3: Register the callback function
print("Yeelink Init OK...")
tmr.alarm(1,60000,1,function() --Step4: Have fun~ (Update your data)
dht.read(4)
yeelink.update(dht.getTemperature())
end)
end)

View File

@ -0,0 +1,134 @@
-- ***************************************************************************
-- Yeelink Updata Libiary Version 0.1.2 r1
--
-- Written by Martin
-- but based on a script of zhouxu_o from bbs.nodemcu.com
--
-- MIT license, http://opensource.org/licenses/MIT
-- ***************************************************************************
--==========================Module Part======================
local moduleName = ...
local M = {}
_G[moduleName] = M
--=========================Local Args=======================
local dns = "0.0.0.0"
local device = ""
local sensor = ""
local apikey = ""
--================================
local debug = true --<<<<<<<<<<<<< Don't forget to "false" it before using
--================================
local sk=net.createConnection(net.TCP, 0)
local datapoint = 0
--====DNS the yeelink ip advance(in order to save RAM)=====
if wifi.sta.getip() == nil then
print("Please Connect WIFI First")
tmr.alarm(1,1000,1,function ()
if wifi.sta.getip() ~= nil then
tmr.stop(1)
sk:dns("api.yeelink.net",function(conn,ip)
dns=ip
print("DNS YEELINK OK... IP: "..dns)
end)
end
end)
end
sk:dns("api.yeelink.net",function(conn,ip)
dns=ip
print("DNS YEELINK OK... IP: "..dns)
end)
--========Set the init function===========
--device->number
--sensor->number
-- apikey must be -> string <-
-- e.g. xxx.init(00000,00000,"123j12b3jkb12k4b23bv54i2b5b3o4")
--========================================
function M.init(_device, _sensor, _apikey)
device = tostring(_device)
sensor = tostring(_sensor)
apikey = _apikey
if dns == "0.0.0.0" then
tmr.alarm(2,5000,1,function ()
if dns == "0.0.0.0" then
print("Waiting for DNS...")
end
end)
return false
else
return dns
end
end
--========Check the DNS Status===========
--if DNS success, return the address(string)
--if DNS fail(or processing), return nil
--
--
--========================================
function M.getDNS()
if dns == "0.0.0.0" then
return nil
else
return dns
end
end
--=====Update to Yeelink Sever(At least 10s per sencods))=====
-- datapoint->number
--
--e.g. xxx.update(233.333)
--============================================================
function M.update(_datapoint)
datapoint = tostring(_datapoint)
sk:on("connection", function(conn)
print("connect OK...")
local a=[[{"value":]]
local b=[[}]]
local st=a..datapoint..b
sk:send("POST /v1.0/device/"..device.."/sensor/"..sensor.."/datapoints HTTP/1.1\r\n"
.."Host: www.yeelink.net\r\n"
.."Content-Length: "..string.len(st).."\r\n"--the length of json is important
.."Content-Type: application/x-www-form-urlencoded\r\n"
.."U-ApiKey:"..apikey.."\r\n"
.."Cache-Control: no-cache\r\n\r\n"
..st.."\r\n" )
end)
sk:on("receive", function(sck, content)
if debug then
print("\r\n"..content.."\r\n")
else
print("Date Receive")
end
end)
sk:connect(80,dns)
end
--================end==========================
return M

Binary file not shown.

Binary file not shown.

View File

@ -41,7 +41,7 @@ class ESPROM:
# Maximum block sized for RAM and Flash writes, respectively.
ESP_RAM_BLOCK = 0x1800
ESP_FLASH_BLOCK = 0x100
ESP_FLASH_BLOCK = 0x400
# Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want.
ESP_ROM_BAUD = 115200
@ -56,6 +56,12 @@ class ESPROM:
ESP_OTP_MAC0 = 0x3ff00050
ESP_OTP_MAC1 = 0x3ff00054
# Sflash stub: an assembly routine to read from spi flash and send to host
SFLASH_STUB = "\x80\x3c\x00\x40\x1c\x4b\x00\x40\x21\x11\x00\x40\x00\x80" \
"\xfe\x3f\xc1\xfb\xff\xd1\xf8\xff\x2d\x0d\x31\xfd\xff\x41\xf7\xff\x4a" \
"\xdd\x51\xf9\xff\xc0\x05\x00\x21\xf9\xff\x31\xf3\xff\x41\xf5\xff\xc0" \
"\x04\x00\x0b\xcc\x56\xec\xfd\x06\xff\xff\x00\x00"
def __init__(self, port = 0, baud = ESP_ROM_BAUD):
self._port = serial.Serial(port, baud)
@ -78,15 +84,7 @@ class ESPROM:
""" Write bytes to the serial port while performing SLIP escaping """
def write(self, packet):
buf = '\xc0'
for b in packet:
if b == '\xc0':
buf += '\xdb\xdc'
elif b == '\xdb':
buf += '\xdb\xdd'
else:
buf += b
buf += '\xc0'
buf = '\xc0'+(packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc'))+'\xc0'
self._port.write(buf)
""" Calculate checksum of a blob, as it is defined by the ROM """
@ -132,11 +130,25 @@ class ESPROM:
# RTS = CH_PD (i.e reset)
# DTR = GPIO0
# self._port.setRTS(True)
# self._port.setDTR(True)
# self._port.setRTS(False)
# time.sleep(0.1)
# self._port.setDTR(False)
# NodeMCU devkit
self._port.setRTS(True)
self._port.setDTR(True)
self._port.setRTS(False)
time.sleep(0.1)
self._port.setRTS(False)
self._port.setDTR(False)
time.sleep(0.1)
self._port.setRTS(True)
time.sleep(0.1)
self._port.setDTR(True)
self._port.setRTS(False)
time.sleep(0.3)
self._port.setDTR(True)
self._port.timeout = 0.5
for i in xrange(10):
@ -209,16 +221,78 @@ class ESPROM:
self.flash_begin(0, 0)
self.flash_finish(reboot)
""" Read MAC from OTP ROM """
def read_mac(self):
mac0 = esp.read_reg(esp.ESP_OTP_MAC0)
mac1 = esp.read_reg(esp.ESP_OTP_MAC1)
if ((mac1 >> 16) & 0xff) == 0:
oui = (0x18, 0xfe, 0x34)
elif ((mac1 >> 16) & 0xff) == 1:
oui = (0xac, 0xd0, 0x74)
else:
raise Exception("Unknown OUI")
return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
""" Read SPI flash manufacturer and device id """
def flash_id(self):
self.flash_begin(0, 0)
self.write_reg(0x60000240, 0x0, 0xffffffff)
self.write_reg(0x60000200, 0x10000000, 0xffffffff)
flash_id = esp.read_reg(0x60000240)
self.flash_finish(False)
return flash_id
""" Read SPI flash """
def flash_read(self, offset, size, count = 1):
# Create a custom stub
stub = struct.pack('<III', offset, size, count) + self.SFLASH_STUB
# Trick ROM to initialize SFlash
self.flash_begin(0, 0)
# Download stub
self.mem_begin(len(stub), 1, len(stub), 0x40100000)
self.mem_block(stub, 0)
self.mem_finish(0x4010001c)
# Fetch the data
data = ''
for _ in xrange(count):
if self._port.read(1) != '\xc0':
raise Exception('Invalid head of packet (sflash read)')
data += self.read(size)
if self._port.read(1) != chr(0xc0):
raise Exception('Invalid end of packet (sflash read)')
return data
""" Perform a chip erase of SPI flash """
def flash_erase(self):
# Trick ROM to initialize SFlash
self.flash_begin(0, 0)
# This is hacky: we don't have a custom stub, instead we trick
# the bootloader to jump to the SPIEraseChip() routine and then halt/crash
# when it tries to boot an unconfigured system.
self.mem_begin(0,0,0,0x40100000)
self.mem_finish(0x40004984)
# Yup - there's no good way to detect if we succeeded.
# It it on the other hand unlikely to fail.
class ESPFirmwareImage:
def __init__(self, filename = None):
self.segments = []
self.entrypoint = 0
self.flash_mode = 0
self.flash_size_freq = 0
if filename is not None:
f = file(filename, 'rb')
(magic, segments, _, _, self.entrypoint) = struct.unpack('<BBBBI', f.read(8))
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', f.read(8))
# some sanity check
if magic != ESPROM.ESP_IMAGE_MAGIC or segments > 16:
@ -246,7 +320,8 @@ class ESPFirmwareImage:
def save(self, filename):
f = file(filename, 'wb')
f.write(struct.pack('<BBBBI', ESPROM.ESP_IMAGE_MAGIC, len(self.segments), 0, 0, self.entrypoint))
f.write(struct.pack('<BBBBI', ESPROM.ESP_IMAGE_MAGIC, len(self.segments),
self.flash_mode, self.flash_size_freq, self.entrypoint))
checksum = ESPROM.ESP_CHECKSUM_MAGIC
for (offset, size, data) in self.segments:
@ -346,6 +421,12 @@ if __name__ == '__main__':
'write_flash',
help = 'Write a binary blob to flash')
parser_write_flash.add_argument('addr_filename', nargs = '+', help = 'Address and binary file to write there, separated by space')
parser_write_flash.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
choices = ['40m', '26m', '20m', '80m'], default = '40m')
parser_write_flash.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
parser_write_flash.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
parser_run = subparsers.add_parser(
'run',
@ -369,11 +450,32 @@ if __name__ == '__main__':
help = 'Create an application image from ELF file')
parser_elf2image.add_argument('input', help = 'Input ELF file')
parser_elf2image.add_argument('--output', '-o', help = 'Output filename prefix', type = str)
parser_elf2image.add_argument('--flash_freq', '-ff', help = 'SPI Flash frequency',
choices = ['40m', '26m', '20m', '80m'], default = '40m')
parser_elf2image.add_argument('--flash_mode', '-fm', help = 'SPI Flash mode',
choices = ['qio', 'qout', 'dio', 'dout'], default = 'qio')
parser_elf2image.add_argument('--flash_size', '-fs', help = 'SPI Flash size in Mbit',
choices = ['4m', '2m', '8m', '16m', '32m'], default = '4m')
parser_read_mac = subparsers.add_parser(
'read_mac',
help = 'Read MAC address from OTP ROM')
parser_flash_id = subparsers.add_parser(
'flash_id',
help = 'Read SPI flash manufacturer and device ID')
parser_read_flash = subparsers.add_parser(
'read_flash',
help = 'Read SPI flash content')
parser_read_flash.add_argument('address', help = 'Start address', type = arg_auto_int)
parser_read_flash.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)
parser_read_flash.add_argument('filename', help = 'Name of binary dump')
parser_erase_flash = subparsers.add_parser(
'erase_flash',
help = 'Perform Chip Erase on SPI flash')
args = parser.parse_args()
# Create the ESPROM connection object, if needed
@ -421,6 +523,12 @@ if __name__ == '__main__':
elif args.operation == 'write_flash':
assert len(args.addr_filename) % 2 == 0
flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
flash_info = struct.pack('BB', flash_mode, flash_size_freq)
while args.addr_filename:
address = int(args.addr_filename[0], 0)
filename = args.addr_filename[1]
@ -434,7 +542,11 @@ if __name__ == '__main__':
print '\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks),
sys.stdout.flush()
block = image[0:esp.ESP_FLASH_BLOCK]
block = block + '\xe0' * (esp.ESP_FLASH_BLOCK-len(block))
# Fix sflash config data
if address == 0 and seq == 0 and block[0] == '\xe9':
block = block[0:2] + flash_info + block[4:]
# Pad the last block
block = block + '\xff' * (esp.ESP_FLASH_BLOCK-len(block))
esp.flash_block(block, seq)
image = image[esp.ESP_FLASH_BLOCK:]
seq += 1
@ -478,6 +590,11 @@ if __name__ == '__main__':
for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")):
data = e.load_section(section)
image.add_segment(e.get_symbol_addr(start), data)
image.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
image.flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40}[args.flash_size]
image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
image.save(args.output + "0x00000.bin")
data = e.load_section(".irom0.text")
off = e.get_symbol_addr("_irom0_text_start") - 0x40200000
@ -487,6 +604,17 @@ if __name__ == '__main__':
f.close()
elif args.operation == 'read_mac':
mac0 = esp.read_reg(esp.ESP_OTP_MAC0)
mac1 = esp.read_reg(esp.ESP_OTP_MAC1)
print 'MAC: 18:fe:34:%02x:%02x:%02x' % ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
mac = esp.read_mac()
print 'MAC: %s' % ':'.join(map(lambda x: '%02x'%x, mac))
elif args.operation == 'flash_id':
flash_id = esp.flash_id()
print 'Manufacturer: %02x' % (flash_id & 0xff)
print 'Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff)
elif args.operation == 'read_flash':
print 'Please wait...'
file(args.filename, 'wb').write(esp.flash_read(args.address, 1024, int(math.ceil(args.size / 1024.)))[:args.size])
elif args.operation == 'erase_flash':
esp.flash_erase()