Commit 45e7f270 authored by funshine's avatar funshine
Browse files

Merge branch 'dev' into json

parents 4d3c1a93 d8c8d257
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// #define FLASH_8M // #define FLASH_8M
// #define FLASH_16M // #define FLASH_16M
#define FLASH_AUTOSIZE #define FLASH_AUTOSIZE
#define FLASH_SAFE_API
// #define DEVELOP_VERSION // #define DEVELOP_VERSION
#define FULL_VERSION_FOR_USER #define FULL_VERSION_FOR_USER
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
static int node_restart( lua_State* L ) static int node_restart( lua_State* L )
{ {
system_restart(); system_restart();
return 0; return 0;
} }
// Lua: dsleep( us, option ) // Lua: dsleep( us, option )
...@@ -56,7 +56,7 @@ static int node_deepsleep( lua_State* L ) ...@@ -56,7 +56,7 @@ static int node_deepsleep( lua_State* L )
else else
system_deep_sleep( us ); system_deep_sleep( us );
} }
return 0; return 0;
} }
// Lua: dsleep_set_options // Lua: dsleep_set_options
...@@ -80,10 +80,14 @@ static int node_info( lua_State* L ) ...@@ -80,10 +80,14 @@ static int node_info( lua_State* L )
lua_pushinteger(L, NODE_VERSION_REVISION); lua_pushinteger(L, NODE_VERSION_REVISION);
lua_pushinteger(L, system_get_chip_id()); // chip id lua_pushinteger(L, system_get_chip_id()); // chip id
lua_pushinteger(L, spi_flash_get_id()); // flash id lua_pushinteger(L, spi_flash_get_id()); // flash id
lua_pushinteger(L, flash_get_size_byte() / 1024); // flash size in KB #if defined(FLASH_SAFE_API)
lua_pushinteger(L, flash_get_mode()); lua_pushinteger(L, flash_safe_get_size_byte() / 1024); // flash size in KB
lua_pushinteger(L, flash_get_speed()); #else
return 8; lua_pushinteger(L, flash_rom_get_size_byte() / 1024); // flash size in KB
#endif // defined(FLASH_SAFE_API)
lua_pushinteger(L, flash_rom_get_mode());
lua_pushinteger(L, flash_rom_get_speed());
return 8;
} }
// Lua: chipid() // Lua: chipid()
...@@ -91,7 +95,7 @@ static int node_chipid( lua_State* L ) ...@@ -91,7 +95,7 @@ static int node_chipid( lua_State* L )
{ {
uint32_t id = system_get_chip_id(); uint32_t id = system_get_chip_id();
lua_pushinteger(L, id); lua_pushinteger(L, id);
return 1; return 1;
} }
// Lua: readvdd33() // Lua: readvdd33()
static int node_readvdd33( lua_State* L ) static int node_readvdd33( lua_State* L )
...@@ -106,24 +110,23 @@ static int node_flashid( lua_State* L ) ...@@ -106,24 +110,23 @@ static int node_flashid( lua_State* L )
{ {
uint32_t id = spi_flash_get_id(); uint32_t id = spi_flash_get_id();
lua_pushinteger( L, id ); lua_pushinteger( L, id );
return 1; return 1;
} }
// Lua: flashsize() // Lua: flashsize()
static int node_flashsize( lua_State* L ) static int node_flashsize( lua_State* L )
{ {
//uint32_t sz = 0; if (lua_type(L, 1) == LUA_TNUMBER)
//if(lua_type(L, 1) == LUA_TNUMBER) {
//{ flash_rom_set_size_byte(luaL_checkinteger(L, 1));
// sz = luaL_checkinteger(L, 1); }
// if(sz > 0) #if defined(FLASH_SAFE_API)
// { uint32_t sz = flash_safe_get_size_byte();
// flash_set_size_byte(sz); #else
// } uint32_t sz = flash_rom_get_size_byte();
//} #endif // defined(FLASH_SAFE_API)
uint32_t sz = flash_get_size_byte();
lua_pushinteger( L, sz ); lua_pushinteger( L, sz );
return 1; return 1;
} }
// Lua: heap() // Lua: heap()
...@@ -131,7 +134,7 @@ static int node_heap( lua_State* L ) ...@@ -131,7 +134,7 @@ static int node_heap( lua_State* L )
{ {
uint32_t sz = system_get_free_heap_size(); uint32_t sz = system_get_free_heap_size();
lua_pushinteger(L, sz); lua_pushinteger(L, sz);
return 1; return 1;
} }
static lua_State *gL = NULL; static lua_State *gL = NULL;
...@@ -146,7 +149,7 @@ static int node_led( lua_State* L ) ...@@ -146,7 +149,7 @@ static int node_led( lua_State* L )
if ( lua_isnumber(L, 1) ) if ( lua_isnumber(L, 1) )
{ {
low = lua_tointeger(L, 1); low = lua_tointeger(L, 1);
if ( low < 0 ){ if ( low < 0 ) {
return luaL_error( L, "wrong arg type" ); return luaL_error( L, "wrong arg type" );
} }
} else { } else {
...@@ -155,7 +158,7 @@ static int node_led( lua_State* L ) ...@@ -155,7 +158,7 @@ static int node_led( lua_State* L )
if ( lua_isnumber(L, 2) ) if ( lua_isnumber(L, 2) )
{ {
high = lua_tointeger(L, 2); high = lua_tointeger(L, 2);
if ( high < 0 ){ if ( high < 0 ) {
return luaL_error( L, "wrong arg type" ); return luaL_error( L, "wrong arg type" );
} }
} else { } else {
...@@ -163,14 +166,14 @@ static int node_led( lua_State* L ) ...@@ -163,14 +166,14 @@ static int node_led( lua_State* L )
} }
led_high_count = (uint32_t)high / READLINE_INTERVAL; led_high_count = (uint32_t)high / READLINE_INTERVAL;
led_low_count = (uint32_t)low / READLINE_INTERVAL; led_low_count = (uint32_t)low / READLINE_INTERVAL;
return 0; return 0;
} }
static int long_key_ref = LUA_NOREF; static int long_key_ref = LUA_NOREF;
static int short_key_ref = LUA_NOREF; static int short_key_ref = LUA_NOREF;
void default_long_press(void *arg){ void default_long_press(void *arg) {
if(led_high_count == 12 && led_low_count == 12){ if (led_high_count == 12 && led_low_count == 12) {
led_low_count = led_high_count = 6; led_low_count = led_high_count = 6;
} else { } else {
led_low_count = led_high_count = 12; led_low_count = led_high_count = 12;
...@@ -180,32 +183,32 @@ void default_long_press(void *arg){ ...@@ -180,32 +183,32 @@ void default_long_press(void *arg){
// NODE_DBG("default_long_press is called. hc: %d, lc: %d\n", led_high_count, led_low_count); // NODE_DBG("default_long_press is called. hc: %d, lc: %d\n", led_high_count, led_low_count);
} }
void default_short_press(void *arg){ void default_short_press(void *arg) {
system_restart(); system_restart();
} }
void key_long_press(void *arg){ void key_long_press(void *arg) {
NODE_DBG("key_long_press is called.\n"); NODE_DBG("key_long_press is called.\n");
if(long_key_ref == LUA_NOREF){ if (long_key_ref == LUA_NOREF) {
default_long_press(arg); default_long_press(arg);
return; return;
} }
if(!gL) if (!gL)
return; return;
lua_rawgeti(gL, LUA_REGISTRYINDEX, long_key_ref); lua_rawgeti(gL, LUA_REGISTRYINDEX, long_key_ref);
lua_call(gL, 0, 0); lua_call(gL, 0, 0);
} }
void key_short_press(void *arg){ void key_short_press(void *arg) {
NODE_DBG("key_short_press is called.\n"); NODE_DBG("key_short_press is called.\n");
if(short_key_ref == LUA_NOREF){ if (short_key_ref == LUA_NOREF) {
default_short_press(arg); default_short_press(arg);
return; return;
} }
if(!gL) if (!gL)
return; return;
lua_rawgeti(gL, LUA_REGISTRYINDEX, short_key_ref); lua_rawgeti(gL, LUA_REGISTRYINDEX, short_key_ref);
lua_call(gL, 0, 0); lua_call(gL, 0, 0);
} }
// Lua: key(type, function) // Lua: key(type, function)
...@@ -213,32 +216,32 @@ static int node_key( lua_State* L ) ...@@ -213,32 +216,32 @@ static int node_key( lua_State* L )
{ {
int *ref = NULL; int *ref = NULL;
size_t sl; size_t sl;
const char *str = luaL_checklstring( L, 1, &sl ); const char *str = luaL_checklstring( L, 1, &sl );
if (str == NULL) if (str == NULL)
return luaL_error( L, "wrong arg type" ); return luaL_error( L, "wrong arg type" );
if(sl == 5 && c_strcmp(str, "short") == 0){ if (sl == 5 && c_strcmp(str, "short") == 0) {
ref = &short_key_ref; ref = &short_key_ref;
}else if(sl == 4 && c_strcmp(str, "long") == 0){ } else if (sl == 4 && c_strcmp(str, "long") == 0) {
ref = &long_key_ref; ref = &long_key_ref;
}else{ } else {
ref = &short_key_ref; ref = &short_key_ref;
} }
gL = L; gL = L;
// luaL_checkanyfunction(L, 2); // luaL_checkanyfunction(L, 2);
if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION){ if (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION) {
lua_pushvalue(L, 2); // copy argument (func) to the top of stack lua_pushvalue(L, 2); // copy argument (func) to the top of stack
if(*ref != LUA_NOREF) if (*ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, *ref); luaL_unref(L, LUA_REGISTRYINDEX, *ref);
*ref = luaL_ref(L, LUA_REGISTRYINDEX); *ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else { // unref the key press function } else { // unref the key press function
if(*ref != LUA_NOREF) if (*ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, *ref); luaL_unref(L, LUA_REGISTRYINDEX, *ref);
*ref = LUA_NOREF; *ref = LUA_NOREF;
} }
return 0; return 0;
} }
#endif #endif
...@@ -248,15 +251,15 @@ extern void dojob(lua_Load *load); ...@@ -248,15 +251,15 @@ extern void dojob(lua_Load *load);
// Lua: input("string") // Lua: input("string")
static int node_input( lua_State* L ) static int node_input( lua_State* L )
{ {
size_t l=0; size_t l = 0;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
if (s != NULL && l > 0 && l < LUA_MAXINPUT - 1) if (s != NULL && l > 0 && l < LUA_MAXINPUT - 1)
{ {
lua_Load *load = &gLoad; lua_Load *load = &gLoad;
if(load->line_position == 0){ if (load->line_position == 0) {
c_memcpy(load->line, s, l); c_memcpy(load->line, s, l);
load->line[l+1] = '\0'; load->line[l + 1] = '\0';
load->line_position = c_strlen(load->line)+1; load->line_position = c_strlen(load->line) + 1;
load->done = 1; load->done = 1;
NODE_DBG("Get command:\n"); NODE_DBG("Get command:\n");
NODE_DBG(load->line); // buggy here NODE_DBG(load->line); // buggy here
...@@ -271,18 +274,18 @@ static int node_input( lua_State* L ) ...@@ -271,18 +274,18 @@ static int node_input( lua_State* L )
static int output_redir_ref = LUA_NOREF; static int output_redir_ref = LUA_NOREF;
static int serial_debug = 1; static int serial_debug = 1;
void output_redirect(const char *str){ void output_redirect(const char *str) {
// if(c_strlen(str)>=TX_BUFF_SIZE){ // if(c_strlen(str)>=TX_BUFF_SIZE){
// NODE_ERR("output too long.\n"); // NODE_ERR("output too long.\n");
// return; // return;
// } // }
if(output_redir_ref == LUA_NOREF || !gL){ if (output_redir_ref == LUA_NOREF || !gL) {
uart0_sendStr(str); uart0_sendStr(str);
return; return;
} }
if(serial_debug!=0){ if (serial_debug != 0) {
uart0_sendStr(str); uart0_sendStr(str);
} }
...@@ -296,15 +299,15 @@ static int node_output( lua_State* L ) ...@@ -296,15 +299,15 @@ static int node_output( lua_State* L )
{ {
gL = L; gL = L;
// luaL_checkanyfunction(L, 1); // luaL_checkanyfunction(L, 1);
if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION){ 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 lua_pushvalue(L, 1); // copy argument (func) to the top of stack
if(output_redir_ref != LUA_NOREF) if (output_redir_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref); luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref);
output_redir_ref = luaL_ref(L, LUA_REGISTRYINDEX); output_redir_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else { // unref the key press function } else { // unref the key press function
if(output_redir_ref != LUA_NOREF) if (output_redir_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref); luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref);
output_redir_ref = LUA_NOREF; output_redir_ref = LUA_NOREF;
serial_debug = 1; serial_debug = 1;
return 0; return 0;
} }
...@@ -312,26 +315,26 @@ static int node_output( lua_State* L ) ...@@ -312,26 +315,26 @@ static int node_output( lua_State* L )
if ( lua_isnumber(L, 2) ) if ( lua_isnumber(L, 2) )
{ {
serial_debug = lua_tointeger(L, 2); serial_debug = lua_tointeger(L, 2);
if(serial_debug!=0) if (serial_debug != 0)
serial_debug = 1; serial_debug = 1;
} else { } else {
serial_debug = 1; // default to 1 serial_debug = 1; // default to 1
} }
return 0; return 0;
} }
static int writer(lua_State* L, const void* p, size_t size, void* u) static int writer(lua_State* L, const void* p, size_t size, void* u)
{ {
UNUSED(L); UNUSED(L);
int file_fd = *( (int *)u ); int file_fd = *( (int *)u );
if((FS_OPEN_OK - 1)==file_fd) if ((FS_OPEN_OK - 1) == file_fd)
return 1; return 1;
NODE_DBG("get fd:%d,size:%d\n",file_fd,size); NODE_DBG("get fd:%d,size:%d\n", file_fd, size);
if(size!=0 && (size!=fs_write(file_fd, (const char *)p, size)) ) if (size != 0 && (size != fs_write(file_fd, (const char *)p, size)) )
return 1; return 1;
NODE_DBG("write fd:%d,size:%d\n",file_fd,size); NODE_DBG("write fd:%d,size:%d\n", file_fd, size);
return 0; return 0;
} }
...@@ -343,45 +346,45 @@ static int node_compile( lua_State* L ) ...@@ -343,45 +346,45 @@ static int node_compile( lua_State* L )
int file_fd = FS_OPEN_OK - 1; int file_fd = FS_OPEN_OK - 1;
size_t len; size_t len;
const char *fname = luaL_checklstring( L, 1, &len ); const char *fname = luaL_checklstring( L, 1, &len );
if( len > FS_NAME_MAX_LENGTH ) if ( len > FS_NAME_MAX_LENGTH )
return luaL_error(L, "filename too long"); return luaL_error(L, "filename too long");
char output[FS_NAME_MAX_LENGTH]; char output[FS_NAME_MAX_LENGTH];
c_strcpy(output, fname); c_strcpy(output, fname);
// check here that filename end with ".lua". // check here that filename end with ".lua".
if(len<4 || (c_strcmp( output+len-4,".lua")!=0) ) if (len < 4 || (c_strcmp( output + len - 4, ".lua") != 0) )
return luaL_error(L, "not a .lua file"); return luaL_error(L, "not a .lua file");
output[c_strlen(output)-2] = 'c'; output[c_strlen(output) - 2] = 'c';
output[c_strlen(output)-1] = '\0'; output[c_strlen(output) - 1] = '\0';
NODE_DBG(output); NODE_DBG(output);
NODE_DBG("\n"); NODE_DBG("\n");
if (luaL_loadfsfile(L,fname)!=0){ if (luaL_loadfsfile(L, fname) != 0) {
return luaL_error(L, lua_tostring(L,-1)); return luaL_error(L, lua_tostring(L, -1));
} }
f = toproto(L,-1); f = toproto(L, -1);
int stripping = 1; /* strip debug information? */ int stripping = 1; /* strip debug information? */
file_fd = fs_open(output, fs_mode2flag("w+")); file_fd = fs_open(output, fs_mode2flag("w+"));
if(file_fd < FS_OPEN_OK) if (file_fd < FS_OPEN_OK)
{ {
return luaL_error(L, "cannot open/write to file"); return luaL_error(L, "cannot open/write to file");
} }
lua_lock(L); lua_lock(L);
int result=luaU_dump(L,f,writer,&file_fd,stripping); int result = luaU_dump(L, f, writer, &file_fd, stripping);
lua_unlock(L); lua_unlock(L);
fs_flush(file_fd); fs_flush(file_fd);
fs_close(file_fd); fs_close(file_fd);
file_fd = FS_OPEN_OK - 1; file_fd = FS_OPEN_OK - 1;
if (result==LUA_ERR_CC_INTOVERFLOW){ if (result == LUA_ERR_CC_INTOVERFLOW) {
return luaL_error(L, "value too big or small for target integer type"); return luaL_error(L, "value too big or small for target integer type");
} }
if (result==LUA_ERR_CC_NOTINTEGER){ if (result == LUA_ERR_CC_NOTINTEGER) {
return luaL_error(L, "target lua_Number is integral but fractional value found"); return luaL_error(L, "target lua_Number is integral but fractional value found");
} }
...@@ -391,7 +394,7 @@ static int node_compile( lua_State* L ) ...@@ -391,7 +394,7 @@ static int node_compile( lua_State* L )
// Module function map // Module function map
#define MIN_OPT_LEVEL 2 #define MIN_OPT_LEVEL 2
#include "lrodefs.h" #include "lrodefs.h"
const LUA_REG_TYPE node_map[] = const LUA_REG_TYPE node_map[] =
{ {
{ LSTRKEY( "restart" ), LFUNCVAL( node_restart ) }, { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) },
{ LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) }, { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) },
...@@ -408,7 +411,7 @@ const LUA_REG_TYPE node_map[] = ...@@ -408,7 +411,7 @@ const LUA_REG_TYPE node_map[] =
{ LSTRKEY( "output" ), LFUNCVAL( node_output ) }, { LSTRKEY( "output" ), LFUNCVAL( node_output ) },
{ LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) }, { LSTRKEY( "readvdd33" ), LFUNCVAL( node_readvdd33) },
{ LSTRKEY( "compile" ), LFUNCVAL( node_compile) }, { LSTRKEY( "compile" ), LFUNCVAL( node_compile) },
// Combined to dsleep(us, option) // Combined to dsleep(us, option)
// { LSTRKEY( "dsleepsetoption" ), LFUNCVAL( node_deepsleep_setoption) }, // { LSTRKEY( "dsleepsetoption" ), LFUNCVAL( node_deepsleep_setoption) },
#if LUA_OPTIMIZE_MEMORY > 0 #if LUA_OPTIMIZE_MEMORY > 0
......
...@@ -30,7 +30,11 @@ ...@@ -30,7 +30,11 @@
#elif defined(FLASH_16M) #elif defined(FLASH_16M)
#define FLASH_SEC_NUM 0x1000 #define FLASH_SEC_NUM 0x1000
#elif defined(FLASH_AUTOSIZE) #elif defined(FLASH_AUTOSIZE)
#define FLASH_SEC_NUM (flash_get_sec_num()) #if defined(FLASH_SAFE_API)
#define FLASH_SEC_NUM (flash_safe_get_sec_num())
#else
#define FLASH_SEC_NUM (flash_rom_get_sec_num())
#endif // defined(FLASH_SAFE_API)
#else #else
#define FLASH_SEC_NUM 0x80 #define FLASH_SEC_NUM 0x80
#endif #endif
...@@ -54,8 +58,14 @@ ...@@ -54,8 +58,14 @@
// SpiFlashOpResult spi_flash_erase_sector(uint16 sec); // SpiFlashOpResult spi_flash_erase_sector(uint16 sec);
// SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size); // SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size);
// SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size); // SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size);
#if defined(FLASH_SAFE_API)
#define flash_write flash_safe_write
#define flash_erase flash_safe_erase_sector
#define flash_read flash_safe_read
#else
#define flash_write spi_flash_write #define flash_write spi_flash_write
#define flash_erase spi_flash_erase_sector #define flash_erase spi_flash_erase_sector
#define flash_read spi_flash_read #define flash_read spi_flash_read
#endif // defined(FLASH_SAFE_API)
#endif // #ifndef __CPU_ESP8266_H__ #endif // #ifndef __CPU_ESP8266_H__
...@@ -20,77 +20,154 @@ static volatile const uint8_t flash_init_data[128] ICACHE_STORE_ATTR ICACHE_RODA ...@@ -20,77 +20,154 @@ static volatile const uint8_t flash_init_data[128] ICACHE_STORE_ATTR ICACHE_RODA
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
SPIFlashInfo flash_get_info(void) uint32_t flash_detect_size_byte(void)
{
#define FLASH_BUFFER_SIZE_DETECT 32
uint32_t dummy_size = FLASH_SIZE_256KBYTE;
uint8_t data_orig[FLASH_BUFFER_SIZE_DETECT] ICACHE_STORE_ATTR = {0};
uint8_t data_new[FLASH_BUFFER_SIZE_DETECT] ICACHE_STORE_ATTR = {0};
if (SPI_FLASH_RESULT_OK == flash_safe_read(0, (uint32 *)data_orig, FLASH_BUFFER_SIZE_DETECT))
{
dummy_size = FLASH_SIZE_256KBYTE;
while ((dummy_size < FLASH_SIZE_16MBYTE) &&
(SPI_FLASH_RESULT_OK == flash_safe_read(dummy_size, (uint32 *)data_new, FLASH_BUFFER_SIZE_DETECT)) &&
(0 != os_memcmp(data_orig, data_new, FLASH_BUFFER_SIZE_DETECT))
)
{
dummy_size *= 2;
}
};
return dummy_size;
#undef FLASH_BUFFER_SIZE_DETECT
}
uint32_t flash_safe_get_size_byte(void)
{
static uint32_t flash_size = 0;
if (flash_size == 0)
{
flash_size = flash_detect_size_byte();
}
return flash_size;
}
uint16_t flash_safe_get_sec_num(void)
{
return (flash_safe_get_size_byte() / (SPI_FLASH_SEC_SIZE));
}
SpiFlashOpResult flash_safe_read(uint32 src_addr, uint32 *des_addr, uint32 size)
{
SpiFlashOpResult result = SPI_FLASH_RESULT_ERR;
FLASH_SAFEMODE_ENTER();
result = spi_flash_read(src_addr, (uint32 *) des_addr, size);
FLASH_SAFEMODE_LEAVE();
return result;
}
SpiFlashOpResult flash_safe_write(uint32 des_addr, uint32 *src_addr, uint32 size)
{
SpiFlashOpResult result = SPI_FLASH_RESULT_ERR;
FLASH_SAFEMODE_ENTER();
result = spi_flash_write(des_addr, src_addr, size);
FLASH_SAFEMODE_LEAVE();
return result;
}
SpiFlashOpResult flash_safe_erase_sector(uint16 sec)
{
SpiFlashOpResult result = SPI_FLASH_RESULT_ERR;
FLASH_SAFEMODE_ENTER();
result = spi_flash_erase_sector(sec);
FLASH_SAFEMODE_LEAVE();
return result;
}
SPIFlashInfo flash_rom_getinfo(void)
{ {
volatile SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR; volatile SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR;
spi_flash_info = *((SPIFlashInfo *)(FLASH_MAP_START_ADDRESS)); // Don't use it before cache read disabled
// spi_flash_read(0, (uint32 *)(& spi_flash_info), sizeof(spi_flash_info)); // FLASH_DISABLE_CACHE();
// spi_flash_info = *((SPIFlashInfo *)(FLASH_ADDRESS_START_MAP));
// FLASH_ENABLE_CACHE();
// Needn't safe mode.
spi_flash_read(0, (uint32 *)(& spi_flash_info), sizeof(spi_flash_info));
return spi_flash_info; return spi_flash_info;
} }
uint8_t flash_get_size(void) uint8_t flash_rom_get_size_type(void)
{ {
return flash_get_info().size; return flash_rom_getinfo().size;
} }
uint32_t flash_get_size_byte(void) uint32_t flash_rom_get_size_byte(void)
{ {
uint32_t flash_size = 0; static uint32_t flash_size = 0;
switch (flash_get_info().size) if (flash_size == 0)
{ {
case SIZE_2MBIT: switch (flash_rom_getinfo().size)
// 2Mbit, 256kByte {
flash_size = 256 * 1024; case SIZE_2MBIT:
break; // 2Mbit, 256kByte
case SIZE_4MBIT: flash_size = 256 * 1024;
// 4Mbit, 512kByte break;
flash_size = 512 * 1024; case SIZE_4MBIT:
break; // 4Mbit, 512kByte
case SIZE_8MBIT: flash_size = 512 * 1024;
// 8Mbit, 1MByte break;
flash_size = 1 * 1024 * 1024; case SIZE_8MBIT:
break; // 8Mbit, 1MByte
case SIZE_16MBIT: flash_size = 1 * 1024 * 1024;
// 16Mbit, 2MByte break;
flash_size = 2 * 1024 * 1024; case SIZE_16MBIT:
break; // 16Mbit, 2MByte
case SIZE_32MBIT: flash_size = 2 * 1024 * 1024;
// 32Mbit, 4MByte break;
flash_size = 4 * 1024 * 1024; case SIZE_32MBIT:
break; // 32Mbit, 4MByte
case SIZE_64MBIT: flash_size = 4 * 1024 * 1024;
// 64Mbit, 8MByte break;
flash_size = 8 * 1024 * 1024; case SIZE_64MBIT:
break; // 64Mbit, 8MByte
case SIZE_128MBIT: flash_size = 8 * 1024 * 1024;
// 128Mbit, 16MByte break;
flash_size = 16 * 1024 * 1024; case SIZE_128MBIT:
break; // 128Mbit, 16MByte
default: flash_size = 16 * 1024 * 1024;
// Unknown flash size, fall back mode. break;
flash_size = 512 * 1024; default:
break; // Unknown flash size, fall back mode.
flash_size = 512 * 1024;
break;
}
} }
return flash_size; return flash_size;
} }
bool flash_set_size(uint8_t size) bool flash_rom_set_size_type(uint8_t size)
{ {
// Dangerous, here are dinosaur infested!!!!! // Dangerous, here are dinosaur infested!!!!!
// Reboot required!!! // Reboot required!!!
// If you don't know what you're doing, your nodemcu may turn into stone ... // If you don't know what you're doing, your nodemcu may turn into stone ...
NODE_DBG("\nBEGIN SET FLASH HEADER\n");
uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR; uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;
spi_flash_read(0, (uint32 *)data, sizeof(data)); if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
SPIFlashInfo *p_spi_flash_info = (SPIFlashInfo *)(data); {
p_spi_flash_info->size = size; ((SPIFlashInfo *)(&data[0]))->size = size;
spi_flash_erase_sector(0); if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
spi_flash_write(0, (uint32 *)data, sizeof(data)); {
//p_spi_flash_info = flash_get_info(); NODE_DBG("\nERASE SUCCESS\n");
//p_spi_flash_info->size = size; }
if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nWRITE SUCCESS, %u\n", size);
}
}
NODE_DBG("\nEND SET FLASH HEADER\n");
return true; return true;
} }
bool flash_set_size_byte(uint32_t size) bool flash_rom_set_size_byte(uint32_t size)
{ {
// Dangerous, here are dinosaur infested!!!!! // Dangerous, here are dinosaur infested!!!!!
// Reboot required!!! // Reboot required!!!
...@@ -102,27 +179,37 @@ bool flash_set_size_byte(uint32_t size) ...@@ -102,27 +179,37 @@ bool flash_set_size_byte(uint32_t size)
case 256 * 1024: case 256 * 1024:
// 2Mbit, 256kByte // 2Mbit, 256kByte
flash_size = SIZE_2MBIT; flash_size = SIZE_2MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 512 * 1024: case 512 * 1024:
// 4Mbit, 512kByte // 4Mbit, 512kByte
flash_size = SIZE_4MBIT; flash_size = SIZE_4MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 1 * 1024 * 1024: case 1 * 1024 * 1024:
// 8Mbit, 1MByte // 8Mbit, 1MByte
flash_size = SIZE_8MBIT; flash_size = SIZE_8MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 2 * 1024 * 1024: case 2 * 1024 * 1024:
// 16Mbit, 2MByte // 16Mbit, 2MByte
flash_size = SIZE_16MBIT; flash_size = SIZE_16MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break; break;
case 4 * 1024 * 1024: case 4 * 1024 * 1024:
// 32Mbit, 4MByte // 32Mbit, 4MByte
flash_size = SIZE_32MBIT; flash_size = SIZE_32MBIT;
flash_set_size(flash_size); flash_rom_set_size_type(flash_size);
break;
case 8 * 1024 * 1024:
// 64Mbit, 8MByte
flash_size = SIZE_64MBIT;
flash_rom_set_size_type(flash_size);
break;
case 16 * 1024 * 1024:
// 128Mbit, 16MByte
flash_size = SIZE_128MBIT;
flash_rom_set_size_type(flash_size);
break; break;
default: default:
// Unknown flash size. // Unknown flash size.
...@@ -132,22 +219,22 @@ bool flash_set_size_byte(uint32_t size) ...@@ -132,22 +219,22 @@ bool flash_set_size_byte(uint32_t size)
return result; return result;
} }
uint16_t flash_get_sec_num(void) uint16_t flash_rom_get_sec_num(void)
{ {
//static uint16_t sec_num = 0; //static uint16_t sec_num = 0;
// return flash_get_size_byte() / (SPI_FLASH_SEC_SIZE); // return flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE);
// c_printf("\nflash_get_size_byte()=%d\n", ( flash_get_size_byte() / (SPI_FLASH_SEC_SIZE) )); // c_printf("\nflash_rom_get_size_byte()=%d\n", ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) ));
// if( sec_num == 0 ) // if( sec_num == 0 )
//{ //{
// sec_num = 4 * 1024 * 1024 / (SPI_FLASH_SEC_SIZE); // sec_num = 4 * 1024 * 1024 / (SPI_FLASH_SEC_SIZE);
//} //}
//return sec_num; //return sec_num;
return ( flash_get_size_byte() / (SPI_FLASH_SEC_SIZE) ); return ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) );
} }
uint8_t flash_get_mode(void) uint8_t flash_rom_get_mode(void)
{ {
SPIFlashInfo spi_flash_info = flash_get_info(); SPIFlashInfo spi_flash_info = flash_rom_getinfo();
switch (spi_flash_info.mode) switch (spi_flash_info.mode)
{ {
// Reserved for future use // Reserved for future use
...@@ -163,10 +250,10 @@ uint8_t flash_get_mode(void) ...@@ -163,10 +250,10 @@ uint8_t flash_get_mode(void)
return spi_flash_info.mode; return spi_flash_info.mode;
} }
uint32_t flash_get_speed(void) uint32_t flash_rom_get_speed(void)
{ {
uint32_t speed = 0; uint32_t speed = 0;
SPIFlashInfo spi_flash_info = flash_get_info(); SPIFlashInfo spi_flash_info = flash_rom_getinfo();
switch (spi_flash_info.speed) switch (spi_flash_info.speed)
{ {
case SPEED_40MHZ: case SPEED_40MHZ:
...@@ -189,11 +276,55 @@ uint32_t flash_get_speed(void) ...@@ -189,11 +276,55 @@ uint32_t flash_get_speed(void)
return speed; return speed;
} }
bool flash_rom_set_speed(uint32_t speed)
{
// Dangerous, here are dinosaur infested!!!!!
// Reboot required!!!
// If you don't know what you're doing, your nodemcu may turn into stone ...
NODE_DBG("\nBEGIN SET FLASH HEADER\n");
uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;
uint8_t speed_type = SPEED_40MHZ;
if (speed < 26700000)
{
speed_type = SPEED_20MHZ;
}
else if (speed < 40000000)
{
speed_type = SPEED_26MHZ;
}
else if (speed < 80000000)
{
speed_type = SPEED_40MHZ;
}
else if (speed >= 80000000)
{
speed_type = SPEED_80MHZ;
}
if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
((SPIFlashInfo *)(&data[0]))->speed = speed_type;
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nERASE SUCCESS\n");
}
if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{
NODE_DBG("\nWRITE SUCCESS, %u\n", speed_type);
}
}
NODE_DBG("\nEND SET FLASH HEADER\n");
return true;
}
bool flash_init_data_written(void) bool flash_init_data_written(void)
{ {
// FLASH SEC - 4 // FLASH SEC - 4
uint32_t data[2] ICACHE_STORE_ATTR; uint32_t data[2] ICACHE_STORE_ATTR;
if (SPI_FLASH_RESULT_OK == spi_flash_read((flash_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data))) #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)))
#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)
{ {
if (data[0] == 0xFFFFFFFF && data[1] == 0xFFFFFFFF) if (data[0] == 0xFFFFFFFF && data[1] == 0xFFFFFFFF)
{ {
...@@ -210,13 +341,23 @@ bool flash_init_data_default(void) ...@@ -210,13 +341,23 @@ bool flash_init_data_default(void)
// Reboot required!!! // Reboot required!!!
// It will init system data to default! // It will init system data to default!
bool result = false; bool result = false;
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 4))) #if defined(FLASH_SAFE_API)
if (SPI_FLASH_RESULT_OK == flash_safe_erase_sector((flash_safe_get_sec_num() - 4)))
{
if (SPI_FLASH_RESULT_OK == flash_safe_write((flash_safe_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)flash_init_data, 128))
{
result = true;
}
}
#else
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_rom_get_sec_num() - 4)))
{ {
if (SPI_FLASH_RESULT_OK == spi_flash_write((flash_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)flash_init_data, 128)) if (SPI_FLASH_RESULT_OK == spi_flash_write((flash_rom_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)flash_init_data, 128))
{ {
result = true; result = true;
} }
} }
#endif // defined(FLASH_SAFE_API)
return result; return result;
} }
...@@ -227,8 +368,13 @@ bool flash_init_data_blank(void) ...@@ -227,8 +368,13 @@ bool flash_init_data_blank(void)
// Reboot required!!! // Reboot required!!!
// It will init system config to blank! // It will init system config to blank!
bool result = false; bool result = false;
if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 2))) && #if defined(FLASH_SAFE_API)
(SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 1)))) 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))))
#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))))
#endif // defined(FLASH_SAFE_API)
{ {
result = true; result = true;
} }
...@@ -254,3 +400,28 @@ uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index) ...@@ -254,3 +400,28 @@ uint8_t byte_of_aligned_array(const uint8_t *aligned_array, uint32_t index)
uint8_t *p = (uint8_t *) (&v); uint8_t *p = (uint8_t *) (&v);
return p[ (index % 4) ]; return p[ (index % 4) ];
} }
// uint8_t flash_rom_get_checksum(void)
// {
// // SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR = flash_rom_getinfo();
// // uint32_t address = sizeof(spi_flash_info) + spi_flash_info.segment_size;
// // uint32_t address_aligned_4bytes = (address + 3) & 0xFFFFFFFC;
// // uint8_t buffer[64] = {0};
// // spi_flash_read(address, (uint32 *) buffer, 64);
// // uint8_t i = 0;
// // c_printf("\nBEGIN DUMP\n");
// // for (i = 0; i < 64; i++)
// // {
// // c_printf("%02x," , buffer[i]);
// // }
// // i = (address + 0x10) & 0x10 - 1;
// // c_printf("\nSIZE:%d CHECK SUM:%02x\n", spi_flash_info.segment_size, buffer[i]);
// // c_printf("\nEND DUMP\n");
// // return buffer[0];
// return 0;
// }
// uint8_t flash_rom_calc_checksum(void)
// {
// return 0;
// }
\ No newline at end of file
...@@ -4,34 +4,61 @@ ...@@ -4,34 +4,61 @@
#include "user_config.h" #include "user_config.h"
#include "cpu_esp8266.h" #include "cpu_esp8266.h"
#define FLASH_MAP_START_ADDRESS (INTERNAL_FLASH_START_ADDRESS) #define FLASH_ADDRESS_START_MAP (INTERNAL_FLASH_START_ADDRESS)
#define FLASH_SIZE_2MBIT (2 * 1024 * 1024)
#define FLASH_SIZE_4MBIT (4 * 1024 * 1024)
#define FLASH_SIZE_8MBIT (8 * 1024 * 1024)
#define FLASH_SIZE_16MBIT (16 * 1024 * 1024)
#define FLASH_SIZE_32MBIT (32 * 1024 * 1024)
#define FLASH_SIZE_64MBIT (64 * 1024 * 1024)
#define FLASH_SIZE_128MBIT (128 * 1024 * 1024)
#define FLASH_SIZE_256KBYTE (FLASH_SIZE_2MBIT / 8)
#define FLASH_SIZE_512KBYTE (FLASH_SIZE_4MBIT / 8)
#define FLASH_SIZE_1MBYTE (FLASH_SIZE_8MBIT / 8)
#define FLASH_SIZE_2MBYTE (FLASH_SIZE_16MBIT / 8)
#define FLASH_SIZE_4MBYTE (FLASH_SIZE_32MBIT / 8)
#define FLASH_SIZE_8MBYTE (FLASH_SIZE_64MBIT / 8)
#define FLASH_SIZE_16MBYTE (FLASH_SIZE_128MBIT/ 8)
#define FLASH_SAFEMODE_ENTER() \
do { \
extern SpiFlashChip * flashchip; \
flashchip->chip_size = FLASH_SIZE_16MBYTE
#define FLASH_SAFEMODE_LEAVE() \
flashchip->chip_size = flash_rom_get_size_byte(); \
} while(0)
/****************************************************************************** /******************************************************************************
* ROM Function definition * ROM Function definition
* Note: It is unsafe to use ROM function, but it may efficient. * Note: It is unsafe to use ROM function, but it may efficient.
* SPIEraseSector * SPIEraseSector
* unknown SPIEraseSector(uint16 sec); * SpiFlashOpResult SPIEraseSector(uint16 sec);
* The 1st parameter is flash sector number. * The 1st parameter is flash sector number.
* Note: Must disable cache read before using it.
* SPIRead (Unsafe) * SPIRead
* unknown SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size); * SpiFlashOpResult SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size);
* The 1st parameter is source addresses. * The 1st parameter is source addresses.
* The 2nd parameter is destination addresses. * The 2nd parameter is destination addresses.
* The 3rd parameter is size. * The 3rd parameter is size.
* Note: Sometimes it have no effect, may be need a delay or other option(lock or unlock, etc.) with known reason. * Note: Must disable cache read before using it.
* SPIWrite (Unsafe) * SPIWrite
* unknown SPIWrite(uint32_t des_addr, uint32_t *src_addr, uint32_t size); * SpiFlashOpResult SPIWrite(uint32_t des_addr, uint32_t *src_addr, uint32_t size);
* The 1st parameter is destination addresses. * The 1st parameter is destination addresses.
* The 2nd parameter is source addresses. * The 2nd parameter is source addresses.
* The 3rd parameter is size. * The 3rd parameter is size.
* Note: Sometimes it have no effect, may be need a delay or other option(lock or unlock, etc.) with known reason. * Note: Must disable cache read before using it.
*******************************************************************************/ *******************************************************************************/
typedef struct typedef struct
{ {
uint8_t unknown0; uint8_t header_magic;
uint8_t unknown1; uint8_t segment_count;
enum enum
{ {
MODE_QIO = 0, MODE_QIO = 0,
...@@ -56,20 +83,31 @@ typedef struct ...@@ -56,20 +83,31 @@ typedef struct
SIZE_64MBIT = 5, SIZE_64MBIT = 5,
SIZE_128MBIT = 6, SIZE_128MBIT = 6,
} size : 4; } size : 4;
uint32_t entry_point;
uint32_t memory_offset;
uint32_t segment_size;
} ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo; } ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo;
SPIFlashInfo flash_get_info(void); uint32_t flash_detect_size_byte(void);
uint8_t flash_get_size(void); uint32_t flash_safe_get_size_byte(void);
uint32_t flash_get_size_byte(void); uint16_t flash_safe_get_sec_num(void);
bool flash_set_size(uint8_t); SpiFlashOpResult flash_safe_read(uint32 src_addr, uint32 *des_addr, uint32 size);
bool flash_set_size_byte(uint32_t); SpiFlashOpResult flash_safe_write(uint32 des_addr, uint32 *src_addr, uint32 size);
uint16_t flash_get_sec_num(void); SpiFlashOpResult flash_safe_erase_sector(uint16 sec);
uint8_t flash_get_mode(void); SPIFlashInfo flash_rom_getinfo(void);
uint32_t flash_get_speed(void); uint8_t flash_rom_get_size_type(void);
uint32_t flash_rom_get_size_byte(void);
bool flash_rom_set_size_type(uint8_t);
bool flash_rom_set_size_byte(uint32_t);
uint16_t flash_rom_get_sec_num(void);
uint8_t flash_rom_get_mode(void);
uint32_t flash_rom_get_speed(void);
bool flash_init_data_written(void); bool flash_init_data_written(void);
bool flash_init_data_default(void); bool flash_init_data_default(void);
bool flash_init_data_blank(void); bool flash_init_data_blank(void);
bool flash_self_destruct(void); bool flash_self_destruct(void);
uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index); uint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index);
// uint8_t flash_rom_get_checksum(void);
// uint8_t flash_rom_calc_checksum(void);
#endif // __FLASH_API_H__ #endif // __FLASH_API_H__
...@@ -60,7 +60,19 @@ void nodemcu_init(void) ...@@ -60,7 +60,19 @@ void nodemcu_init(void)
NODE_DBG("Can not init platform for modules.\n"); NODE_DBG("Can not init platform for modules.\n");
return; return;
} }
#if defined(FLASH_SAFE_API)
if( flash_safe_get_size_byte() != flash_rom_get_size_byte()) {
NODE_ERR("Self adjust flash size.\n");
// Fit hardware real flash size.
flash_rom_set_size_byte(flash_safe_get_size_byte());
// Flash init data at FLASHSIZE - 0x04000 Byte.
flash_init_data_default();
// Flash blank data at FLASHSIZE - 0x02000 Byte.
flash_init_data_blank();
}
#endif // defined(FLASH_SAFE_API)
if( !flash_init_data_written() ){ if( !flash_init_data_written() ){
NODE_ERR("Restore init data.\n"); NODE_ERR("Restore init data.\n");
// Flash init data at FLASHSIZE - 0x04000 Byte. // Flash init data at FLASHSIZE - 0x04000 Byte.
......
---
-- Working Example: https://www.youtube.com/watch?v=PDxTR_KJLhc
-- @author Miguel (AllAboutEE.com)
-- @description This example will read the first email in your inbox using IMAP and
-- display it through serial. The email server must provided unecrypted access. The code
-- was tested with an AOL and Time Warner cable email accounts (GMail and other services who do
-- not support no SSL access will not work).
require("imap")
local IMAP_USERNAME = "email@domain.com"
local IMAP_PASSWORD = "password"
-- find out your unencrypted imap server and port
-- from your email provided i.e. google "[my email service] imap settings" for example
local IMAP_SERVER = "imap.service.com"
local IMAP_PORT = "143"
local IMAP_TAG = "t1" -- You do not need to change this
local IMAP_DEBUG = true -- change to true if you would like to see the entire conversation between
-- the ESP8266 and IMAP server
local SSID = "ssid"
local SSID_PASSWORD = "password"
local count = 0 -- we will send several IMAP commands/requests, this variable helps keep track of which one to send
-- configure the ESP8266 as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)
-- create an unencrypted connection
local imap_socket = net.createConnection(net.TCP,0)
---
-- @name setup
-- @description A call back function used to begin reading email
-- upon sucessfull connection to the IMAP server
function setup(sck)
-- Set the email user name and password, IMAP tag, and if debugging output is needed
imap.config(IMAP_USERNAME,
IMAP_PASSWORD,
IMAP_TAG,
IMAP_DEBUG)
imap.login(sck)
end
imap_socket:on("connection",setup) -- call setup() upon connection
imap_socket:connect(IMAP_PORT,IMAP_SERVER) -- connect to the IMAP server
local subject = ""
local from = ""
local message = ""
---
-- @name do_next
-- @description A call back function for a timer alarm used to check if the previous
-- IMAP command reply has been processed. If the IMAP reply has been processed
-- this function will call the next IMAP command function necessary to read the email
function do_next()
-- Check if the IMAP reply was processed
if(imap.response_processed() == true) then
-- The IMAP reply was processed
if (count == 0) then
-- After logging in we need to select the email folder from which we wish to read
-- in this case the INBOX folder
imap.examine(imap_socket,"INBOX")
count = count + 1
elseif (count == 1) then
-- After examining/selecting the INBOX folder we can begin to retrieve emails.
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"SUBJECT") -- Retrieve the SUBJECT of the first/newest email
count = count + 1
elseif (count == 2) then
subject = imap.get_header() -- store the SUBJECT response in subject
imap.fetch_header(imap_socket,imap.get_most_recent_num(),"FROM") -- Retrieve the FROM of the first/newest email
count = count + 1
elseif (count == 3) then
from = imap.get_header() -- store the FROM response in from
imap.fetch_body_plain_text(imap_socket,imap.get_most_recent_num()) -- Retrieve the BODY of the first/newest email
count = count + 1
elseif (count == 4) then
body = imap.get_body() -- store the BODY response in body
imap.logout(imap_socket) -- Logout of the email account
count = count + 1
else
-- display the email contents
-- create patterns to strip away IMAP protocl text from actual message
pattern1 = "(\*.+\}\r\n)" -- to remove "* n command (BODY[n] {n}"
pattern2 = "(%)\r\n.+)" -- to remove ") t1 OK command completed"
from = string.gsub(from,pattern1,"")
from = string.gsub(from,pattern2,"")
print(from)
subject = string.gsub(subject,pattern1,"")
subject = string.gsub(subject,pattern2,"")
print(subject)
body = string.gsub(body,pattern1,"")
body = string.gsub(body,pattern2,"")
print("Message: " .. body)
tmr.stop(0) -- Stop the timer alarm
imap_socket:close() -- close the IMAP socket
collectgarbage() -- clean up
end
end
end
-- A timer alarm is sued to check if an IMAP reply has been processed
tmr.alarm(0,1000,1, do_next)
---
-- Working Example: https://www.youtube.com/watch?v=CcRbFIJ8aeU
-- @description a basic SMTP email example. You must use an account which can provide unencrypted authenticated access.
-- This example was tested with an AOL and Time Warner email accounts. GMail does not offer unecrypted authenticated access.
-- To obtain your email's SMTP server and port simply Google it e.g. [my email domain] SMTP settings
-- For example for timewarner you'll get to this page http://www.timewarnercable.com/en/support/faqs/faqs-internet/e-mailacco/incoming-outgoing-server-addresses.html
-- To Learn more about SMTP email visit:
-- SMTP Commands Reference - http://www.samlogic.net/articles/smtp-commands-reference.htm
-- See "SMTP transport example" in this page http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol
-- @author Miguel
require("base64")
-- The email and password from the account you want to send emails from
local MY_EMAIL = "esp8266@domain.com"
local EMAIL_PASSWORD = "123456"
-- The SMTP server and port of your email provider.
-- If you don't know it google [my email provider] SMTP settings
local SMTP_SERVER = "smtp.server.com"
local SMTP_PORT = "587"
-- The account you want to send email to
local mail_to = "to_email@domain.com"
-- Your access point's SSID and password
local SSID = "ssid"
local SSID_PASSWORD = "password"
-- configure ESP as a station
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,SSID_PASSWORD)
wifi.sta.autoconnect(1)
-- These are global variables. Don't change their values
-- they will be changed in the functions below
local email_subject = ""
local email_body = ""
local count = 0
local smtp_socket = nil -- will be used as socket to email server
-- The display() function will be used to print the SMTP server's response
function display(sck,response)
print(response)
end
-- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence.
-- I was going to use socket callbacks but the code would not run callbacks after the first 3.
function do_next()
if(count == 0)then
count = count+1
local IP_ADDRESS = wifi.sta.getip()
smtp_socket:send("HELO "..IP_ADDRESS.."\r\n")
elseif(count==1) then
count = count+1
smtp_socket:send("AUTH LOGIN\r\n")
elseif(count == 2) then
count = count + 1
smtp_socket:send(base64.enc(MY_EMAIL).."\r\n")
elseif(count == 3) then
count = count + 1
smtp_socket:send(base64.enc(EMAIL_PASSWORD).."\r\n")
elseif(count==4) then
count = count+1
smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")
elseif(count==5) then
count = count+1
smtp_socket:send("RCPT TO:<" .. mail_to ..">\r\n")
elseif(count==6) then
count = count+1
smtp_socket:send("DATA\r\n")
elseif(count==7) then
count = count+1
local message = string.gsub(
"From: \"".. MY_EMAIL .."\"<"..MY_EMAIL..">\r\n" ..
"To: \"".. mail_to .. "\"<".. mail_to..">\r\n"..
"Subject: ".. email_subject .. "\r\n\r\n" ..
email_body,"\r\n.\r\n","")
smtp_socket:send(message.."\r\n.\r\n")
elseif(count==8) then
count = count+1
tmr.stop(0)
smtp_socket:send("QUIT\r\n")
else
smtp_socket:close()
end
end
-- The connectted() function is executed when the SMTP socket is connected to the SMTP server.
-- This function will create a timer to call the do_next function which will send the SMTP commands
-- in sequence, one by one, every 5000 seconds.
-- You can change the time to be smaller if that works for you, I used 5000ms just because.
function connected(sck)
tmr.alarm(0,5000,1,do_next)
end
-- @name send_email
-- @description Will initiated a socket connection to the SMTP server and trigger the connected() function
-- @param subject The email's subject
-- @param body The email's body
function send_email(subject,body)
count = 0
email_subject = subject
email_body = body
smtp_socket = net.createConnection(net.TCP,0)
smtp_socket:on("connection",connected)
smtp_socket:on("receive",display)
smtp_socket:connect(SMTP_PORT,SMTP_SERVER)
end
-- Send an email
send_email(
"ESP8266",
[[Hi,
How are your IoT projects coming along?
Best Wishes,
ESP8266]])
-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
-- licensed under the terms of the LGPL2
local moduleName = ...
local M = {}
_G[moduleName] = M
-- character table string
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
-- encoding
function M.enc(data)
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end
-- decoding
function M.dec(data)
data = string.gsub(data, '[^'..b..'=]', '')
return (data:gsub('.', function(x)
if (x == '=') then return '' end
local r,f='',(b:find(x)-1)
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
return r;
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
if (#x ~= 8) then return '' end
local c=0
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(7-i) or 0) end
return string.char(c)
end))
end
return M
---
-- Working Example: https://www.youtube.com/watch?v=PDxTR_KJLhc
-- IMPORTANT: run node.compile("imap.lua") after uploading this script
-- to create a compiled module. Then run file.remove("imap.lua")
-- @name imap
-- @description An IMAP 4rev1 module that can be used to read email.
-- Tested on NodeMCU 0.9.5 build 20150213.
-- @date March 12, 2015
-- @author Miguel
-- GitHub: https://github.com/AllAboutEE
-- YouTube: https://www.youtube.com/user/AllAboutEE
-- Website: http://AllAboutEE.com
--
-- Visit the following URLs to learn more about IMAP:
-- "How to test an IMAP server by using telnet" http://www.anta.net/misc/telnet-troubleshooting/imap.shtml
-- "RFC 2060 - Internet Message Access Protocol - Version 4rev1" http://www.faqs.org/rfcs/rfc2060.html
-------------------------------------------------------------------------------------------------------------
local moduleName = ...
local M = {}
_G[moduleName] = M
local USERNAME = ""
local PASSWORD = ""
local SERVER = ""
local PORT = ""
local TAG = ""
local DEBUG = false
local body = "" -- used to store an email's body / main text
local header = "" -- used to store an email's last requested header field e.g. SUBJECT, FROM, DATA etc.
local most_recent_num = 1 -- used to store the latest/newest email number/id
local response_processed = false -- used to know if the last IMAP response has been processed
---
-- @name response_processed
-- @returns The response process status of the last IMAP command sent
function M.response_processed()
return response_processed
end
---
-- @name display
-- @description A generic IMAP response processing function.
-- Can disply the IMAP response if DEBUG is set to true.
-- Sets the reponse processed variable to true when the string "complete"
-- is found in the IMAP reply/response
local function display(socket, response)
-- If debuggins is enabled print the IMAP response
if(DEBUG) then
print(response)
end
-- Some IMAP responses are long enough that they will cause the display
-- function to be called several times. One thing is certain, IMAP will replay with
-- "<tag> OK <command> complete" when it's done sending data back.
if(string.match(response,'complete') ~= nil) then
response_processed = true
end
end
---
-- @name config
-- @description Initiates the IMAP settings
function M.config(username,password,tag,debug)
USERNAME = username
PASSWORD = password
TAG = tag
DEBUG = debug
end
---
-- @name login
-- @descrpiton Logs into a new email session
function M.login(socket)
response_processed = false -- we are sending a new command
-- which means that the response for it has not been processed
socket:send(TAG .. " LOGIN " .. USERNAME .. " " .. PASSWORD .. "\r\n")
socket:on("receive",display)
end
---
-- @name get_most_recent_num
-- @returns The most recent email number. Should only be called after examine()
function M.get_most_recent_num()
return most_recent_num
end
---
-- @name set_most_recent_num
-- @description Gets the most recent email number from the EXAMINE command.
-- i.e. if EXAMINE returns "* 4 EXISTS" this means that there are 4 emails,
-- so the latest/newest will be identified by the number 4
local function set_most_recent_num(socket,response)
if(DEBUG) then
print(response)
end
local _, _, num = string.find(response,"([0-9]+) EXISTS(\.)") -- the _ and _ keep the index of the string found
-- but we don't care about that.
if(num~=nil) then
most_recent_num = num
end
if(string.match(response,'complete') ~= nil) then
response_processed = true
end
end
---
-- @name examine
-- @description IMAP examines the given mailbox/folder. Sends the IMAP EXAMINE command
function M.examine(socket,mailbox)
response_processed = false
socket:send(TAG .. " EXAMINE " .. mailbox .. "\r\n")
socket:on("receive",set_most_recent_num)
end
---
-- @name get_header
-- @returns The last fetched header field
function M.get_header()
return header
end
---
-- @name set_header
-- @description Records the IMAP header field response in a variable
-- so that it may be read later
local function set_header(socket,response)
if(DEBUG) then
print(response)
end
header = header .. response
if(string.match(response,'complete') ~= nil) then
response_processed = true
end
end
---
-- @name fetch_header
-- @description Fetches an emails header field e.g. SUBJECT, FROM, DATE
-- @param socket The IMAP socket to use
-- @param msg_number The email number to read e.g. 1 will read fetch the latest/newest email
-- @param field A header field such as SUBJECT, FROM, or DATE
function M.fetch_header(socket,msg_number,field)
header = "" -- we are getting a new header so clear this variable
response_processed = false
socket:send(TAG .. " FETCH " .. msg_number .. " BODY[HEADER.FIELDS (" .. field .. ")]\r\n")
socket:on("receive",set_header)
end
---
-- @name get_body
-- @return The last email read's body
function M.get_body()
return body
end
---
-- @name set_body
-- @description Records the IMAP body response in a variable
-- so that it may be read later
local function set_body(socket,response)
if(DEBUG) then
print(response)
end
body = body .. response
if(string.match(response,'complete') ~= nil) then
response_processed = true
end
end
---
-- @name fetch_body_plain_text
-- @description Sends the IMAP command to fetch a plain text version of the email's body
-- @param socket The IMAP socket to use
-- @param msg_number The email number to obtain e.g. 1 will obtain the latest email
function M.fetch_body_plain_text(socket,msg_number)
response_processed = false
body = "" -- clear the body variable since we'll be fetching a new email
socket:send(TAG .. " FETCH " .. msg_number .. " BODY[1]\r\n")
socket:on("receive",set_body)
end
---
-- @name logout
-- @description Sends the IMAP command to logout of the email session
function M.logout(socket)
response_processed = false
socket:send(TAG .. " LOGOUT\r\n")
socket:on("receive",display)
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment