diff --git a/.gitignore b/.gitignore index 533bf9c..6c56811 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,9 @@ src/lfs/lfs.img *.x86_64 *.hex +# Build Artifacts +build +firmware/builds + # Private files private - diff --git a/README.md b/README.md index 14d3b57..dce3e1b 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ # Konnected **Konnected** integrates wired alarm system sensors and sirens to SmartThings, Home Assistant, OpenHAB, or Hubitat using a NodeMCU based ESP8266 development board and (optional) relay. This project consists of a few components: - + 1. [NodeMCU](http://nodemcu.com/index_en.html) based firmware for an ESP8266 development board in `firmware` 1. Lua and HTML source code for the NodeMCU in `src`. All these files are built into a SPIFFS file system which runs on NodeMCU 1. [SmartThings](https://www.smartthings.com/) platform code in `smartapps` and `devicetypes` - + ![](http://docs.konnected.io/assets/images/konnected-alarm-panel.jpg) ## Skip this Installation! @@ -26,7 +26,7 @@ #### Note on Device Drivers Windows and Mac users will need to download drivers so your computer can talk to the ESP8266 chip over USB. Depending -on which board you have, there are different drivers: +on which board you have, there are different drivers: **[WeMos CH340 drivers](https://www.wemos.cc/en/latest/ch340_driver.html)** for boards that: * have the name _LoLin_ on the back or front @@ -41,23 +41,19 @@ on which board you have, there are different drivers: Konnected leverages the [NodeMCU](https://github.com/nodemcu/nodemcu-firmware) codebase and [Docker builder](https://hub.docker.com/r/marcelstoer/nodemcu-build/) to create a base nodeMCU firmware image and a filesystem containing the Konnected application. Building only requires a few steps. 1. Download and install [Docker](https://www.docker.com/products/docker-desktop) -1. Clone the Konnected and nodeMCU repos to the same level in your working directory +1. Clone the Konnected repo git clone https://github.com/konnected-io/konnected-security.git - git clone https://github.com/nodemcu/nodemcu-firmware.git - -1. Check out the 2.2.1 release of nodemcu - pushd nodemcu-firmware && git checkout 2.2.1-master_20190405 && popd - -1. Use the build-firmware script to kick off the build - providing a semantic version command line argument as shown below. The build script will automatically pull down the nodeMCU docker builder, build the base firmware, create an LFS image, and build a SPIFFS file system containing the entire Konnected application. +1. Use the build-firmware script to kick off the build - providing a semantic version command line argument as shown below. The build script will automatically pull down the correct nodeMCU image, and use this nodeMCU docker builder to create base firmware, an LFS image, and a SPIFFS file system containing the entire Konnected application. cd konnected-security ./scripts/build-firmware 2-2-99 -1. Once the build completes a folder will be created in `firmware/builds` named after the version specified in the previous step. This folder will contain two files also reflecting the version. +1. Once the build completes a folder will be created in `firmware/builds` named after the version specified in the previous step. This folder will contain three files also reflecting the version. 1. konnected-filesystem-0x100000-2-2-99.img 1. konnected-firmware-2-2-99.bin + 1. konnected-esp8266-2-2-99.bin *Note: Each time you build it will remove any prior build outputs corresponding to the same version.* *Note: Versions in this project should always be formatted `--`.* @@ -67,26 +63,26 @@ Flashing a build is simple with the [Konnected Flashing Tool](https://help.konne Mac and Linux users can also easily flash from the command line using [scripts/flash](scripts/flash). - 1. You must have Python installed with `pip` or `pip3`. - * **Mac users**: I recommend using [Homebrew](https://brew.sh/) and `brew install python` - + 1. You must have Python installed with `pip` or `pip3`. + * **Mac users**: I recommend using [Homebrew](https://brew.sh/) and `brew install python` + 1. Open up a terminal and install `esptool` packages: - + pip3 install esptool - + 1. Run the script in `scripts/flash` to flash the firmware and software to the device. You must pass in version and serial port args. The flash script will always attempt to flash a matching version in `firmware/builds` before falling back to `firmware/releases` ./scripts/flash 2-2-99 /dev/ttyS3 - + *Note: You may also need to make the script executable by running `chmod 755 scripts/flash`.* - + ### Donations We work hard on this project because we're passionate about making home automation accessible to everybody. Millions of homes in North America and worldwide are already wired with sensors and have the potential to become smart homes. We want to make this a reality. - + If you've used Konnected Security and it's improved your life and your home security, please consider [donating](http://docs.konnected.io/donate) to help us achieve that goal. diff --git a/firmware/nodemcu-firmware-overlay/app/include/user_config.h b/firmware/nodemcu-firmware-overlay/app/include/user_config.h index f1303b0..a3c0fd9 100644 --- a/firmware/nodemcu-firmware-overlay/app/include/user_config.h +++ b/firmware/nodemcu-firmware-overlay/app/include/user_config.h @@ -22,6 +22,26 @@ //#define BIT_RATE_AUTOBAUD +// At start-up firmware details like: +// +// NodeMCU 3.0.1.0 +// branch: +// commit: +// release: +// release DTS: +// SSL: false +// build type: integer +// LFS: 0x0 +// modules: file,gpio,net,node,rtctime,sntp,tmr,uart,wifi +// build 2020-01-27 17:39 powered by Lua 5.1.4 on SDK 3.0.2(824dc80) +// +// will be printed to serial console. While it's mandatory for bug reports +// and good for development, it may be unwanted for non-interactive serial +// devices. + +//#define DISABLE_STARTUP_BANNER + + // Three separate build variants are now supported. The main difference is in the // processing of numeric data types. If LUA_NUMBER_INTEGRAL is defined, then // all numeric calculations are done in integer, with divide being an integer @@ -41,12 +61,12 @@ // The Lua Flash Store (LFS) allows you to store Lua code in Flash memory and // the Lua VMS will execute this code directly from flash without needing any -// RAM overhead. If you want to enable LFS then set the following define to -// the size of the store that you need. This can be any multiple of 4kB up to -// a maximum 256Kb. - -#define LUA_FLASH_STORE 0x10000 +// RAM overhead. You can now configure LFS directly in the System Partition +// Table insted of at compile time. However for backwards compatibility setting +// LUA_FLASH_STORE defines the default partition size if the NodeMCU partition +// tool is not used. +#define LUA_FLASH_STORE 0x40000 // By default Lua executes the file init.lua at start up. The following // define allows you to replace this with an alternative startup. Warning: @@ -59,7 +79,7 @@ // NodeMCU supports two file systems: SPIFFS and FATFS, the first is available -// on all ESP8266 modules. The latter requires extra H/W so is less common. +// on all ESP8266 modules. The latter requires extra H/W so it is less common. // If you use SPIFFS then there are a number of options which impact the // RAM overhead and performance of the file system. @@ -71,11 +91,15 @@ // general, limiting the size of the FS only to what your application needs // gives the fastest start-up and imaging times. +// You can now configure SPIFFS size and position directly in the System +// Partition Table. However backwards compatibility SPIFFS_MAX_FILESYSTEM_SIZE +// can be set and this defines the default SPIFFS partition size if the NodeMCU +// partition tool is not used. The value (~0x0) means the maximum size remaining. + #define BUILD_SPIFFS -#define SPIFFS_FIXED_LOCATION 0x100000 -#define SPIFFS_MAX_FILESYSTEM_SIZE 128000 -//#define SPIFFS_SIZE_1M_BOUNDARY #define SPIFFS_CACHE 1 // Enable if you use you SPIFFS in R/W mode +#define SPIFFS_MAX_FILESYSTEM_SIZE 0x100000 +#define SPIFFS_FIXED_LOCATION 0x100000 #define SPIFFS_MAX_OPEN_FILES 4 // maximum number of open files for SPIFFS #define FS_OBJ_NAME_LEN 31 // maximum length of a filename @@ -84,26 +108,26 @@ // The HTTPS stack requires client SSL to be enabled. The SSL buffer size is // used only for espconn-layer secure connections, and is ignored otherwise. -// Some HTTPS applications require a larger buffer size to work. See +// Some HTTPS applications require a larger buffer size to work. See // https://github.com/nodemcu/nodemcu-firmware/issues/1457 for details. // The SHA2 and MD2 libraries are also optionally used by the crypto functions. // The SHA1 and MD5 function are implemented in the ROM BIOS. The MD2 and SHA2 // are by firmware code, and can be enabled if you need this functionality. #define CLIENT_SSL_ENABLE -//#define MD2_ENABLE #define SHA2_ENABLE -#define SSL_BUFFER_SIZE 5376 +#define SSL_BUFFER_SIZE 5380 +#define SSL_MAX_FRAGMENT_LENGTH_CODE MBEDTLS_SSL_MAX_FRAG_LEN_4096 // GPIO_INTERRUPT_ENABLE needs to be defined if your application uses the // gpio.trig() or related GPIO interrupt service routine code. Likewise the -// GPIO interrupt hook is requited for a few modules such as rotary. If you -// don't require this functionality, then commenting out these options out +// GPIO interrupt hook is required for a few modules such as rotary. If you +// don't require this functionality, then commenting out these options // will remove any associated runtime overhead. #define GPIO_INTERRUPT_ENABLE -//#define GPIO_INTERRUPT_HOOK_ENABLE +#define GPIO_INTERRUPT_HOOK_ENABLE // If your application uses the light sleep functions and you wish the @@ -113,15 +137,18 @@ //#define TIMER_SUSPEND_ENABLE //#define PMSLEEP_ENABLE +// The net module optionally offers net info functionnality. Uncomment the following +// to enable the functionnality. +#define NET_PING_ENABLE // The WiFi module optionally offers an enhanced level of WiFi connection // management, using internal timer callbacks. Whilst many Lua developers // prefer to implement equivalent features in Lua, others will prefer the // Wifi module to do this for them. Uncomment the following to enable -// this functionality. See the relevant WiFi module documentation for +// this functionality. See the relevant WiFi module documentation for // further details, as the scope of these changes is not obvious. -// Enable the wifi.startsmart() and wifi.stopsmart() +// Enable the wifi.startsmart() and wifi.stopsmart() //#define WIFI_SMART_ENABLE // Enable wifi.sta.config() event callbacks @@ -130,10 +157,6 @@ // Enable creation on the wifi.eventmon.reason table #define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE -// Enable use of the WiFi.monitor sub-module -//#define LUA_USE_MODULES_WIFI_MONITOR - - // Whilst the DNS client details can be configured through the WiFi API, // the defaults can be exposed temporarily during start-up. The following // WIFI_STA options allow you to configure this in the firmware. If the @@ -155,7 +178,23 @@ #define ENDUSER_SETUP_AP_SSID "konnected" -// The following sections are only relevent for those developers who are +// I2C software driver partially supports use of GPIO16 (D0) pin for SCL line. +// GPIO16 does not support open-drain mode and works in push-pull mode, +// so clock stretching will not be possible, because circuit in slave device that +// supposed to drive SCL low during stretching will not be capable to hold SCL low. +// Also I2C speed will be limited to no more than 400000 Hz (FAST mode). +// This define is does not have an effect on an old driver (see I2C_MASTER_OLD_VERSION). + +//#define I2C_MASTER_GPIO16_ENABLE + +// For compatibility reasons you can switch to old version of I2C software driver. +// It does not support changing speed, have only one bus id = 0, does not support GPIO16 +// and works only in Standard(slow) mode with clock speed around 50kHz. + +#define I2C_MASTER_OLD_VERSION + + +// The following sections are only relevant for those developers who are // developing modules or core Lua changes and configure how extra diagnostics // are enabled in the firmware. These should only be configured if you are // building your own custom firmware and have full access to the firmware @@ -189,6 +228,28 @@ // change this if you have tracked the implications through the Firmware sources // and understand the these. +#define NODEMCU_EAGLEROM_PARTITION 1 +#define NODEMCU_IROM0TEXT_PARTITION 2 +#define NODEMCU_LFS0_PARTITION 3 +#define NODEMCU_LFS1_PARTITION 4 +#define NODEMCU_TLSCERT_PARTITION 5 +#define NODEMCU_SPIFFS0_PARTITION 6 +#define NODEMCU_SPIFFS1_PARTITION 7 + +#ifndef LUA_FLASH_STORE +# define LUA_FLASH_STORE 0x0 +#endif + +#ifndef SPIFFS_FIXED_LOCATION + #define SPIFFS_FIXED_LOCATION 0x0 + // You'll rarely need to customize this, because nowadays + // it's usually overruled by the partition table anyway. +#endif +#ifndef SPIFFS_MAX_FILESYSTEM_SIZE + #define SPIFFS_MAX_FILESYSTEM_SIZE 0xFFFFFFFF +#endif +//#define SPIFFS_SIZE_1M_BOUNDARY + #define LUA_TASK_PRIO USER_TASK_PRIO_0 #define LUA_PROCESS_LINE_SIG 2 #define LUA_OPTIMIZE_DEBUG 2 @@ -196,17 +257,17 @@ #define STRBUF_DEFAULT_INCREMENT 3 #define LUA_USE_BUILTIN_DEBUG_MINIMAL // for debug.getregistry() and debug.traceback() -#ifdef DEVELOPMENT_TOOLS -#if defined(LUA_CROSS_COMPILER) || !defined(DEVELOPMENT_USE_GDB) +#if defined(DEVELOPMENT_TOOLS) && defined(DEVELOPMENT_USE_GDB) +extern void LUA_DEBUG_HOOK (void); +#define lua_assert(x) ((x) ? (void) 0 : LUA_DEBUG_HOOK ()) +#elif defined(DEVELOPMENT_TOOLS) && defined(LUA_CROSS_COMPILER) extern void luaL_assertfail(const char *file, int line, const char *message); #define lua_assert(x) ((x) ? (void) 0 : luaL_assertfail(__FILE__, __LINE__, #x)) #else -extern void luaL_dbgbreak(void); -#define lua_assert(x) ((x) ? (void) 0 : luaL_dbgbreak()) -#endif +#define lua_assert(x) ((void) (x)) #endif -#if !defined(LUA_NUMBER_INTEGRAL) && defined (LUA_DWORD_ALIGNED_TVALUES) +#if !defined(LUA_NUMBER_INTEGRAL) && !defined (LUA_DWORD_ALIGNED_TVALUES) #define LUA_PACK_TVALUES #else #undef LUA_PACK_TVALUES @@ -217,17 +278,22 @@ extern void luaL_dbgbreak(void); #define COAP_DEBUG #endif /* DEVELOP_VERSION */ + +#if !defined(LUA_CROSS_COMPILER) && !defined(dbg_printf) +extern void dbg_printf(const char *fmt, ...); +#endif + #ifdef NODE_DEBUG #define NODE_DBG dbg_printf #else -#define NODE_DBG +#define NODE_DBG( ... ) #endif /* NODE_DEBUG */ #define NODE_ERROR #ifdef NODE_ERROR #define NODE_ERR dbg_printf #else -#define NODE_ERR +#define NODE_ERR( ... ) #endif /* NODE_ERROR */ // #define GPIO_SAFE_NO_INTR_ENABLE @@ -235,12 +301,7 @@ extern void luaL_dbgbreak(void); #define ICACHE_STORE_ATTR __attribute__((aligned(4))) #define ICACHE_STRING(x) ICACHE_STRING2(x) #define ICACHE_STRING2(x) #x -#define ICACHE_RAM_ATTR \ - __attribute__((section(".iram0.text." __FILE__ "." ICACHE_STRING(__LINE__)))) -#define ICACHE_FLASH_RESERVED_ATTR \ - __attribute__((section(".irom.reserved." __FILE__ "." ICACHE_STRING(__LINE__)),\ - used,unused,aligned(INTERNAL_FLASH_SECTOR_SIZE))) - +#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text." __FILE__ "." ICACHE_STRING(__LINE__)))) #ifdef GPIO_SAFE_NO_INTR_ENABLE #define NO_INTR_CODE ICACHE_RAM_ATTR __attribute__ ((noinline)) #else diff --git a/firmware/nodemcu-firmware-overlay/app/include/user_mbedtls.h b/firmware/nodemcu-firmware-overlay/app/include/user_mbedtls.h index a269c5d..03af8bc 100644 --- a/firmware/nodemcu-firmware-overlay/app/include/user_mbedtls.h +++ b/firmware/nodemcu-firmware-overlay/app/include/user_mbedtls.h @@ -1,4 +1,5 @@ -#include "c_types.h" +#include +#include #include "user_config.h" @@ -73,34 +74,36 @@ #undef MBEDTLS_ENABLE_WEAK_CIPHERSUITES #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES -#define MBEDTLS_ECP_DP_SECP192R1_ENABLED -#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#undef MBEDTLS_ECP_DP_SECP192R1_ENABLED +#undef MBEDTLS_ECP_DP_SECP224R1_ENABLED #define MBEDTLS_ECP_DP_SECP256R1_ENABLED #define MBEDTLS_ECP_DP_SECP384R1_ENABLED -#define MBEDTLS_ECP_DP_SECP521R1_ENABLED -#define MBEDTLS_ECP_DP_SECP192K1_ENABLED -#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#undef MBEDTLS_ECP_DP_SECP521R1_ENABLED + +#undef MBEDTLS_ECP_DP_SECP192K1_ENABLED +#undef MBEDTLS_ECP_DP_SECP224K1_ENABLED #define MBEDTLS_ECP_DP_SECP256K1_ENABLED + #define MBEDTLS_ECP_DP_BP256R1_ENABLED #define MBEDTLS_ECP_DP_BP384R1_ENABLED -#define MBEDTLS_ECP_DP_BP512R1_ENABLED -#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#undef MBEDTLS_ECP_DP_BP512R1_ENABLED +#undef MBEDTLS_ECP_DP_CURVE25519_ENABLED /* Not exported on the wire yet :( */ #define MBEDTLS_ECP_NIST_OPTIM -#undef MBEDTLS_ECDSA_DETERMINISTIC +#define MBEDTLS_ECDSA_DETERMINISTIC #undef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED #undef MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED #undef MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED #undef MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_RSA_ENABLED #define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED #define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -#undef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #undef MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED #undef MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED @@ -108,7 +111,7 @@ #undef MBEDTLS_ERROR_STRERROR_DUMMY -#define MBEDTLS_GENPRIME +#undef MBEDTLS_GENPRIME #undef MBEDTLS_FS_IO @@ -138,8 +141,8 @@ #undef MBEDTLS_SSL_HW_RECORD_ACCEL -#define MBEDTLS_SSL_CBC_RECORD_SPLITTING -#define MBEDTLS_SSL_RENEGOTIATION +#undef MBEDTLS_SSL_CBC_RECORD_SPLITTING +#undef MBEDTLS_SSL_RENEGOTIATION #undef MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO #undef MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE @@ -147,8 +150,8 @@ #define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH #undef MBEDTLS_SSL_PROTO_SSL3 -#define MBEDTLS_SSL_PROTO_TLS1 -#define MBEDTLS_SSL_PROTO_TLS1_1 +#undef MBEDTLS_SSL_PROTO_TLS1 +#undef MBEDTLS_SSL_PROTO_TLS1_1 #define MBEDTLS_SSL_PROTO_TLS1_2 #undef MBEDTLS_SSL_PROTO_DTLS @@ -178,23 +181,29 @@ #undef MBEDTLS_AESNI_C #define MBEDTLS_AES_C -#define MBEDTLS_ARC4_C +#undef MBEDTLS_ARC4_C #define MBEDTLS_ASN1_PARSE_C #define MBEDTLS_ASN1_WRITE_C #define MBEDTLS_BASE64_C #define MBEDTLS_BIGNUM_C -#define MBEDTLS_BLOWFISH_C +#undef MBEDTLS_BLOWFISH_C #define MBEDTLS_CAMELLIA_C #define MBEDTLS_CCM_C #undef MBEDTLS_CERTS_C #define MBEDTLS_CIPHER_C #define MBEDTLS_CMAC_C #define MBEDTLS_CTR_DRBG_C -#undef MBEDTLS_DEBUG_C -#define MBEDTLS_DES_C + +#ifdef DEVELOP_VERSION +# define MBEDTLS_DEBUG_C +#else +# undef MBEDTLS_DEBUG_C +#endif + +#undef MBEDTLS_DES_C #define MBEDTLS_DHM_C #define MBEDTLS_ECDH_C -#undef MBEDTLS_ECDSA_C +#define MBEDTLS_ECDSA_C #undef MBEDTLS_ECJPAKE_C #define MBEDTLS_ECP_C #define MBEDTLS_ENTROPY_C @@ -205,7 +214,7 @@ #define MBEDTLS_MD_C #undef MBEDTLS_MD2_C #undef MBEDTLS_MD4_C -#define MBEDTLS_MD5_C +#undef MBEDTLS_MD5_C #undef MBEDTLS_MEMORY_BUFFER_ALLOC_C #define MBEDTLS_NET_C #define MBEDTLS_OID_C @@ -240,7 +249,7 @@ #define MBEDTLS_X509_CREATE_C #define MBEDTLS_X509_CRT_WRITE_C #define MBEDTLS_X509_CSR_WRITE_C -#define MBEDTLS_XTEA_C +#undef MBEDTLS_XTEA_C #define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */ #define MBEDTLS_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ @@ -256,7 +265,7 @@ //#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ //#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ -//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +#define MBEDTLS_ECP_MAX_BITS 384 /**< Maximum bit size of groups */ #define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */ #define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */ @@ -266,8 +275,10 @@ //#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ //#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ -#define MBEDTLS_PLATFORM_STD_CALLOC pvPortCalloc /**< Default allocator to use, can be undefined */ -#define MBEDTLS_PLATFORM_STD_FREE vPortFree /**< Default free to use, can be undefined */ +extern void *mbedtls_calloc_wrap(size_t n, size_t sz); +#define MBEDTLS_PLATFORM_STD_CALLOC mbedtls_calloc_wrap /**< Default allocator to use, can be undefined */ +extern void mbedtls_free_wrap(void *p); +#define MBEDTLS_PLATFORM_STD_FREE mbedtls_free_wrap /**< Default free to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ //#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ @@ -292,22 +303,16 @@ //#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ //#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ -#if 0 -// dynamic buffer sizing with espconn_secure_set_size() -extern unsigned int max_content_len; -#define MBEDTLS_SSL_MAX_CONTENT_LEN max_content_len; -#else // the current mbedtls integration doesn't allow to set the buffer size dynamically: // MBEDTLS_SSL_MAX_FRAGMENT_LENGTH feature and dynamic sizing are mutually exclusive -// due to non-constant initializer element in app/mbedtls/library/ssl_tls.c:150 +// due to non-constant initializer element in app/mbedtls/library/ssl_tls.c:150 // the buffer size is hardcoded here and value is taken from SSL_BUFFER_SIZE (user_config.h) #define MBEDTLS_SSL_MAX_CONTENT_LEN SSL_BUFFER_SIZE /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ -#endif //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ //#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ //#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ -#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 +//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 #define MBEDTLS_X509_MAX_INTERMEDIATE_CA 3 /**< Maximum number of intermediate CAs in a verification chain. */ //#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ diff --git a/firmware/nodemcu-firmware-overlay/app/include/user_modules.h b/firmware/nodemcu-firmware-overlay/app/include/user_modules.h index 3e9f757..b367d4e 100644 --- a/firmware/nodemcu-firmware-overlay/app/include/user_modules.h +++ b/firmware/nodemcu-firmware-overlay/app/include/user_modules.h @@ -21,9 +21,9 @@ //#define LUA_USE_MODULES_COLOR_UTILS //#define LUA_USE_MODULES_CRON #define LUA_USE_MODULES_CRYPTO +//#define LUA_USE_MODULES_DCC #define LUA_USE_MODULES_DHT -#define LUA_USE_MODULES_DS18B20 -//#define LUA_USE_MODULES_ENCODER +#define LUA_USE_MODULES_ENCODER #define LUA_USE_MODULES_ENDUSER_SETUP // USE_DNS in dhcpserver.h needs to be enabled for this module to work. #define LUA_USE_MODULES_FILE //#define LUA_USE_MODULES_GDBSTUB @@ -40,10 +40,12 @@ #define LUA_USE_MODULES_MQTT #define LUA_USE_MODULES_NET #define LUA_USE_MODULES_NODE -//#define LUA_USE_MODULES_OW +#define LUA_USE_MODULES_OW //#define LUA_USE_MODULES_PCM //#define LUA_USE_MODULES_PERF +//#define LUA_USE_MODULES_PIPE //#define LUA_USE_MODULES_PWM +//#define LUA_USE_MODULES_PWM2 //#define LUA_USE_MODULES_RC //#define LUA_USE_MODULES_RFSWITCH //#define LUA_USE_MODULES_ROTARY @@ -54,6 +56,7 @@ //#define LUA_USE_MODULES_SIGMA_DELTA #define LUA_USE_MODULES_SJSON #define LUA_USE_MODULES_SNTP +//#define LUA_USE_MODULES_SOFTUART //#define LUA_USE_MODULES_SOMFY //#define LUA_USE_MODULES_SPI //#define LUA_USE_MODULES_SQLITE3 diff --git a/firmware/nodemcu-firmware-overlay/app/include/user_version.h b/firmware/nodemcu-firmware-overlay/app/include/user_version.h index a33e207..a8e7d0d 100644 --- a/firmware/nodemcu-firmware-overlay/app/include/user_version.h +++ b/firmware/nodemcu-firmware-overlay/app/include/user_version.h @@ -2,6 +2,7 @@ #define __USER_VERSION_H__ #include "version.h" /* ESP firmware header */ +#include #define NODE_VERSION_MAJOR ESP_SDK_VERSION_MAJOR #define NODE_VERSION_MINOR ESP_SDK_VERSION_MINOR @@ -11,10 +12,12 @@ #define NODE_VERSION_STR(x) #x #define NODE_VERSION_XSTR(x) NODE_VERSION_STR(x) -#define NODE_VERSION "Konnected firmware 2.3.0\r\nNodeMCU " ESP_SDK_VERSION_STRING "." NODE_VERSION_XSTR(NODE_VERSION_INTERNAL) +# define NODE_VERSION "Konnected firmware 3.0.0\r\nNodeMCU " ESP_SDK_VERSION_STRING "." NODE_VERSION_XSTR(NODE_VERSION_INTERNAL) +// Leave the space after # in the line above. It busts replacement of NODE_VERSION in the docker build which is not needed anymore with this PR. +// Can be removed when the script is adapted #ifndef BUILD_DATE -#define BUILD_DATE "20190805" +#define BUILD_DATE BUILDINFO_BUILD_DATE #endif extern char SDK_VERSION[]; diff --git a/firmware/nodemcu-firmware-overlay/app/user/user_main.c b/firmware/nodemcu-firmware-overlay/app/user/user_main.c new file mode 100644 index 0000000..c9d4788 --- /dev/null +++ b/firmware/nodemcu-firmware-overlay/app/user/user_main.c @@ -0,0 +1,359 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: user_main.c + * + * Description: entry file of user application + * + * Modification history: + * 2014/1/1, v1.0 create this file. +*******************************************************************************/ +#include "lua.h" +#include "platform.h" +#include +#include +#include +#include "vfs.h" +#include "flash_api.h" +#include "user_interface.h" +#include "user_modules.h" + +#include "ets_sys.h" +#include "driver/uart.h" +#include "driver/input.h" +#include "task/task.h" +#include "mem.h" +#include "espconn.h" +#include "sections.h" +#include "../modules/wifi_common.h" + +#ifdef LUA_USE_MODULES_RTCTIME +#include "rtc/rtctime.h" +#endif +extern int lua_main (void); + +/* Contents of esp_init_data_default.bin */ +extern const uint32_t init_data[], init_data_end[]; +#define INIT_DATA_SIZE ((init_data_end - init_data)*sizeof(uint32_t)) +__asm__( + ".align 4\n" + "init_data: .incbin \"" ESP_INIT_DATA_DEFAULT "\"\n" + "init_data_end:\n" +); +extern const char _irom0_text_start[], _irom0_text_end[], _flash_used_end[]; + +#define IROM0_SIZE (_irom0_text_end - _irom0_text_start) + +#define PRE_INIT_TEXT_ATTR __attribute__((section(".p3.pre_init"))) +#define IROM_PTABLE_ATTR __attribute__((section(".irom0.ptable"))) +#define USED_ATTR __attribute__((used)) + +#define PARTITION(n) (SYSTEM_PARTITION_CUSTOMER_BEGIN + n) + +#define SIZE_256K 0x00040000 +#define SIZE_1024K 0x00100000 +#define PT_CHUNK 0x00002000 +#define PT_ALIGN(n) ((n + (PT_CHUNK-1)) & (~((PT_CHUNK-1)))) +#define FLASH_BASE_ADDR ((char *) 0x40200000) + +#define NODEMCU_PARTITION_EAGLEROM PLATFORM_PARTITION(NODEMCU_EAGLEROM_PARTITION) +#define NODEMCU_PARTITION_IROM0TEXT PLATFORM_PARTITION(NODEMCU_IROM0TEXT_PARTITION) +#define NODEMCU_PARTITION_LFS PLATFORM_PARTITION(NODEMCU_LFS0_PARTITION) +#define NODEMCU_PARTITION_SPIFFS PLATFORM_PARTITION(NODEMCU_SPIFFS0_PARTITION) + +#define RF_CAL_SIZE 0x1000 +#define PHY_DATA_SIZE 0x1000 +#define SYSTEM_PARAMETER_SIZE 0x3000 + +#define MAX_PARTITIONS 20 +#define WORDSIZE sizeof(uint32_t) +#define PTABLE_SIZE 7 /** THIS MUST BE MATCHED TO NO OF PT ENTRIES BELOW **/ + +struct defaultpt { + platform_rcr_t hdr; + partition_item_t pt[PTABLE_SIZE+1]; // the +! is for the endmarker + }; +#define PT_LEN (NUM_PARTITIONS*sizeof(partition_item_t)) +/* + * See app/platform/platform.h for how the platform reboot config records are used + * and these records are allocated. The first record is a default partition table + * and this is statically declared in compilation below. + */ +static const struct defaultpt rompt IROM_PTABLE_ATTR USED_ATTR = { + .hdr = {.len = sizeof(struct defaultpt)/WORDSIZE - 1, + .id = PLATFORM_RCR_PT}, + .pt = { + { NODEMCU_PARTITION_EAGLEROM, 0x00000, 0x0B000}, + { SYSTEM_PARTITION_RF_CAL, 0x0D000, RF_CAL_SIZE}, + { SYSTEM_PARTITION_PHY_DATA, 0x0F000, PHY_DATA_SIZE}, + { NODEMCU_PARTITION_IROM0TEXT, 0x10000, 0x0000}, + { NODEMCU_PARTITION_LFS, 0x0, LUA_FLASH_STORE}, + { NODEMCU_PARTITION_SPIFFS, 0x0, SPIFFS_MAX_FILESYSTEM_SIZE}, + { SYSTEM_PARTITION_SYSTEM_PARAMETER, 0x0, SYSTEM_PARAMETER_SIZE}, + {0,(uint32_t) &_irom0_text_end,0} + } +}; +//TODO: map the TLS server and client certs into NODEMCU_TLSCERT_PARTITION + +static uint32_t first_time_setup(partition_item_t *pt, uint32_t n, uint32_t flash_size); +static void phy_data_setup (partition_item_t *pt, uint32_t n); +extern void _ResetHandler(void); + +/* + * The non-OS SDK prolog has been fundamentally revised in V3. See SDK EN document + * Partition Table.md for further discussion. This version of user_main.c is a + * complete rework aligned to V3, with the redundant pre-V3 features removed. + * + * SDK V3 significantly reduces the RAM footprint required by the SDK and introduces + * the use of a partition table (PT) to control flash allocation. The NodeMCU uses + * this PT for overall allocation of its flash resources. The non_OS SDK calls the + * user_pre_init() entry to do all of this startup configuration. Note that this + * runs with Icache enabled -- that is the IROM0 partition is already mapped to the + * address space at 0x40210000 and so that most SDK services are available, such + * as system_get_flash_size_map() which returns the valid flash size (including the + * 8Mb and 16Mb variants). + * + * The first 4K page of IROM0 (flash offset 0x10000) is used to maintain a set of + * Resource Communication Records (RCR) for inter-boot configuration using a NAND + * write-once algo (see app/platform/platform.h). One of the current records is the + * SDK3.0 PT. This build statically compiles in an initial version at the start of + * the PT, with a {0, _irom0_text_end,0} marker as the last record and some fields + * also that need to be recomputed at runtime. This version is either replaced + * by first boot processing after provisioning, or by a node.setpartitiontable() + * API call. These replacement PTs are complete and can be passed directly for use + * by the non-OS SDK. + * + * Note that we have released a host PC-base python tool, nodemcu-partition.py, to + * configure the PT, etc during provisioning. + */ +void user_pre_init(void) { + STARTUP_COUNT; +#ifdef LUA_USE_MODULES_RTCTIME + // Note: Keep this as close to call_user_start() as possible, since it + // is where the cpu clock actually gets bumped to 80MHz. + rtctime_early_startup (); +#endif + int startup_option = platform_rcr_get_startup_option(); + + if (startup_option & STARTUP_OPTION_CPU_FREQ_MAX) { + REG_SET_BIT(0x3ff00014, BIT(0)); + ets_update_cpu_frequency(SYS_CPU_160MHZ); + } + int no_banner = startup_option & STARTUP_OPTION_NO_BANNER; + + partition_item_t *rcr_pt = NULL, *pt; + enum flash_size_map fs_size_code = system_get_flash_size_map(); +// Flash size lookup is SIZE_256K*2^N where N is as follows (see SDK/user_interface.h) + /* 0 1 2 3 4 5 6 7 8 9 */ + /* ½M ¼M 1M 2M 4M 2M 4M 4M 8M 16M */ + static char flash_size_scaler[] = "\001\000\002\003\004\003\004\004\005\006"; + uint32_t flash_size = SIZE_256K << flash_size_scaler[fs_size_code]; + + uint32_t i = platform_rcr_read(PLATFORM_RCR_PT, (void **) &rcr_pt); + uint32_t n = i / sizeof(partition_item_t); + + if (flash_size < SIZE_1024K) { + os_printf("Flash size (%u) too small to support NodeMCU\n", flash_size); + return; + } else { + if (!no_banner) { + os_printf("system SPI FI size:%u, Flash size: %u\n", fs_size_code, flash_size ); + } + } + + pt = os_malloc_iram(i); // We will work on and register a copy of the PT in iRAM + // Return if anything is amiss; The SDK will halt if the PT hasn't been registered + if ( !rcr_pt || !pt || n * sizeof(partition_item_t) != i) { + return; + } + os_memcpy(pt, rcr_pt, i); + + if (pt[n-1].type == 0) { + // If the last PT entry is a {0,XX,0} end marker, then we need first time setup + n = first_time_setup(pt, n-1, flash_size); // return n because setup might shrink the PT + } + + if (platform_rcr_read(PLATFORM_RCR_PHY_DATA, NULL)!=0) { + phy_data_setup(pt, n); + } + + // Now register the partition and return + if( fs_size_code > 1 && system_partition_table_regist(pt, n, fs_size_code)) { + if (no_banner) { + system_set_os_print(0); + } + STARTUP_COUNT; + return; + } + os_printf("Invalid system partition table\n"); + while (1) {}; +} + +/* + * If the PLATFORM_RCR_PT record doesn't exist then the PHY_DATA partition might + * not have been initialised. This must be set to the proper default init data + * otherwise the SDK will halt on the "rf_cal[0] !=0x05,is 0xFF" error. + */ +static void phy_data_setup (partition_item_t *pt, uint32_t n) { + uint8_t header[sizeof(uint32_t)] = {0}; + int i; + + for (i = 0; i < n; i++) { + if (pt[i].type == SYSTEM_PARTITION_PHY_DATA) { + uint32_t addr = pt[i].addr; + platform_s_flash_read(header, addr, sizeof(header)); + if (header[0] != 0x05) { + uint32_t sector = pt[i].addr/INTERNAL_FLASH_SECTOR_SIZE; + if (platform_flash_erase_sector(sector) == PLATFORM_OK) { + os_printf("Writing Init Data to 0x%08x\n",addr); + platform_s_flash_write(init_data, addr, INIT_DATA_SIZE); + } + } + // flag setup complete so we don't retry this every boot + platform_rcr_write(PLATFORM_RCR_PHY_DATA, &addr, 0); + return; + } + } + // If the PHY_DATA doesn't exist or the write fails then the + // SDK will raise the rf_cal error anyway, so just return. +} + +/* + * First time setup does the one-off PT calculations and checks. If these are OK, + * then writes back a new RCR for the updated PT and triggers a reboot. It returns + * on failure. + */ +static uint32_t first_time_setup(partition_item_t *pt, uint32_t n, uint32_t flash_size) { + int i, j, last = 0, newn = n; + /* + * Scan down the PT adjusting and 0 entries to sensible defaults. Also delete any + * zero-sized partitions (as the SDK barfs on these). + */ + for (i = 0, j = 0; i < n; i ++) { + partition_item_t *p = pt + i; + switch (p->type) { + + case NODEMCU_PARTITION_IROM0TEXT: + // If the IROM0 partition size is 0 then compute from the IROM0_SIZE. Note + // that the size in the end-marker is used by the nodemcu-partition.py + // script and not here. + if (p->size == 0) { + p->size = PT_ALIGN(IROM0_SIZE); + } + break; + + case NODEMCU_PARTITION_LFS: + // Properly align the LFS partition size and make it consecutive to + // the previous partition. + p->size = PT_ALIGN(p->size); + if (p->addr == 0) + p->addr = last; + break; + + /* + * Set up the SPIFFS partition based on some sensible defaults: + * size == 0 mean no SPIFFS partition. + * size == ~0 means use all of the available flash for SPIFFS (resp the addr if set). + * if size > 0 then float the default boundary to 1M if the SPIFFS will fit. + */ + case NODEMCU_PARTITION_SPIFFS: + if (p->size == ~0x0) { /* Maximum SPIFFS partition */ + if (p->addr == 0) + p->addr = last; + p->size = flash_size - SYSTEM_PARAMETER_SIZE - last; + } else if (p->size > 0x0) { /* Explicit SPIFFS size */ + if (p->addr < last) // SPIFFS can't overlap the previous region; + p->addr = 0; + if (p->addr == 0) + p->addr = (p->size <= flash_size - SYSTEM_PARAMETER_SIZE - 0x100000) ? + 0x100000 : last; + } + /* else p->size == 0 No SPIFFS partition */ + break; + + case SYSTEM_PARTITION_SYSTEM_PARAMETER: + p->addr = flash_size - SYSTEM_PARAMETER_SIZE; + p->size = SYSTEM_PARAMETER_SIZE; + } + + if (p->size == 0) { + // Delete 0-sized partitions as the SDK barfs on these + newn--; + } else { + /* + * Do consistency tests on the partition. The address and size must + * be flash sector aligned. Partitions can't overlap, and the last + * patition must fit within the flash size. + */ + if (p->addr & (INTERNAL_FLASH_SECTOR_SIZE - 1) || + p->size & (INTERNAL_FLASH_SECTOR_SIZE - 1) || + p->addr < last || + p->addr + p->size > flash_size) { + os_printf("Partition %u invalid alignment\n", i); + while(1) {/*system_soft_wdt_feed ();*/} + } + if (j < i) // shift the partition down if we have any deleted slots + pt[j] = *p; + j++; + last = p->addr + p->size; + } + } + + platform_rcr_write(PLATFORM_RCR_PT, pt, newn*sizeof(partition_item_t)); + ets_delay_us(5000); + _ResetHandler(); // Trigger reset; the new PT will be loaded on reboot +} + +uint32 ICACHE_RAM_ATTR user_iram_memory_is_enabled(void) { + return FALSE; // NodeMCU runs like a dog if iRAM is enabled +} + +void nodemcu_init(void) { + STARTUP_COUNT; + NODE_DBG("Task task_lua starting.\n"); + // Call the Lua bootstrap startup directly. This uses the task interface + // internally to carry out the main lua libraries initialisation. + if(lua_main()) + lua_main(); // If it returns true then LFS restart is needed +} + +/****************************************************************************** + * FunctionName : user_init + * Description : entry of user application, init user function here + * Parameters : none + * Returns : none +*******************************************************************************/ +void user_init(void) { +#ifdef LUA_USE_MODULES_RTCTIME + rtctime_late_startup (); +#endif + if( platform_init() != PLATFORM_OK ) { + // This should never happen + NODE_DBG("Can not init platform for modules.\n"); + return; + } + UartBautRate br = BIT_RATE_DEFAULT; + uart_init (br, br); +#ifdef LUA_USE_MODULES_WIFI + wifi_change_default_host_name(); +#endif +#ifndef NODE_DEBUG + system_set_os_print(0); +#endif + system_init_done_cb(nodemcu_init); +} +#if 0 +/* + * The SDK now establishes exception handlers for EXCCAUSE errors: ILLEGAL, + * INSTR_ERROR, LOAD_STORE_ERROR, PRIVILEGED, UNALIGNED, LOAD_PROHIBITED, + * STORE_PROHIBITED. These handlers are established in SDK/app_main.c. + * LOAD_STORE_ERROR is handled by SDK/user_exceptions.o:load_non_32_wide_handler() + * which is a fork of our version. The remaining are handled by a static function + * at SDK:app+main.c:offset 0x0348. This wrappoer is only needed for debugging. + */ +void __real__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn); +void __wrap__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn) { + os_printf("Exception handler %x %x\n", cause, fn); + __real__xtos_set_exception_handler (cause, fn); +} +#endif \ No newline at end of file diff --git a/scripts/build-firmware b/scripts/build-firmware index 26c93b5..ac79abc 100755 --- a/scripts/build-firmware +++ b/scripts/build-firmware @@ -1,11 +1,12 @@ -#!/bin/bash +#!/usr/bin/env bash function usage() { echo echo "usage: $0 " echo - echo ' version should be formatted --' - echo + echo ' -v version should be formatted --' + echo ' -c optional abs path to custom nodemcu-firmware repo' + echo echo 'Execute from the root dir of the repo. Upon successful completion the release will be created in firmware/releases/' echo " ex: '$0 2-3-0'" exit 1 @@ -14,48 +15,105 @@ if [ "$#" == 0 ]; then usage fi -VERSION="$1" -if ! [[ "${VERSION}" =~ ^[0-9]+-[0-9]+-[0-9]+ ]] ; then - echo "Version not formatted correctly..." - usage -fi +set -e -FIRMWARE_PATH="${PWD}/../nodemcu-firmware" +FW_TAG="3.0.0-release_20210201" +VERSION="3-0-0" FIRMWARE_OVERLAY_PATH="firmware/nodemcu-firmware-overlay" + +LFS_BASE="${PWD}/src/lfs" +OUTPUT_BASE="${PWD}/build" +OUTPUT_APP="${OUTPUT_BASE}/app" +FW_BASE="${OUTPUT_BASE}/nodemcu-firmware" + +# process cmd args +while getopts "v:c:h" opt; do + case ${opt} in + h ) + usage + ;; + c ) + FW_BASE="$OPTARG" + FW_TAG='' + echo "using custom nodemcu-repo ${FW_BASE}" + ;; + v ) + VERSION="$OPTARG" + if ! [[ "${VERSION}" =~ ^[0-9]+-[0-9]+-[0-9]+ ]] ; then + echo "Version not formatted correctly..." + usage + fi + echo "tagging as version ${VERSION}" + ;; + \? ) + echo "Invalid Option: -$OPTARG" 1>&2 + exit 1 + ;; + esac +done + BUILD_PATH="firmware/builds/${VERSION}" IMAGE_NAME="konnected-firmware-${VERSION}" +rm -rf ${OUTPUT_BASE} +mkdir -p "${OUTPUT_BASE}"; +chown -R $USER "${OUTPUT_BASE}" + +# pull and update the FW repo if none is supplied +if [ ! -z "$FW_TAG" ] ; then + echo "Checking out nodemcu-firmware:${FW_TAG}" + git clone --recurse-submodules https://github.com/nodemcu/nodemcu-firmware.git \ + "${FW_BASE}" + cd "${FW_BASE}" + git checkout "${FW_TAG}" + git submodule update --recursive + cd - +fi + # Copy firmware configuration from this repository to the nodemcu-firmware repo -cp "${FIRMWARE_OVERLAY_PATH}"/app/include/* "${FIRMWARE_PATH}/app/include/" +cp -rf "${FIRMWARE_OVERLAY_PATH}"/* "${FW_BASE}/" -rm -f "${FIRMWARE_PATH}/local/fs/*" +rm -f "${FW_BASE}/local/fs/*" # Build NodeMCU firmware image -docker run -e "INTEGER_ONLY=1" \ - -e "IMAGE_NAME=${IMAGE_NAME}" \ - --rm -ti -v "${FIRMWARE_PATH}:/opt/nodemcu-firmware" marcelstoer/nodemcu-build build +docker run -e "IMAGE_NAME=${IMAGE_NAME}" \ + --rm -ti -v "${FW_BASE}:/opt/nodemcu-firmware" marcelstoer/nodemcu-build build # Build LFS image with application files -docker run -e "IMAGE_NAME=lfs" \ - --rm -ti -v "${FIRMWARE_PATH}:/opt/nodemcu-firmware" \ - -v "${PWD}/src/lfs:/opt/lua" marcelstoer/nodemcu-build lfs-image +LUA_FILES=$(find ${LFS_BASE} -iname "*.lua" | sed "s|${LFS_BASE}|/lfs|g") + +echo Adding files to LFS: +echo ${LUA_FILES} +docker run --rm -ti \ + -v ${FW_BASE}:/nodemcu-firmware \ + -v ${OUTPUT_APP}:/build \ + -v ${LFS_BASE}:/lfs \ + marcelstoer/nodemcu-build /nodemcu-firmware/luac.cross.int -m 0x40000 -f -o "/build/lfs.img" ${LUA_FILES} +echo + +# transfer source files not in the lfs to the build output (ignore the status) +cp -f ${LFS_BASE}/../* "${OUTPUT_APP}" 2>/dev/null || true; echo "Building SPIFFS..." -mv src/lfs/LFS_integer_lfs.img src/lfs/lfs.img -rm -f src/lfs/LFS_float_lfs.img +# Build spiffsimg tool (manual for now because of https://github.com/nodemcu/nodemcu-firmware/issues/2943) +docker run --rm -ti \ + -v ${FW_BASE}:/nodemcu-firmware \ + marcelstoer/nodemcu-build make -C /nodemcu-firmware/tools/spiffsimg -# Build SPIFFS image +# Create SPIFFS image docker run \ - --rm -ti -v "${FIRMWARE_PATH}:/opt/nodemcu-firmware" \ + --rm -ti -v "${FW_BASE}:/opt/nodemcu-firmware" \ -v "${PWD}/scripts:/scripts" \ - -v "${PWD}/src:/opt/lua" marcelstoer/nodemcu-build bash /scripts/build-spiffs + -v "${OUTPUT_APP}:/opt/lua" marcelstoer/nodemcu-build bash /scripts/build-spiffs -# Create or clear the output directory and transfer files +# Create or clear the output directory and transfer files mkdir -p "${BUILD_PATH}" rm -rf "${BUILD_PATH}/*" -cp "${FIRMWARE_PATH}/bin/nodemcu_integer_${IMAGE_NAME}.bin" "${BUILD_PATH}/${IMAGE_NAME}.bin" -cp "${FIRMWARE_PATH}/bin/konnected-filesystem-0x100000.img" "${BUILD_PATH}/konnected-filesystem-0x100000-${VERSION}.img" +cp "${FW_BASE}/bin/nodemcu_integer_${IMAGE_NAME}.bin" "${BUILD_PATH}/${IMAGE_NAME}.bin" +cp "${FW_BASE}/bin/konnected-filesystem-0x100000.img" "${BUILD_PATH}/konnected-filesystem-0x100000-${VERSION}.img" srec_cat -output "${BUILD_PATH}/konnected-esp8266-${VERSION}.bin" -binary "${BUILD_PATH}/${IMAGE_NAME}.bin" -binary -fill 0xff 0x0000 0x100000 "${BUILD_PATH}/konnected-filesystem-0x100000-${VERSION}.img" -binary -offset 0x100000 +# Copy to common name for ease of flashing +cp "${BUILD_PATH}/konnected-esp8266-${VERSION}.bin" "${BUILD_PATH}/../konnected-esp8266-latest.bin" echo "Build Complete: Flash this build with './scripts/flash ${VERSION} '" \ No newline at end of file diff --git a/scripts/cross-compile b/scripts/cross-compile index 5ab98bc..7b2cd6f 100644 --- a/scripts/cross-compile +++ b/scripts/cross-compile @@ -1,5 +1,5 @@ #!/bin/bash for fname in /opt/nodemcu-firmware/local/fs/*.lua ; do - /opt/nodemcu-firmware/luac.cross -o /opt/nodemcu-firmware/local/fs/$(basename "$fname" .lua).{lc,lua} + /opt/nodemcu-firmware/luac.cross.int -o /opt/nodemcu-firmware/local/fs/$(basename "$fname" .lua).{lc,lua} done \ No newline at end of file diff --git a/scripts/flash b/scripts/flash index 1c00f6e..d26b16a 100755 --- a/scripts/flash +++ b/scripts/flash @@ -46,8 +46,8 @@ fi FILESYSTEM_NAME="$(echo ${BUILD_PATH}/konnected-filesystem-0x*-${VERSION}.img)" FS_ADDRESS="$(cut -d'-' -f5 <<<${FILESYSTEM_NAME})" -esptool.py "--port=${PORT}" write_flash --flash_mode dio 0x00000 "${FIRMWARE_NAME}" -esptool.py "--port=${PORT}" write_flash --flash_mode dio "${FS_ADDRESS}" "${FILESYSTEM_NAME}" +esptool.py "--port=${PORT}" write_flash --flash_mode dio --flash_size detect 0x00000 "${FIRMWARE_NAME}" +esptool.py "--port=${PORT}" write_flash --flash_mode dio --flash_size detect "${FS_ADDRESS}" "${FILESYSTEM_NAME}" tput bel diff --git a/scripts/spiffs.lst b/scripts/spiffs.lst index 6a78aa4..c993a11 100644 --- a/scripts/spiffs.lst +++ b/scripts/spiffs.lst @@ -7,4 +7,4 @@ import /opt/lua/http_index.html.gz http_index.html.gz import /opt/lua/init.lua init.lua import /opt/lua/sensors.lua sensors.lua import /opt/lua/settings.lua settings.lua -import /opt/lua/lfs/lfs.img lfs.img \ No newline at end of file +import /opt/lua/lfs.img lfs.img \ No newline at end of file diff --git a/src/enduser_setup.html.gz b/src/enduser_setup.html.gz index fbf730b..fa8d16c 100644 Binary files a/src/enduser_setup.html.gz and b/src/enduser_setup.html.gz differ diff --git a/src/init.lua b/src/init.lua index 49fda46..005c83a 100644 --- a/src/init.lua +++ b/src/init.lua @@ -1,8 +1,8 @@ print("Heap: ", node.heap(), "Initializing Konnected (" .. string.gsub(wifi.sta.getmac(), ":", "") .. ")") -- load the application in LFS if needed -if node.flashindex() == nil then - node.flashreload("lfs.img") +if node.flashindex("_init") == nil then + node.LFS.reload("lfs.img") end pcall(node.flashindex("_init")) diff --git a/src/lfs/application.lua b/src/lfs/application.lua index cb5ccf7..f6b68d1 100644 --- a/src/lfs/application.lua +++ b/src/lfs/application.lua @@ -4,6 +4,7 @@ local dht_sensors = require("dht_sensors") local ds18b20_sensors = require("ds18b20_sensors") local actuators = require("actuators") local settings = require("settings") +local ds18b20 = require("ds18b20") local sensorTimer = tmr.create() -- globals @@ -54,13 +55,11 @@ end if #ds18b20_sensors > 0 then local function ds18b20Callback(pin) - local callbackFn = function(i, rom, res, temp, temp_dec, par) - local temperature_string = temp .. "." .. math.abs(temp_dec) - print("Heap:", node.heap(), "Temperature:", temperature_string, "Resolution:", res) - if (res >= 12) then - table.insert(sensorPut, { pin = pin, temp = temperature_string, - addr = string.format("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", - string.match(rom, "(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)")) }) + local callbackFn = function(temps) + for addr,value in pairs(temps) do + print("Heap:", node.heap(), "Temperature:", value) + table.insert(sensorPut, { pin = pin, temp = value, + addr = string.format(('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(addr:byte(1,8)))}) end end return callbackFn @@ -71,10 +70,8 @@ if #ds18b20_sensors > 0 then pollInterval = (pollInterval > 0 and pollInterval or 3) * 60 * 1000 print("Heap:", node.heap(), "Polling DS18b20 on pin " .. sensor.pin .. " every " .. pollInterval .. "ms") local callbackFn = ds18b20Callback(sensor.pin) - ds18b20.setup(sensor.pin) - ds18b20.setting({}, 12) - tmr.create():alarm(pollInterval, tmr.ALARM_AUTO, function() ds18b20.read(callbackFn, {}) end) - ds18b20.read(callbackFn, {}) + tmr.create():alarm(pollInterval, tmr.ALARM_AUTO, function() ds18b20:read_temp(callbackFn, sensor.pin, ds18b20.C) end) + ds18b20:read_temp(callbackFn, sensor.pin, ds18b20.C) end end diff --git a/src/lfs/aws_iot.lua b/src/lfs/aws_iot.lua index 37d07d4..1b84402 100644 --- a/src/lfs/aws_iot.lua +++ b/src/lfs/aws_iot.lua @@ -72,7 +72,8 @@ local function startLoop() end) mqttTimeout:start() - c:connect(settings.endpoint) + -- stripping -ats uses the endpoint with a smaller cert chain + c:connect(string.gsub(settings.endpoint, "-ats", "")) end c:on('puback', function(_, message_id) diff --git a/src/lfs/device.lua b/src/lfs/device.lua index 4a42010..f4f942e 100644 --- a/src/lfs/device.lua +++ b/src/lfs/device.lua @@ -1,8 +1,8 @@ local me = { id = "uuid:8f655392-a778-4fee-97b9-4825918" .. string.format("%x", node.chipid()), name = "Konnected", - hwVersion = "2.3.0", - swVersion = "2.3.6", + hwVersion = "3.0.0", + swVersion = "3.0.0", http_port = math.floor(node.chipid()/1000) + 8000, urn = "urn:schemas-konnected-io:device:Security:1" } diff --git a/src/lfs/ds18b20.lua b/src/lfs/ds18b20.lua new file mode 100644 index 0000000..dcc4b06 --- /dev/null +++ b/src/lfs/ds18b20.lua @@ -0,0 +1,228 @@ +-------------------------------------------------------------------------------- +-- DS18B20 one wire module for NODEMCU +-- NODEMCU TEAM +-- LICENCE: http://opensource.org/licenses/MIT +-- @voborsky, @devsaurus, TerryE 26 Mar 2017 +-------------------------------------------------------------------------------- +local modname = ... + +-- Used modules and functions +local type, tostring, pcall, ipairs = + type, tostring, pcall, ipairs +-- Local functions +local ow_setup, ow_search, ow_select, ow_read, ow_read_bytes, ow_write, ow_crc8, + ow_reset, ow_reset_search, ow_skip, ow_depower = + ow.setup, ow.search, ow.select, ow.read, ow.read_bytes, ow.write, ow.crc8, + ow.reset, ow.reset_search, ow.skip, ow.depower + +local node_task_post, node_task_LOW_PRIORITY = node.task.post, node.task.LOW_PRIORITY +local string_char, string_dump = string.char, string.dump +local now, tmr_create, tmr_ALARM_SINGLE = tmr.now, tmr.create, tmr.ALARM_SINGLE +local table_sort, table_concat = table.sort, table.concat +local math_floor = math.floor +local file_open = file.open +local conversion + +local DS18B20FAMILY = 0x28 +local DS1920FAMILY = 0x10 -- and DS18S20 series +local CONVERT_T = 0x44 +local READ_SCRATCHPAD = 0xBE +local READ_POWERSUPPLY= 0xB4 +local MODE = 1 + +local pin, cb, unit = 3 +local status = {} + +local debugPrint = function() return end + +-------------------------------------------------------------------------------- +-- Implementation +-------------------------------------------------------------------------------- +local function enable_debug() + debugPrint = function (...) print(now(),' ', ...) end +end + +local function to_string(addr, esc) + if type(addr) == 'string' and #addr == 8 then + return ( esc == true and + '"\\%u\\%u\\%u\\%u\\%u\\%u\\%u\\%u"' or + '%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X '):format(addr:byte(1,8)) + else + return tostring(addr) + end +end + +local function readout(self) + local next = false + local sens = self.sens + local temp = self.temp + for i, s in ipairs(sens) do + if status[i] == 1 then + ow_reset(pin) + local addr = s:sub(1,8) + ow_select(pin, addr) -- select the sensor + ow_write(pin, READ_SCRATCHPAD, MODE) + local data = ow_read_bytes(pin, 9) + + local t=(data:byte(1)+data:byte(2)*256) + -- t is actually signed so process the sign bit and adjust for fractional bits + -- the DS18B20 family has 4 fractional bits and the DS18S20s, 1 fractional bit + t = ((t <= 32767) and t or t - 65536) * + ((addr:byte(1) == DS18B20FAMILY) and 625 or 5000) + local crc, b9 = ow_crc8(string.sub(data,1,8)), data:byte(9) + + if 1/2 == 0 then + -- integer version + if unit == 'F' then + t = (t * 18)/10 + 320000 + elseif unit == 'K' then + t = t + 2731500 + end + local sgn = t<0 and -1 or 1 + local tA = sgn*t + local tH=tA/10000 + local tL=(tA%10000)/1000 + ((tA%1000)/100 >= 5 and 1 or 0) + + if tH and (t~=850000) then + debugPrint(to_string(addr),(sgn<0 and "-" or "")..tH.."."..tL, crc, b9) + if crc==b9 then temp[addr]=(sgn<0 and "-" or "")..tH.."."..tL end + status[i] = 2 + end + -- end integer version + else + -- float version + t = t / 10000 + if math_floor(t)~=85 then + if unit == 'F' then + t = t * 18/10 + 32 + elseif unit == 'K' then + t = t + 27315/100 + end + debugPrint(to_string(addr), t, crc, b9) + if crc==b9 then temp[addr]=t end + status[i] = 2 + end + -- end float version + end + end + next = next or status[i] == 0 + end + if next then + node_task_post(node_task_LOW_PRIORITY, function() return conversion(self) end) + else + --sens = {} + if cb then + node_task_post(node_task_LOW_PRIORITY, function() return cb(temp) end) + end + end +end + +conversion = (function (self) + local sens = self.sens + local powered_only = true + for _, s in ipairs(sens) do powered_only = powered_only and s:byte(9) ~= 1 end + if powered_only then + debugPrint("starting conversion: all sensors") + ow_reset(pin) + ow_skip(pin) -- skip ROM selection, talk to all sensors + ow_write(pin, CONVERT_T, MODE) -- and start conversion + for i, _ in ipairs(sens) do status[i] = 1 end + else + local started = false + for i, s in ipairs(sens) do + if status[i] == 0 then + local addr, parasite = s:sub(1,8), s:byte(9) == 1 + if parasite and started then break end -- do not start concurrent conversion of powered and parasite + debugPrint("starting conversion:", to_string(addr), parasite and "parasite" or "") + ow_reset(pin) + ow_select(pin, addr) -- select the sensor + ow_write(pin, CONVERT_T, MODE) -- and start conversion + status[i] = 1 + if parasite then break end -- parasite sensor blocks bus during conversion + started = true + end + end + end + tmr_create():alarm(750, tmr_ALARM_SINGLE, function() return readout(self) end) +end) + +local function _search(self, lcb, lpin, search, save) + self.temp = {} + if search then self.sens = {}; status = {} end + local sens = self.sens + pin = lpin or pin + + local addr + if not search and #sens == 0 then + -- load addreses if available + debugPrint ("geting addreses from flash") + local s,check,a = pcall(dofile, "ds18b20_save.lc") + if s and check == "ds18b20" then + for i = 1, #a do sens[i] = a[i] end + end + debugPrint (#sens, "addreses found") + end + + ow_setup(pin) + if search or #sens == 0 then + ow_reset_search(pin) + -- ow_target_search(pin,0x28) + -- search the first device + addr = ow_search(pin) + else + for i, _ in ipairs(sens) do status[i] = 0 end + end + local function cycle() + if addr then + local crc=ow_crc8(addr:sub(1,7)) + if (crc==addr:byte(8)) and ((addr:byte(1)==DS1920FAMILY) or (addr:byte(1)==DS18B20FAMILY)) then + ow_reset(pin) + ow_select(pin, addr) + ow_write(pin, READ_POWERSUPPLY, MODE) + local parasite = (ow_read(pin)==0 and 1 or 0) + sens[#sens+1]= addr..string_char(parasite) + status[#sens] = 0 + debugPrint("contact: ", to_string(addr), parasite == 1 and "parasite" or "") + end + addr = ow_search(pin) + node_task_post(node_task_LOW_PRIORITY, cycle) + else + ow_depower(pin) + -- place powered sensors first + table_sort(sens, function(a, b) return a:byte(9)