commit
aaca524ce0
|
@ -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:
|
||||
|
|
73
README.md
73
README.md
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
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]);
|
||||
//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();
|
||||
|
||||
}
|
||||
lua_call(L, 0, 0);
|
||||
//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(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(tmr->L, 0, 0);
|
||||
}
|
||||
|
||||
void alarm_timer_cb0(void *arg){
|
||||
if( !arg )
|
||||
return;
|
||||
alarm_timer_common((lua_State*)arg, 0);
|
||||
// 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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void alarm_timer_cb1(void *arg){
|
||||
if( !arg )
|
||||
return;
|
||||
alarm_timer_common((lua_State*)arg, 1);
|
||||
// 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;
|
||||
}
|
||||
|
||||
void alarm_timer_cb2(void *arg){
|
||||
if( !arg )
|
||||
return;
|
||||
alarm_timer_common((lua_State*)arg, 2);
|
||||
// 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;
|
||||
}
|
||||
|
||||
void alarm_timer_cb3(void *arg){
|
||||
if( !arg )
|
||||
return;
|
||||
alarm_timer_common((lua_State*)arg, 3);
|
||||
// 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;
|
||||
}
|
||||
|
||||
void alarm_timer_cb4(void *arg){
|
||||
if( !arg )
|
||||
return;
|
||||
alarm_timer_common((lua_State*)arg, 4);
|
||||
// Lua: tmr.alarm( id, interval, repeat, function )
|
||||
static int tmr_alarm(lua_State* L){
|
||||
tmr_register(L);
|
||||
return tmr_start(L);
|
||||
}
|
||||
|
||||
void alarm_timer_cb5(void *arg){
|
||||
if( !arg )
|
||||
return;
|
||||
alarm_timer_common((lua_State*)arg, 5);
|
||||
// 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;
|
||||
}
|
||||
|
||||
void alarm_timer_cb6(void *arg){
|
||||
if( !arg )
|
||||
return;
|
||||
alarm_timer_common((lua_State*)arg, 6);
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 );
|
||||
WRITE_PERI_REG(0x60000914, 0x73);
|
||||
}
|
||||
if(remain>0)
|
||||
os_delay_us( remain );
|
||||
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: now() , return system timer in us
|
||||
static int tmr_now( lua_State* L )
|
||||
{
|
||||
unsigned now = 0x7FFFFFFF & system_get_time();
|
||||
lua_pushinteger( L, now );
|
||||
return 1;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: stop( id )
|
||||
static int tmr_stop( lua_State* L )
|
||||
{
|
||||
unsigned id = luaL_checkinteger( L, 1 );
|
||||
MOD_CHECK_ID( tmr, id );
|
||||
|
||||
os_timer_disarm(&(alarm_timer[id]));
|
||||
if(alarm_timer_cb_ref[id] != LUA_NOREF)
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, alarm_timer_cb_ref[id]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*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 )
|
||||
{
|
||||
WRITE_PERI_REG(0x60000914, 0x73);
|
||||
// update_key_led();
|
||||
return 0;
|
||||
// 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 );
|
||||
return 1;
|
||||
|
||||
//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[] =
|
||||
{
|
||||
{ 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( "time" ), LFUNCVAL( tmr_time ) },
|
||||
#if LUA_OPTIMIZE_MEMORY > 0
|
||||
|
||||
const LUA_REG_TYPE tmr_map[] = {
|
||||
{ LSTRKEY( "delay" ), LFUNCVAL( tmr_delay ) },
|
||||
{ LSTRKEY( "now" ), LFUNCVAL( tmr_now ) },
|
||||
{ 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 }
|
||||
{ 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);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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
|
||||
luaL_register( L, AUXLIB_TMR, tmr_map );
|
||||
// Add constants
|
||||
|
||||
return 1;
|
||||
#endif // #if LUA_OPTIMIZE_MEMORY > 0
|
||||
return 0;
|
||||
#else
|
||||
luaL_register( L, AUXLIB_TMR, tmr_map );
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
@ -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
|
||||
}
|
Binary file not shown.
|
@ -128,38 +128,32 @@ 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)
|
||||
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)
|
||||
self._port.setRTS(True)
|
||||
time.sleep(0.05)
|
||||
self._port.setDTR(True)
|
||||
self._port.setRTS(False)
|
||||
time.sleep(0.05)
|
||||
self._port.setDTR(False)
|
||||
|
||||
# NodeMCU devkit
|
||||
self._port.setRTS(True)
|
||||
self._port.setDTR(True)
|
||||
time.sleep(0.1)
|
||||
self._port.setRTS(False)
|
||||
self._port.setDTR(False)
|
||||
time.sleep(0.1)
|
||||
self._port.setRTS(True)
|
||||
time.sleep(0.1)
|
||||
self._port.setDTR(True)
|
||||
self._port.setRTS(False)
|
||||
time.sleep(0.3)
|
||||
self._port.setDTR(True)
|
||||
|
||||
self._port.timeout = 0.5
|
||||
for i in xrange(10):
|
||||
try:
|
||||
self._port.flushInput()
|
||||
self._port.flushOutput()
|
||||
self.sync()
|
||||
self._port.timeout = 5
|
||||
return
|
||||
except:
|
||||
time.sleep(0.1)
|
||||
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()
|
||||
self.sync()
|
||||
self._port.timeout = 5
|
||||
return
|
||||
except:
|
||||
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,7 +569,10 @@ if __name__ == '__main__':
|
|||
seq += 1
|
||||
print
|
||||
print '\nLeaving...'
|
||||
esp.flash_finish(False)
|
||||
if args.flash_mode == 'dio':
|
||||
esp.flash_unlock_dio()
|
||||
else:
|
||||
esp.flash_finish(False)
|
||||
|
||||
elif args.operation == 'run':
|
||||
esp.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)
|
||||
|
|
Loading…
Reference in New Issue