diff --git a/.travis.yml b/.travis.yml
index 894f2fd0..5e76c51e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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:
diff --git a/README.md b/README.md
index 4e7a4aeb..89794648 100644
--- a/README.md
+++ b/README.md
@@ -36,44 +36,32 @@ Tencent QQ group: 309957875
- cross compiler (done)
# Change log
+2015-06-25
+move constants to ROM. Frees up 16k+ of RAM.
+add dhtlib for DHT11/21/22/33/44, port from Arduino.
+add 433MHz transmission.
+add crypto library.
+re-add ws2812.write().
+add wifi.getchannel.
+changed wifi_setip() to allow setting SoftAP gateway to 0.0.0.0.
+added net.dns.setdnsserver and net.dns.getdnsserver.
+add support for lm92 temperature sensor.
+implement getStrWidth() and setFontLineSpacingFactor().
+add -Os flag to release and debug builds.
+changed output format of table that is output by wifi_scan_done.
+added ability to set scan configuration to wifi.sta.getap.
+added function wifi.sta.getconfig().
+allow connecting to unsecured WiFi networks.
+add setphymode and getphymode to wifi module.
+add multicastJoin and multicastLeave to net module.
+add Yeelink Modules.
+
2015-03-31
polish mqtt module, add queue for mqtt module.
add reconnect option to mqtt.connect api, :connect( host, port, secure, auto_reconnect, function(client) )
move node.readvdd33 to adc.readvdd33.
tools/esptool.py supported NodeMCU devkit automatic flash.
-2015-03-18
-update u8glib.
-merge everything to master.
-
-2015-03-17
-add cjson module, only cjson.encode() and cjson.decode() is implemented.
-read doc [here](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/cjson/manual.txt)
-
-2015-03-15
-bugs fixed: #239, #273.
-reduce coap module memory usage, add coap module to default built.
-
-2015-03-11
-fix bugs of spiffs.
-build both float and integer version [latest releases](https://github.com/nodemcu/nodemcu-firmware/releases/latest).
-fix tmr.time().
-fix memory leak when DNS fail.
-
-2015-03-10
-update to the recent spiffs.
-add file.fsinfo() api, usage: remain, used, total = file.fsinfo().
-add Travis CI. please download the latest firmware from [releases](https://github.com/nodemcu/nodemcu-firmware/releases).
-add math lib, partial api work.
-u8g module, ws2812 module default enabled in dev-branch build.
-
-2015-02-13
-add node.compile() api to compile lua text file into lua bytecode file.
-this will reduce memory usage noticeably when require modules into NodeMCU.
-raise internal LUA_BUFFERSIZE from 1024 to 4096.
-lua require("mod") will load "mod.lc" file first if exist.
-build latest pre_build bin.
-
[more change log](https://github.com/nodemcu/nodemcu-firmware/wiki)
##GPIO NEW TABLE ( Build 20141219 and later)
diff --git a/app/Makefile b/app/Makefile
index 87331c24..8275a264 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -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 \
diff --git a/app/include/rom.h b/app/include/rom.h
index 88d7c81d..51d3fbe1 100644
--- a/app/include/rom.h
+++ b/app/include/rom.h
@@ -37,3 +37,57 @@ 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);
+
+
+// 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);
+
diff --git a/app/include/user_version.h b/app/include/user_version.h
index 789e5fea..a803dfaa 100644
--- a/app/include/user_version.h
+++ b/app/include/user_version.h
@@ -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 20150625"
#endif /* __USER_VERSION_H__ */
diff --git a/app/modules/u8g.c b/app/modules/u8g.c
index 3596ab06..b046635e 100644
--- a/app/modules/u8g.c
+++ b/app/modules/u8g.c
@@ -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 */
diff --git a/app/u8glib/u8g.h b/app/u8glib/u8g.h
index 7aa2845a..e62fb024 100644
--- a/app/u8glib/u8g.h
+++ b/app/u8glib/u8g.h
@@ -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
diff --git a/app/user/user_exceptions.c b/app/user/user_exceptions.c
new file mode 100644
index 00000000..fb26e76a
--- /dev/null
+++ b/app/user/user_exceptions.c
@@ -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
+ */
+
+#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);
+}
diff --git a/app/user/user_exceptions.h b/app/user/user_exceptions.h
new file mode 100644
index 00000000..d2cf5166
--- /dev/null
+++ b/app/user/user_exceptions.h
@@ -0,0 +1,5 @@
+#include "c_types.h"
+#include "rom.h"
+#include
+
+void load_non_32_wide_handler (struct exception_frame *ef, uint32_t cause) TEXT_SECTION_ATTR;
diff --git a/app/user/user_main.c b/app/user/user_main.c
index 88938da8..c24e0f00 100644
--- a/app/user/user_main.c
+++ b/app/user/user_main.c
@@ -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");
diff --git a/include/c_types.h b/include/c_types.h
index 55bffd46..2cd6332a 100644
--- a/include/c_types.h
+++ b/include/c_types.h
@@ -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
diff --git a/ld/eagle.app.v6.ld b/ld/eagle.app.v6.ld
index a36cb31e..2df6a4ae 100644
--- a/ld/eagle.app.v6.ld
+++ b/ld/eagle.app.v6.ld
@@ -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)
diff --git a/tools/esp-open-sdk.tar.gz b/tools/esp-open-sdk.tar.gz
new file mode 100644
index 00000000..87af5572
Binary files /dev/null and b/tools/esp-open-sdk.tar.gz differ
diff --git a/tools/esptool.py b/tools/esptool.py
index 88a4b4ed..53e10041 100755
--- a/tools/esptool.py
+++ b/tools/esptool.py
@@ -360,6 +360,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':
@@ -586,7 +600,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)