Merge pull request #529 from nodemcu/dev096

Dev096 into master.
This commit is contained in:
Vowstar 2015-07-04 04:36:28 +08:00
commit aaca524ce0
26 changed files with 908 additions and 326 deletions

View File

@ -2,7 +2,6 @@ language: cpp
before_install:
- sudo apt-get install -y python-serial srecord
install:
- wget https://github.com/GeorgeHahn/nodemcu-firmware/raw/travis/tools/esp-open-sdk.tar.gz -O tools/esp-open-sdk.tar.gz
- tar -zxvf tools/esp-open-sdk.tar.gz
- export PATH=$PATH:$PWD/esp-open-sdk/sdk:$PWD/esp-open-sdk/xtensa-lx106-elf/bin
script:

View File

@ -36,44 +36,41 @@ Tencent QQ group: 309957875<br />
- cross compiler (done)
# Change log
2015-06-27<br />
fixed ap/station-ap cannot connect to the device.<br />
added wifi.ap.getconfig().<br />
fixed net.dns.getdnsserver().<br />
added new base64 lua example.<br />
added node.bootreason() to inspect boot cause.<br />
optimization of u8g.<br />
# Change log
2015-06-25<br />
move constants to ROM. Frees up 16k+ of RAM.<br />
add dhtlib for DHT11/21/22/33/44, port from Arduino.<br />
add 433MHz transmission.<br />
add crypto library.<br />
re-add ws2812.write().<br />
add wifi.getchannel.<br />
changed wifi_setip() to allow setting SoftAP gateway to 0.0.0.0.<br />
added net.dns.setdnsserver and net.dns.getdnsserver.<br />
add support for lm92 temperature sensor.<br />
implement getStrWidth() and setFontLineSpacingFactor().<br />
add -Os flag to release and debug builds.<br />
changed output format of table that is output by wifi_scan_done.<br />
added ability to set scan configuration to wifi.sta.getap.<br />
added function wifi.sta.getconfig().<br />
allow connecting to unsecured WiFi networks.<br />
add setphymode and getphymode to wifi module.<br />
add multicastJoin and multicastLeave to net module.<br />
add Yeelink Modules.<br />
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.
2015-03-17<br />
add cjson module, only cjson.encode() and cjson.decode() is implemented.<br />
read doc [here](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/cjson/manual.txt)
2015-03-15<br />
bugs fixed: #239, #273.<br />
reduce coap module memory usage, add coap module to default built.
2015-03-11<br />
fix bugs of spiffs.<br />
build both float and integer version [latest releases](https://github.com/nodemcu/nodemcu-firmware/releases/latest).<br />
fix tmr.time().<br />
fix memory leak when DNS fail.
2015-03-10<br />
update to the recent spiffs.<br />
add file.fsinfo() api, usage: remain, used, total = file.fsinfo().<br />
add Travis CI. please download the latest firmware from [releases](https://github.com/nodemcu/nodemcu-firmware/releases).<br />
add math lib, partial api work.<br />
u8g module, ws2812 module default enabled in dev-branch build.
2015-02-13<br />
add node.compile() api to compile lua text file into lua bytecode file.<br />
this will reduce memory usage noticeably when require modules into NodeMCU.<br />
raise internal LUA_BUFFERSIZE from 1024 to 4096.<br />
lua require("mod") will load "mod.lc" file first if exist.<br />
build latest pre_build bin.
[more change log](https://github.com/nodemcu/nodemcu-firmware/wiki)<br />
##GPIO NEW TABLE ( Build 20141219 and later)
@ -145,6 +142,11 @@ build latest pre_build bin.
#define LUA_USE_MODULES_CJSON
#endif /* LUA_USE_MODULES */
```
#Online firmware custom build
For many application, some modules are not used, remove them can free many memory.<br />
Please try Marcel's [NodeMCU custom builds](http://frightanic.com/nodemcu-custom-build) cloud service and you can get your own firmware.<br />
#Flash the firmware
nodemcu_latest.bin: 0x00000<br />
@ -160,6 +162,13 @@ Or, if you build your own bin from source code.<br />
#Connect the hardware in serial
baudrate:9600
#Write Lua script to filesystem
####Esplorer
Victor Brutskiy's [Esplorer](https://github.com/4refr0nt/ESPlorer) support most platforms such as Linux, Windows, Mac OS, etc. This software is opensource and can write lua/lc files to filesystem.
####NodeMCU Studio
[NodeMCU Studio](https://github.com/nodemcu/nodemcu-studio-csharp) is written in C# and support Windows. This software is opensource and can write lua files to filesystem.
#Start play
####Connect to your ap

View File

@ -99,7 +99,7 @@ LINKFLAGS_eagle.app.v6 = \
-nostdlib \
-T$(LD_FILE) \
-Wl,--no-check-sections \
-u call_user_start \
-Wl,--wrap=_xtos_set_exception_handler \
-Wl,-static \
-Wl,--start-group \
-lc \

View File

@ -252,6 +252,8 @@ int dht_readSensor(uint8_t pin, uint8_t wakeupDelay)
DIRECT_WRITE_LOW(pin);
// delay(wakeupDelay);
for (i = 0; i < wakeupDelay; i++) os_delay_us(1000);
// Disable interrupts
os_intr_lock();
// digitalWrite(pin, HIGH); // T-go
DIRECT_WRITE_HIGH(pin);
os_delay_us(40);
@ -303,6 +305,8 @@ int dht_readSensor(uint8_t pin, uint8_t wakeupDelay)
idx++;
}
}
// Enable interrupts
os_intr_unlock();
// pinMode(pin, OUTPUT);
DIRECT_MODE_OUTPUT(pin);
// digitalWrite(pin, HIGH);

View File

@ -37,3 +37,60 @@ extern unsigned char * base64_decode(const unsigned char *src, size_t len, size_
// initialized because it uses mem_malloc
extern void mem_init(void * start_addr);
// 2, 3 = reset (module dependent?), 4 = wdt
int rtc_get_reset_reason (void);
// Hardware exception handling
struct exception_frame
{
uint32_t epc;
uint32_t ps;
uint32_t sar;
uint32_t unused;
union {
struct {
uint32_t a0;
// note: no a1 here!
uint32_t a2;
uint32_t a3;
uint32_t a4;
uint32_t a5;
uint32_t a6;
uint32_t a7;
uint32_t a8;
uint32_t a9;
uint32_t a10;
uint32_t a11;
uint32_t a12;
uint32_t a13;
uint32_t a14;
uint32_t a15;
};
uint32_t a_reg[15];
};
uint32_t cause;
};
/**
* C-level exception handler callback prototype.
*
* Does not need an RFE instruction - it is called through a wrapper which
* performs state capture & restore, as well as the actual RFE.
*
* @param ef An exception frame containing the relevant state from the
* exception triggering. This state may be manipulated and will
* be applied on return.
* @param cause The exception cause number.
*/
typedef void (*exception_handler_fn) (struct exception_frame *ef, uint32_t cause);
/**
* Sets the exception handler function for a particular exception cause.
* @param handler The exception handler to install.
* If NULL, reverts to the XTOS default handler.
* @returns The previous exception handler, or NULL if none existed prior.
*/
exception_handler_fn _xtos_set_exception_handler (uint32_t cause, exception_handler_fn handler);

View File

@ -29,6 +29,7 @@
#define LUA_USE_MODULES_MQTT
#define LUA_USE_MODULES_COAP
#define LUA_USE_MODULES_U8G
#define LUA_USE_MODULES_WS2801
#define LUA_USE_MODULES_WS2812
#define LUA_USE_MODULES_CJSON
#define LUA_USE_MODULES_CRYPTO

View File

@ -7,6 +7,6 @@
#define NODE_VERSION_INTERNAL 0U
#define NODE_VERSION "NodeMCU 0.9.6"
#define BUILD_DATE "build 20150618"
#define BUILD_DATE "build 20150627"
#endif /* __USER_VERSION_H__ */

View File

@ -13,7 +13,7 @@
#include "user_interface.h"
////////////////////////////////////////////////////////////////////////////////////
static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
static uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
static u8_t old_xid[4] = {0};
static const uint8_t magic_cookie[4] = {99, 130, 83, 99};
static struct udp_pcb *pcb_dhcps = NULL;

View File

@ -133,6 +133,14 @@
#define ROM_MODULES_BIT
#endif
#if defined(LUA_USE_MODULES_WS2801)
#define MODULES_WS2801 "ws2801"
#define ROM_MODULES_WS2801 \
_ROM(MODULES_WS2801, luaopen_ws2801, ws2801_map)
#else
#define ROM_MODULES_WS2801
#endif
#if defined(LUA_USE_MODULES_WS2812)
#define MODULES_WS2812 "ws2812"
#define ROM_MODULES_WS2812 \
@ -190,6 +198,7 @@
ROM_MODULES_UART \
ROM_MODULES_OW \
ROM_MODULES_BIT \
ROM_MODULES_WS2801 \
ROM_MODULES_WS2812 \
ROM_MODULES_CJSON \
ROM_MODULES_CRYPTO \

View File

@ -13,6 +13,7 @@
#include "c_types.h"
#include "mem.h"
#include "espconn.h"
#include "lwip/dns.h"
#ifdef CLIENT_SSL_ENABLE
unsigned char *default_certificate;
@ -224,7 +225,9 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
*/
// "enhanced"
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
if(ipaddr == NULL)
{
@ -242,7 +245,7 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
}
// "enhanced" end
lua_call(gL, 1, 0);
lua_call(gL, 2, 0);
end:
if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0)
@ -1445,14 +1448,16 @@ static int net_getdnsserver( lua_State* L )
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);
// ip_addr_t ipaddr;
// dns_getserver(numdns,&ipaddr);
// Bug fix by @md5crypt https://github.com/nodemcu/nodemcu-firmware/pull/500
ip_addr_t ipaddr = dns_getserver(numdns);
if ( ip_addr_isany(&ipaddr) ) {
lua_pushnil( L );
} else {
char temp[20] = {0};
c_sprintf(temp, IPSTR, IP2STR( &ipaddr ) );
c_sprintf(temp, IPSTR, IP2STR( &ipaddr.addr ) );
lua_pushstring( L, temp );
}

View File

@ -414,6 +414,13 @@ static int node_setcpufreq(lua_State* L)
return 1;
}
// Lua: code = bootreason()
static int node_bootreason (lua_State *L)
{
lua_pushnumber (L, rtc_get_reset_reason ());
return 1;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
@ -438,6 +445,7 @@ const LUA_REG_TYPE node_map[] =
{ LSTRKEY( "CPU80MHZ" ), LNUMVAL( CPU80MHZ ) },
{ LSTRKEY( "CPU160MHZ" ), LNUMVAL( CPU160MHZ ) },
{ LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) },
{ LSTRKEY( "bootreason" ), LFUNCVAL( node_bootreason) },
// Combined to dsleep(us, option)
// { LSTRKEY( "dsleepsetoption" ), LFUNCVAL( node_deepsleep_setoption) },
#if LUA_OPTIMIZE_MEMORY > 0

View File

@ -9,13 +9,13 @@
#define defProtocol 1
#define defRepeat 10
#define defBits 24
void transmit(int pin, int pulseLen, int nHighPulses, int nLowPulses) {
static void ICACHE_FLASH_ATTR 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
//rc.send(4,267715,24,185,1,10) --GPIO, code, bits, pulselen, protocol, repeat
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);

478
app/modules/tmr.c Normal file → Executable file
View File

@ -1,232 +1,358 @@
// Module for interfacing with timer
/*guys, srsly, turn on warnings in the makefile*/
#if defined(__GNUC__)
#pragma GCC diagnostic warning "-Wall"
#pragma GCC diagnostic warning "-Wextra"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
/*-------------------------------------
NEW TIMER API
---------------------------------------
tmr.wdclr() -- not changed
tmr.now() -- not changed
tmr.time() -- not changed
tmr.delay() -- not changed
tmr.alarm() -- not changed
tmr.stop() -- changed, see below. use tmr.unregister for old functionality
tmr.register(id, interval, mode, function)
bind function with timer and set the interval in ms
the mode can be:
tmr.ALARM_SINGLE for a single run alarm
tmr.ALARM_SEMI for a multiple single run alarm
tmr.ALARM_AUTO for a repating alarm
tmr.register does NOT start the timer
tmr.alarm is a tmr.register & tmr.start macro
tmr.unregister(id)
stop alarm, unbind function and clean up memory
not needed for ALARM_SINGLE, as it unregisters itself
tmr.start(id)
ret: bool
start a alarm, returns true on success
tmr.stop(id)
ret: bool
stops a alarm, returns true on success
this call dose not free any memory, to do so use tmr.unregister
stopped alarms can be started with start
tmr.interval(id, interval)
set alarm interval, running alarm will be restarted
tmr.state(id)
ret: (bool, int) or nil
returns alarm status (true=started/false=stopped) and mode
nil if timer is unregistered
tmr.softwd(int)
set a negative value to stop the timer
any other value starts the timer, when the
countdown reaches zero, the device restarts
the timer units are seconds
*/
#define MIN_OPT_LEVEL 2
//#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
#include "lrodefs.h"
#include "c_types.h"
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};
#define TIMER_MODE_OFF 3
#define TIMER_MODE_SINGLE 0
#define TIMER_MODE_SEMI 2
#define TIMER_MODE_AUTO 1
#define TIMER_IDLE_FLAG (1<<7)
void alarm_timer_common(lua_State* L, unsigned id){
if(alarm_timer_cb_ref[id] == LUA_NOREF)
//well, the following are my assumptions
//why, oh why is there no good documentation
//chinese companies should learn from Atmel
extern void ets_timer_arm_new(os_timer_t* t, uint32_t milliseconds, uint32_t repeat_flag, uint32_t isMstimer);
extern void ets_timer_disarm(os_timer_t* t);
extern void ets_timer_setfn(os_timer_t* t, os_timer_func_t *f, void *arg);
extern void ets_delay_us(uint32_t us);
extern uint32_t system_get_time();
extern uint32_t platform_tmr_exists(uint32_t t);
extern uint32_t system_rtc_clock_cali_proc();
extern uint32_t system_get_rtc_time();
extern void system_restart();
//in fact lua_State is constant, it's pointless to pass it around
//but hey, whatever, I'll just pass it, still we waste 28B here
typedef struct{
os_timer_t os;
lua_State* L;
sint32_t lua_ref;
uint32_t interval;
uint8_t mode;
}timer_struct_t;
typedef timer_struct_t* timer_t;
//everybody just love unions! riiiiight?
static union {
uint64_t block;
uint32_t part[2];
} rtc_time;
static sint32_t soft_watchdog = -1;
static timer_struct_t alarm_timers[NUM_TMR];
static os_timer_t rtc_timer;
static void alarm_timer_common(void* arg){
timer_t tmr = &alarm_timers[(uint32_t)arg];
if(tmr->lua_ref == LUA_NOREF || tmr->L == NULL)
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_rawgeti(tmr->L, LUA_REGISTRYINDEX, tmr->lua_ref);
//if the timer was set to single run we clean up after it
if(tmr->mode == TIMER_MODE_SINGLE){
luaL_unref(tmr->L, LUA_REGISTRYINDEX, tmr->lua_ref);
tmr->lua_ref = LUA_NOREF;
tmr->mode = TIMER_MODE_OFF;
}else if(tmr->mode == TIMER_MODE_SEMI){
tmr->mode |= TIMER_IDLE_FLAG;
}
lua_call(L, 0, 0);
lua_call(tmr->L, 0, 0);
}
void alarm_timer_cb0(void *arg){
if( !arg )
return;
alarm_timer_common((lua_State*)arg, 0);
}
void alarm_timer_cb1(void *arg){
if( !arg )
return;
alarm_timer_common((lua_State*)arg, 1);
}
void alarm_timer_cb2(void *arg){
if( !arg )
return;
alarm_timer_common((lua_State*)arg, 2);
}
void alarm_timer_cb3(void *arg){
if( !arg )
return;
alarm_timer_common((lua_State*)arg, 3);
}
void alarm_timer_cb4(void *arg){
if( !arg )
return;
alarm_timer_common((lua_State*)arg, 4);
}
void alarm_timer_cb5(void *arg){
if( !arg )
return;
alarm_timer_common((lua_State*)arg, 5);
}
void alarm_timer_cb6(void *arg){
if( !arg )
return;
alarm_timer_common((lua_State*)arg, 6);
}
typedef void (*alarm_timer_callback)(void *arg);
static alarm_timer_callback alarm_timer_cb[NUM_TMR] = {alarm_timer_cb0,alarm_timer_cb1,alarm_timer_cb2,alarm_timer_cb3,alarm_timer_cb4,alarm_timer_cb5,alarm_timer_cb6};
// Lua: delay( us )
static int tmr_delay( lua_State* L )
{
s32 us;
us = luaL_checkinteger( L, 1 );
if ( us <= 0 )
return luaL_error( L, "wrong arg range" );
if(us<1000000)
{
os_delay_us( us );
WRITE_PERI_REG(0x60000914, 0x73);
return 0;
}
unsigned sec = (unsigned)us / 1000000;
unsigned remain = (unsigned)us % 1000000;
int i = 0;
for(i=0;i<sec;i++){
os_delay_us( 1000000 );
// Lua: tmr.delay( us )
static int tmr_delay( lua_State* L ){
sint32_t us = luaL_checkinteger(L, 1);
if(us <= 0)
return luaL_error(L, "wrong arg range");
while(us >= 1000000){
us -= 1000000;
os_delay_us(1000000);
WRITE_PERI_REG(0x60000914, 0x73);
}
if(us>0){
os_delay_us(us);
WRITE_PERI_REG(0x60000914, 0x73);
}
if(remain>0)
os_delay_us( remain );
return 0;
}
// Lua: now() , return system timer in us
static int tmr_now( lua_State* L )
{
unsigned now = 0x7FFFFFFF & system_get_time();
lua_pushinteger( L, now );
// Lua: tmr.now() , return system timer in us
static int tmr_now(lua_State* L){
uint32_t now = 0x7FFFFFFF & system_get_time();
lua_pushinteger(L, now);
return 1;
}
// Lua: alarm( id, interval, repeat, function )
static int tmr_alarm( lua_State* L )
{
s32 interval;
unsigned repeat = 0;
int stack = 1;
unsigned id = luaL_checkinteger( L, stack );
stack++;
MOD_CHECK_ID( tmr, id );
interval = luaL_checkinteger( L, stack );
stack++;
if ( interval <= 0 )
return luaL_error( L, "wrong arg range" );
if ( lua_isnumber(L, stack) ){
repeat = lua_tointeger(L, stack);
stack++;
if ( repeat != 1 && repeat != 0 )
return luaL_error( L, "wrong arg type" );
alarm_timer_repeat[id]=repeat;
}
// luaL_checkanyfunction(L, stack);
if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){
lua_pushvalue(L, stack); // copy argument (func) to the top of stack
if(alarm_timer_cb_ref[id] != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]);
alarm_timer_cb_ref[id] = luaL_ref(L, LUA_REGISTRYINDEX);
}
os_timer_disarm(&(alarm_timer[id]));
os_timer_setfn(&(alarm_timer[id]), (os_timer_func_t *)(alarm_timer_cb[id]), L);
os_timer_arm(&(alarm_timer[id]), interval, repeat);
// Lua: tmr.register( id, interval, mode, function )
static int tmr_register(lua_State* L){
uint32_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr, id);
sint32_t interval = luaL_checkinteger(L, 2);
uint8_t mode = luaL_checkinteger(L, 3);
//validate arguments
uint8_t args_valid = interval <= 0
|| (mode != TIMER_MODE_SINGLE && mode != TIMER_MODE_SEMI && mode != TIMER_MODE_AUTO)
|| (lua_type(L, 4) != LUA_TFUNCTION && lua_type(L, 4) != LUA_TLIGHTFUNCTION);
if(args_valid)
return luaL_error(L, "wrong arg range");
//get the lua function reference
lua_pushvalue(L, 4);
sint32_t ref = luaL_ref(L, LUA_REGISTRYINDEX);
timer_t tmr = &alarm_timers[id];
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
ets_timer_disarm(&tmr->os);
//there was a bug in this part, the second part of the following condition was missing
if(tmr->lua_ref != LUA_NOREF && tmr->lua_ref != ref)
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
tmr->lua_ref = ref;
tmr->mode = mode|TIMER_IDLE_FLAG;
tmr->interval = interval;
tmr->L = L;
ets_timer_setfn(&tmr->os, alarm_timer_common, (void*)id);
return 0;
}
// Lua: stop( id )
static int tmr_stop( lua_State* L )
{
unsigned id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( tmr, id );
// Lua: tmr.start( id )
static int tmr_start(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
//we return false if the timer is not idle
if(!(tmr->mode&TIMER_IDLE_FLAG)){
lua_pushboolean(L, 0);
}else{
tmr->mode &= ~TIMER_IDLE_FLAG;
ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1);
lua_pushboolean(L, 1);
}
return 1;
}
os_timer_disarm(&(alarm_timer[id]));
if(alarm_timer_cb_ref[id] != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]);
// Lua: tmr.alarm( id, interval, repeat, function )
static int tmr_alarm(lua_State* L){
tmr_register(L);
return tmr_start(L);
}
// Lua: tmr.stop( id )
static int tmr_stop(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
//we return false if the timer is idle (of not registered)
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF){
tmr->mode |= TIMER_IDLE_FLAG;
ets_timer_disarm(&tmr->os);
lua_pushboolean(L, 1);
}else{
lua_pushboolean(L, 0);
}
return 1;
}
// Lua: tmr.unregister( id )
static int tmr_unregister(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
if(!(tmr->mode & TIMER_IDLE_FLAG) && tmr->mode != TIMER_MODE_OFF)
ets_timer_disarm(&tmr->os);
if(tmr->lua_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, tmr->lua_ref);
tmr->lua_ref = LUA_NOREF;
tmr->mode = TIMER_MODE_OFF;
return 0;
}
// Lua: tmr.interval( id, interval )
static int tmr_interval(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
sint32_t interval = luaL_checkinteger(L, 2);
if(interval <= 0)
return luaL_error(L, "wrong arg range");
if(tmr->mode != TIMER_MODE_OFF){
tmr->interval = interval;
if(!(tmr->mode&TIMER_IDLE_FLAG)){
ets_timer_disarm(&tmr->os);
ets_timer_arm_new(&tmr->os, tmr->interval, tmr->mode==TIMER_MODE_AUTO, 1);
}
}
return 0;
}
// Lua: tmr.state( id )
static int tmr_state(lua_State* L){
uint8_t id = luaL_checkinteger(L, 1);
MOD_CHECK_ID(tmr,id);
timer_t tmr = &alarm_timers[id];
if(tmr->mode == TIMER_MODE_OFF){
lua_pushnil(L);
return 1;
}
lua_pushboolean(L, (tmr->mode&TIMER_IDLE_FLAG)==0);
lua_pushinteger(L, tmr->mode&(~TIMER_IDLE_FLAG));
return 2;
}
/*I left the led comments 'couse I don't know
why they are here*/
// extern void update_key_led();
// Lua: wdclr()
static int tmr_wdclr( lua_State* L )
{
// Lua: tmr.wdclr()
static int tmr_wdclr( lua_State* L ){
WRITE_PERI_REG(0x60000914, 0x73);
// update_key_led();
return 0;
}
static os_timer_t rtc_timer_updator;
static uint32_t cur_count = 0;
static uint32_t rtc_10ms = 0;
void rtc_timer_update_cb(void *arg){
uint32_t t = (uint32_t)system_get_rtc_time();
uint32_t delta = 0;
if(t>=cur_count){
delta = t-cur_count;
}else{
delta = 0xFFFFFFF - cur_count + t + 1;
}
// uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count);
// NODE_ERR("%x\n",t);
cur_count = t;
uint32_t c = system_rtc_clock_cali_proc();
uint32_t itg = c >> 12; // ~=5
uint32_t dec = c & 0xFFF; // ~=2ff
rtc_10ms += (delta*itg + ((delta*dec)>>12)) / 10000;
// TODO: store rtc_10ms to rtc memory.
//system_rtc_clock_cali_proc() returns
//a fixed point value (12 bit fraction part)
//it tells how many rtc clock ticks represent 1us.
//the high 64 bits of the uint64_t multiplication
//are unnedded (I did the math)
static uint32_t rtc2sec(uint64_t rtc){
uint64_t aku = system_rtc_clock_cali_proc();
aku *= rtc;
return (aku>>12)/1000000;
}
// Lua: time() , return rtc time in second
static int tmr_time( lua_State* L )
{
uint32_t local = rtc_10ms;
lua_pushinteger( L, ((uint32_t)(local/100)) & 0x7FFFFFFF );
//the following function workes, I just wrote it and didn't use it.
/*static uint64_t sec2rtc(uint32_t sec){
uint64_t aku = (1<<20)/system_rtc_clock_cali_proc();
aku *= sec;
return (aku>>8)*1000000;
}*/
inline static void rtc_timer_update(){
uint32_t current = system_get_rtc_time();
if(rtc_time.part[0] > current) //overflow check
rtc_time.part[1]++;
rtc_time.part[0] = current;
}
void rtc_callback(void *arg){
rtc_timer_update();
if(soft_watchdog > 0){
soft_watchdog--;
if(soft_watchdog == 0)
system_restart();
}
}
// Lua: tmr.time() , return rtc time in second
static int tmr_time( lua_State* L ){
rtc_timer_update();
lua_pushinteger(L, rtc2sec(rtc_time.block));
return 1;
}
// Lua: tmr.softwd( value )
static int tmr_softwd( lua_State* L ){
soft_watchdog = luaL_checkinteger(L, 1);
return 0;
}
// Module function map
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE tmr_map[] =
{
const LUA_REG_TYPE tmr_map[] = {
{ LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
{ LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
{ LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
{ LSTRKEY( "stop" ), LFUNCVAL( tmr_stop ) },
{ LSTRKEY( "wdclr" ), LFUNCVAL( tmr_wdclr ) },
{ LSTRKEY( "softwd" ), LFUNCVAL( tmr_softwd ) },
{ LSTRKEY( "time" ), LFUNCVAL( tmr_time ) },
{ LSTRKEY( "register" ), LFUNCVAL ( tmr_register ) },
{ LSTRKEY( "alarm" ), LFUNCVAL( tmr_alarm ) },
{ LSTRKEY( "start" ), LFUNCVAL ( tmr_start ) },
{ LSTRKEY( "stop" ), LFUNCVAL ( tmr_stop ) },
{ LSTRKEY( "unregister" ), LFUNCVAL ( tmr_unregister ) },
{ LSTRKEY( "state" ), LFUNCVAL ( tmr_state ) },
{ LSTRKEY( "interval" ), LFUNCVAL ( tmr_interval) },
#if LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "ALARM_SINGLE" ), LNUMVAL( TIMER_MODE_SINGLE ) },
{ LSTRKEY( "ALARM_SEMI" ), LNUMVAL( TIMER_MODE_SEMI ) },
{ LSTRKEY( "ALARM_AUTO" ), LNUMVAL( TIMER_MODE_AUTO ) },
#endif
{ LNILKEY, LNILVAL }
};
LUALIB_API int luaopen_tmr( lua_State *L )
{
int i = 0;
for(i=0;i<NUM_TMR;i++){
os_timer_disarm(&(alarm_timer[i]));
os_timer_setfn(&(alarm_timer[i]), (os_timer_func_t *)(alarm_timer_cb[i]), L);
LUALIB_API int luaopen_tmr( lua_State *L ){
int i;
for(i=0; i<NUM_TMR; i++){
alarm_timers[i].lua_ref = LUA_NOREF;
alarm_timers[i].mode = TIMER_MODE_OFF;
ets_timer_disarm(&alarm_timers[i].os);
}
os_timer_disarm(&rtc_timer_updator);
os_timer_setfn(&rtc_timer_updator, (os_timer_func_t *)(rtc_timer_update_cb), NULL);
os_timer_arm(&rtc_timer_updator, 500, 1);
rtc_time.block = 0;
ets_timer_disarm(&rtc_timer);
ets_timer_setfn(&rtc_timer, rtc_callback, NULL);
ets_timer_arm_new(&rtc_timer, 1000, 1, 1);
#if LUA_OPTIMIZE_MEMORY > 0
return 0;
#else // #if LUA_OPTIMIZE_MEMORY > 0
#else
luaL_register( L, AUXLIB_TMR, tmr_map );
// Add constants
lua_pushvalue( L, -1 );
lua_setmetatable( L, -2 );
MOD_REG_NUMBER( L, "ALARM_SINGLE", TIMER_MODE_SINGLE );
MOD_REG_NUMBER( L, "ALARM_SEMI", TIMER_MODE_SEMI );
MOD_REG_NUMBER( L, "ALARM_AUTO", TIMER_MODE_AUTO );
return 1;
#endif // #if LUA_OPTIMIZE_MEMORY > 0
#endif
}

View File

@ -26,21 +26,6 @@ typedef struct _lu8g_userdata_t lu8g_userdata_t;
#define LU8G (&(lud->u8g))
// function to read 4-byte aligned from program memory AKA irom0
u8g_pgm_uint8_t ICACHE_FLASH_ATTR u8g_pgm_read(const u8g_pgm_uint8_t *adr)
{
uint32_t iadr = (uint32_t)adr;
// set up pointer to 4-byte aligned memory location
uint32_t *ptr = (uint32_t *)(iadr & ~0x3);
// read 4-byte aligned
uint32_t pgm_data = *ptr;
// return the correct byte within the retrieved 32bit word
return pgm_data >> ((iadr % 4) * 8);
}
// helper function: retrieve and check userdata argument
static lu8g_userdata_t *get_lud( lua_State *L )
{
@ -889,22 +874,12 @@ uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void
break;
case U8G_COM_MSG_WRITE_SEQ:
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
platform_spi_send_recv( 1, *ptr++ );
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P:
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
platform_spi_send_recv( 1, u8g_pgm_read(ptr) );
ptr++;
platform_spi_send_recv( 1, *ptr++ );
arg_val--;
}
}
@ -957,6 +932,7 @@ uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, voi
break;
case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
@ -973,24 +949,6 @@ uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, voi
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_WRITE_SEQ_P:
//u8g->pin_list[U8G_PI_SET_A0] = 1;
if ( u8g_com_esp8266_ssd_start_sequence(u8g) == 0 )
return platform_i2c_send_stop( ESP_I2C_ID ), 0;
{
register uint8_t *ptr = arg_ptr;
while( arg_val > 0 )
{
// ignore return value -> tolerate missing ACK
if ( platform_i2c_send_byte( ESP_I2C_ID, u8g_pgm_read(ptr) ) == 0 )
; //return 0;
ptr++;
arg_val--;
}
}
// platform_i2c_send_stop( ESP_I2C_ID );
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g->pin_list[U8G_PI_A0_STATE] = arg_val;
u8g->pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again */

View File

@ -17,23 +17,48 @@
static int wifi_smart_succeed = LUA_NOREF;
static uint8 getap_output_format=0;
#if defined( NODE_SMART_OLDSTYLE )
#else
static lua_State* smart_L = NULL;
#endif
static void wifi_smart_succeed_cb(void *arg){
NODE_DBG("wifi_smart_succeed_cb is called.\n");
#if defined( NODE_SMART_OLDSTYLE )
if( !arg )
return;
#if 0
if(wifi_smart_succeed == LUA_NOREF)
return;
lua_State* L = (lua_State *)arg;
lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
lua_call(L, 0, 0);
#else
if( !arg )
return;
struct station_config *sta_conf = arg;
wifi_station_set_config(sta_conf);
wifi_station_disconnect();
wifi_station_connect();
if(wifi_smart_succeed != LUA_NOREF)
{
lua_rawgeti(smart_L, LUA_REGISTRYINDEX, wifi_smart_succeed);
lua_pushstring(smart_L, sta_conf->ssid);
lua_pushstring(smart_L, sta_conf->password);
lua_call(smart_L, 2, 0);
luaL_unref(smart_L, LUA_REGISTRYINDEX, wifi_smart_succeed);
wifi_smart_succeed = LUA_NOREF;
}
smartconfig_stop();
#endif
if(wifi_smart_succeed == LUA_NOREF)
return;
lua_State* L = (lua_State *)arg;
lua_rawgeti(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
lua_call(L, 0, 0);
#endif // defined( NODE_SMART_OLDSTYLE )
}
static int wifi_scan_succeed = LUA_NOREF;
@ -107,6 +132,9 @@ static void wifi_scan_done(void *arg, STATUS status)
// Lua: smart(type, function succeed_cb)
static int wifi_start_smart( lua_State* L )
{
#if defined( NODE_SMART_OLDSTYLE )
unsigned channel;
int stack = 1;
@ -133,15 +161,49 @@ static int wifi_start_smart( lua_State* L )
}else{
smart_begin(channel, (smart_succeed )wifi_smart_succeed_cb, L);
}
// smartconfig_start(0, wifi_smart_succeed_cb);
#else
if(wifi_get_opmode() != STATION_MODE)
{
return luaL_error( L, "Smart link only in STATION mode" );
}
uint8_t smart_type = 0;
int stack = 1;
smart_L = L;
if ( lua_isnumber(L, stack) )
{
smart_type = lua_tointeger(L, stack);
stack++;
}
if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION)
{
lua_pushvalue(L, stack); // copy argument (func) to the top of stack
if(wifi_smart_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
wifi_smart_succeed = luaL_ref(L, LUA_REGISTRYINDEX);
}
if ( smart_type > 1 )
return luaL_error( L, "wrong arg range" );
smartconfig_start(smart_type, wifi_smart_succeed_cb);
#endif // defined( NODE_SMART_OLDSTYLE )
return 0;
}
// Lua: exit_smart()
static int wifi_exit_smart( lua_State* L )
{
#if defined( NODE_SMART_OLDSTYLE )
smart_end();
// smartconfig_stop();
#else
smartconfig_stop();
#endif // defined( NODE_SMART_OLDSTYLE )
if(wifi_smart_succeed != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, wifi_smart_succeed);
wifi_smart_succeed = LUA_NOREF;
@ -815,6 +877,19 @@ static int wifi_ap_getbroadcast( lua_State* L ){
return wifi_getbroadcast(L, SOFTAP_IF);
}
// Lua: wifi.ap.getconfig()
static int wifi_ap_getconfig( lua_State* L )
{
struct softap_config config;
wifi_softap_get_config(&config);
lua_pushstring( L, config.ssid );
if(config.authmode = AUTH_OPEN)
lua_pushnil(L);
else
lua_pushstring( L, config.password );
return 2;
}
// Lua: wifi.ap.config(table)
static int wifi_ap_config( lua_State* L )
{
@ -1030,6 +1105,7 @@ static const LUA_REG_TYPE wifi_station_map[] =
{ LSTRKEY( "connect" ), LFUNCVAL ( wifi_station_connect4lua ) },
{ LSTRKEY( "disconnect" ), LFUNCVAL ( wifi_station_disconnect4lua ) },
{ LSTRKEY( "autoconnect" ), LFUNCVAL ( wifi_station_setauto ) },
{ LSTRKEY( "getconfig" ), LFUNCVAL( wifi_ap_getconfig ) },
{ LSTRKEY( "getip" ), LFUNCVAL ( wifi_station_getip ) },
{ LSTRKEY( "setip" ), LFUNCVAL ( wifi_station_setip ) },
{ LSTRKEY( "getbroadcast" ), LFUNCVAL ( wifi_station_getbroadcast) },

140
app/modules/ws2801.c Normal file
View File

@ -0,0 +1,140 @@
#include "lualib.h"
#include "lauxlib.h"
#include "platform.h"
#include "auxmods.h"
#include "lrotable.h"
#include "c_stdlib.h"
#include "c_string.h"
/**
* Code is based on https://github.com/CHERTS/esp8266-devkit/blob/master/Espressif/examples/EspLightNode/user/ws2801.c
* and provides a similar api as the ws2812 module.
* The current implementation allows the caller to use
* any combination of GPIO0, GPIO2, GPIO4, GPIO5 as clock and data.
*/
#define PIN_CLK_DEFAULT 0
#define PIN_DATA_DEFAULT 2
static uint32_t ws2801_bit_clk;
static uint32_t ws2801_bit_data;
static void ws2801_byte(uint8_t n) {
uint8_t bitmask;
for (bitmask = 0x80; bitmask !=0 ; bitmask >>= 1) {
if (n & bitmask) {
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, ws2801_bit_data);
} else {
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_data);
}
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, ws2801_bit_clk);
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_clk);
}
}
static void ws2801_color(uint8_t r, uint8_t g, uint8_t b) {
ws2801_byte(r);
ws2801_byte(g);
ws2801_byte(b);
}
static void ws2801_strip(uint8_t const * data, uint16_t len) {
while (len--) {
ws2801_byte(*(data++));
}
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, ws2801_bit_data);
}
static void enable_pin_mux(pin) {
// The API only supports setting PERIPHS_IO_MUX on GPIO 0, 2, 4, 5
switch (pin) {
case 0:
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
break;
case 2:
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
break;
case 4:
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
break;
case 5:
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
break;
default:
break;
}
}
/* Lua: ws2801.init(pin_clk, pin_data)
* Sets up the GPIO pins
*
* ws2801.init(0, 2) uses GPIO0 as clock and GPIO2 as data.
* This is the default behavior.
*/
static int ICACHE_FLASH_ATTR ws2801_init_lua(lua_State* L) {
uint32_t pin_clk;
uint32_t pin_data;
uint32_t func_gpio_clk;
uint32_t func_gpio_data;
if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
// Use default pins if the input is omitted
pin_clk = PIN_CLK_DEFAULT;
pin_data = PIN_DATA_DEFAULT;
} else {
pin_clk = luaL_checkinteger(L, 1);
pin_data = luaL_checkinteger(L, 2);
}
ws2801_bit_clk = 1 << pin_clk;
ws2801_bit_data = 1 << pin_data;
os_delay_us(10);
//Set GPIO pins to output mode
enable_pin_mux(pin_clk);
enable_pin_mux(pin_data);
//Set both GPIOs low low
gpio_output_set(0, ws2801_bit_clk | ws2801_bit_data, ws2801_bit_clk | ws2801_bit_data, 0);
os_delay_us(10);
}
/* Lua: ws2801.write(pin, "string")
* Byte triples in the string are interpreted as R G B values.
* This function does not corrupt your buffer.
*
* ws2801.write(string.char(255, 0, 0)) sets the first LED red.
* ws2801.write(string.char(0, 0, 255):rep(10)) sets ten LEDs blue.
* ws2801.write(string.char(0, 255, 0, 255, 255, 255)) first LED green, second LED white.
*/
static int ICACHE_FLASH_ATTR ws2801_writergb(lua_State* L) {
size_t length;
const char *buffer = luaL_checklstring(L, 1, &length);
os_delay_us(10);
os_intr_lock();
ws2801_strip(buffer, length);
os_intr_unlock();
return 0;
}
#define MIN_OPT_LEVEL 2
#include "lrodefs.h"
const LUA_REG_TYPE ws2801_map[] =
{
{ LSTRKEY( "write" ), LFUNCVAL( ws2801_writergb )},
{ LSTRKEY( "init" ), LFUNCVAL( ws2801_init_lua )},
{ LNILKEY, LNILVAL}
};
LUALIB_API int luaopen_ws2801(lua_State *L) {
LREGISTER(L, "ws2801", ws2801_map);
return 1;
}

View File

@ -88,7 +88,7 @@ extern "C" {
# define U8G_FONT_SECTION(name) U8G_SECTION(".progmem." name)
# endif
# if defined(__XTENSA__)
# define U8G_FONT_SECTION(name) U8G_SECTION(".u8g_progmem." name)
# define U8G_FONT_SECTION(name)
# endif
#else
# define U8G_NOINLINE
@ -116,10 +116,10 @@ typedef uint8_t u8g_fntpgm_uint8_t;
#elif defined(__XTENSA__)
# define U8G_PROGMEM
# define PROGMEM U8G_SECTION(".u8g_progmem.data")
# define PROGMEM
typedef uint8_t u8g_pgm_uint8_t;
typedef uint8_t u8g_fntpgm_uint8_t;
u8g_pgm_uint8_t u8g_pgm_read(const u8g_pgm_uint8_t *adr);
# define u8g_pgm_read(adr) (*(const u8g_pgm_uint8_t *)(adr))
# define U8G_PSTR(s) ((u8g_pgm_uint8_t *)(s))
#else

112
app/user/user_exceptions.c Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright 2015 Dius Computing Pty Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the copyright holders nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Johny Mattsson <jmattsson@dius.com.au>
*/
#include "user_exceptions.h"
#define LOAD_MASK 0x00f00fu
#define L8UI_MATCH 0x000002u
#define L16UI_MATCH 0x001002u
#define L16SI_MATCH 0x009002u
void load_non_32_wide_handler (struct exception_frame *ef, uint32_t cause)
{
/* If this is not EXCCAUSE_LOAD_STORE_ERROR you're doing it wrong! */
(void)cause;
uint32_t epc1 = ef->epc;
uint32_t excvaddr;
uint32_t insn;
asm (
"rsr %0, EXCVADDR;" /* read out the faulting address */
"movi a4, ~3;" /* prepare a mask for the EPC */
"and a4, a4, %2;" /* apply mask for 32bit aligned base */
"l32i a5, a4, 0;" /* load part 1 */
"l32i a6, a4, 4;" /* load part 2 */
"ssa8l %2;" /* set up shift register for src op */
"src %1, a6, a5;" /* right shift to get faulting instruction */
:"=r"(excvaddr), "=r"(insn)
:"r"(epc1)
:"a4", "a5", "a6"
);
uint32_t valmask = 0;
uint32_t what = insn & LOAD_MASK;
if (what == L8UI_MATCH)
valmask = 0xffu;
else if (what == L16UI_MATCH || what == L16SI_MATCH)
valmask = 0xffffu;
else
{
die:
/* Turns out we couldn't fix this, trigger a system break instead
* and hang if the break doesn't get handled. This is effectively
* what would happen if the default handler was installed. */
asm ("break 1, 1");
while (1) {}
}
/* Load, shift and mask down to correct size */
uint32_t val = (*(uint32_t *)(excvaddr & ~0x3));
val >>= (excvaddr & 0x3) * 8;
val &= valmask;
/* Sign-extend for L16SI, if applicable */
if (what == L16SI_MATCH && (val & 0x8000))
val |= 0xffff0000;
int regno = (insn & 0x0000f0u) >> 4;
if (regno == 1)
goto die; /* we can't support loading into a1, just die */
else if (regno != 0)
--regno; /* account for skipped a1 in exception_frame */
ef->a_reg[regno] = val; /* carry out the load */
ef->epc += 3; /* resume at following instruction */
}
/**
* The SDK's user_main function installs a debugging handler regardless
* of whether there's a proper handler installed for EXCCAUSE_LOAD_STORE_ERROR,
* which of course breaks everything if we allow that to go through. As such,
* we use the linker to wrap that call and stop the SDK from shooting itself in
* its proverbial foot.
*/
exception_handler_fn
__wrap__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn)
{
if (cause != EXCCAUSE_LOAD_STORE_ERROR)
__real__xtos_set_exception_handler (cause, fn);
}

View File

@ -0,0 +1,5 @@
#include "c_types.h"
#include "rom.h"
#include <xtensa/corebits.h>
void load_non_32_wide_handler (struct exception_frame *ef, uint32_t cause) TEXT_SECTION_ATTR;

View File

@ -16,6 +16,7 @@
#include "flash_fs.h"
#include "user_interface.h"
#include "user_exceptions.h"
#include "ets_sys.h"
#include "driver/uart.h"
@ -25,6 +26,21 @@
#define TASK_QUEUE_LEN 4
os_event_t *taskQueue;
/* Note: the trampoline *must* be explicitly put into the .text segment, since
* by the time it is invoked the irom has not yet been mapped. This naturally
* also goes for anything the trampoline itself calls.
*/
void user_start_trampoline (void) TEXT_SECTION_ATTR;
void user_start_trampoline (void)
{
__real__xtos_set_exception_handler (
EXCCAUSE_LOAD_STORE_ERROR, load_non_32_wide_handler);
call_user_start ();
}
void task_lua(os_event_t *e){
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
NODE_DBG("Task task_lua started.\n");

View File

@ -84,6 +84,9 @@ typedef enum {
#define ICACHE_FLASH_ATTR
#endif /* ICACHE_FLASH */
#define TEXT_SECTION_ATTR __attribute__((section(".text")))
#define RAM_CONST_ATTR __attribute__((section(".text")))
#ifndef __cplusplus
typedef unsigned char bool;
#define BOOL bool

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 = 0x60000
irom0_0_seg : org = 0x40210000, len = 0x80000
}
PHDRS
@ -19,7 +19,7 @@ PHDRS
/* Default entry point: */
ENTRY(call_user_start)
ENTRY(user_start_trampoline)
PROVIDE(_memmap_vecbase_reset = 0x40000000);
/* Various memory-map dependent cache attribute settings: */
_memmap_cacheattr_wb_base = 0x00000110;
@ -72,8 +72,9 @@ SECTIONS
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
*(.literal.* .text.*)
/* put font and progmem data into irom0 */
*(.u8g_progmem.*)
/* Trade some performance for lots of ram. At the time of writing the
* available Lua heap went from 18248 to 34704. */
*(.rodata*)
_irom0_text_end = ABSOLUTE(.);
_flash_used_end = ABSOLUTE(.);
@ -124,10 +125,7 @@ SECTIONS
.rodata : ALIGN(4)
{
_rodata_start = ABSOLUTE(.);
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table)

Binary file not shown.

View File

@ -0,0 +1,36 @@
--this version actually works
local tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
base64 = {
enc = function(data)
local l,out = 0,''
local m = (3-data:len()%3)%3
local d = data..string.rep('\0',m)
for i=1,d:len() do
l = bit.lshift(l,8)
l = l+d:byte(i,i)
if i%3==0 then
for j=1,4 do
local a = bit.rshift(l,18)+1
out = out..tab:sub(a,a)
l = bit.band(bit.lshift(l,6),0xFFFFFF)
end
end
end
return out:sub(1,-1-m)..string.rep('=',m)
end,
dec = function(data)
local a,b = data:gsub('=','A')
local out = ''
local l = 0
for i=1,a:len() do
l=l+tab:find(a:sub(i,i))-1
if i%4==0 then
out=out..string.char(bit.rshift(l,16),bit.band(bit.rshift(l,8),255),bit.band(l,255))
l=0
end
l=bit.lshift(l,6)
end
return out:sub(1,-b-1)
end
}

BIN
tools/esp-open-sdk.tar.gz Normal file

Binary file not shown.

View File

@ -128,30 +128,20 @@ class ESPROM:
def connect(self):
print 'Connecting...'
# 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)
time.sleep(0.1)
self._port.setRTS(False)
for _ in xrange(4):
# issue reset-to-bootloader:
# RTS = either CH_PD or nRESET (both active low = chip in reset)
# DTR = GPIO0 (active low = boot to flasher)
self._port.setDTR(False)
time.sleep(0.1)
self._port.setRTS(True)
time.sleep(0.1)
time.sleep(0.05)
self._port.setDTR(True)
self._port.setRTS(False)
time.sleep(0.3)
self._port.setDTR(True)
time.sleep(0.05)
self._port.setDTR(False)
self._port.timeout = 0.5
for i in xrange(10):
self._port.timeout = 0.3 # worst-case latency timer should be 255ms (probably <20ms)
for _ in xrange(4):
try:
self._port.flushInput()
self._port.flushOutput()
@ -159,7 +149,11 @@ class ESPROM:
self._port.timeout = 5
return
except:
time.sleep(0.1)
time.sleep(0.05)
# this is a workaround for the CH340 serial driver on current versions of Linux,
# which seems to sometimes set the serial port up with wrong parameters
self._port.close()
self._port.open()
raise Exception('Failed to connect')
""" Read memory address in target """
@ -268,6 +262,15 @@ class ESPROM:
return data
""" Abuse the loader protocol to force flash to be left in write mode """
def flash_unlock_dio(self):
# Enable flash write mode
self.flash_begin(0, 0)
# Reset the chip rather than call flash_finish(), which would have
# write protected the chip again (why oh why does it do that?!)
self.mem_begin(0,0,0,0x40100000)
self.mem_finish(0x40000080)
""" Perform a chip erase of SPI flash """
def flash_erase(self):
# Trick ROM to initialize SFlash
@ -360,6 +363,20 @@ class ELFFile:
self._fetch_symbols()
return self.symbols[sym]
def get_entry_point(self):
tool_readelf = "xtensa-lx106-elf-readelf"
if os.getenv('XTENSA_CORE')=='lx106':
tool_objcopy = "xt-readelf"
try:
proc = subprocess.Popen([tool_readelf, "-h", self.name], stdout=subprocess.PIPE)
except OSError:
print "Error calling "+tool_nm+", do you have Xtensa toolchain in PATH?"
sys.exit(1)
for l in proc.stdout:
fields = l.strip().split()
if fields[0] == "Entry":
return int(fields[3], 0);
def load_section(self, section):
tool_objcopy = "xtensa-lx106-elf-objcopy"
if os.getenv('XTENSA_CORE')=='lx106':
@ -552,6 +569,9 @@ if __name__ == '__main__':
seq += 1
print
print '\nLeaving...'
if args.flash_mode == 'dio':
esp.flash_unlock_dio()
else:
esp.flash_finish(False)
elif args.operation == 'run':
@ -586,7 +606,7 @@ if __name__ == '__main__':
args.output = args.input + '-'
e = ELFFile(args.input)
image = ESPFirmwareImage()
image.entrypoint = e.get_symbol_addr("call_user_start")
image.entrypoint = e.get_entry_point()
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)