diff --git a/.gitmodules b/.gitmodules index ca26e7d93..403d4ce64 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "tools/esptool"] path = tools/esptool url = https://github.com/espressif/esptool.git +[submodule "tools/sdk/uzlib"] + path = tools/sdk/uzlib + url = https://github.com/earlephilhower/uzlib.git diff --git a/.travis.yml b/.travis.yml index 7c50c68de..c187c2712 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,11 +24,15 @@ jobs: - name: "Platformio (1)" stage: build script: $TRAVIS_BUILD_DIR/tests/platformio.sh + install: + - sudo apt-get install python3-pip python3-setuptools env: - BUILD_PARITY=even - name: "Platformio (2)" stage: build script: $TRAVIS_BUILD_DIR/tests/platformio.sh + install: + - sudo apt-get install python3-pip python3-setuptools env: - BUILD_PARITY=odd @@ -76,6 +80,18 @@ jobs: env: - BUILD_PARITY=odd + - name: "Mac OSX can build sketches" + os: osx + stage: build + script: $TRAVIS_BUILD_DIR/tests/build.sh + env: MACOSX=1 BUILD_PARITY=custom mod=500 rem=1 + + - name: "Windows can build sketches" + os: windows + stage: build + script: $TRAVIS_BUILD_DIR/tests/build.sh + env: WINDOWS=1 BUILD_PARITY=custom mod=500 rem=1 + - name: "Host tests" stage: build script: $TRAVIS_BUILD_DIR/tests/ci/host_test.sh @@ -98,18 +114,6 @@ jobs: stage: build script: $TRAVIS_BUILD_DIR/tests/buildm.sh - - name: "Mac OSX can build sketches" - os: osx - stage: build - script: $TRAVIS_BUILD_DIR/tests/build.sh - env: MACOSX=1 BUILD_PARITY=custom mod=500 rem=1 - - - name: "Windows can build sketches" - os: windows - stage: build - script: $TRAVIS_BUILD_DIR/tests/build.sh - env: WINDOWS=1 BUILD_PARITY=custom mod=500 rem=1 - - name: "Boards" stage: build script: $TRAVIS_BUILD_DIR/tests/ci/build_boards.sh diff --git a/README.md b/README.md index 22a12463a..2b198c63b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Arduino core for ESP8266 WiFi chip # Quick links -- [Latest release documentation](https://arduino-esp8266.readthedocs.io/en/2.5.2/) +- [Latest release documentation](https://arduino-esp8266.readthedocs.io/en/2.6.3/) - [Current "git version" documentation](https://arduino-esp8266.readthedocs.io/en/latest/) - [Install git version](https://arduino-esp8266.readthedocs.io/en/latest/installing.html#using-git-version) ([sources](doc/installing.rst#using-git-version)) @@ -36,7 +36,7 @@ Starting with 1.6.4, Arduino allows installation of third-party platform package #### Latest release [![Latest release](https://img.shields.io/github/release/esp8266/Arduino.svg)](https://github.com/esp8266/Arduino/releases/latest/) Boards manager link: `https://arduino.esp8266.com/stable/package_esp8266com_index.json` -Documentation: [https://arduino-esp8266.readthedocs.io/en/2.5.2/](https://arduino-esp8266.readthedocs.io/en/2.5.2/) +Documentation: [https://arduino-esp8266.readthedocs.io/en/2.6.3/](https://arduino-esp8266.readthedocs.io/en/2.6.3/) ### Using git version [![Linux build status](https://travis-ci.org/esp8266/Arduino.svg)](https://travis-ci.org/esp8266/Arduino) @@ -106,7 +106,7 @@ Arduino IDE is developed and maintained by the Arduino team. The IDE is licensed ESP8266 core includes an xtensa gcc toolchain, which is also under GPL. -Esptool written by Christian Klippel is licensed under GPLv2, currently maintained by Ivan Grokhotkov: https://github.com/igrr/esptool-ck. +Esptool.py was initially created by Fredrik Ahlberg (@themadinventor, @kongo), and is currently maintained by Angus Gratton (@projectgus) under GPL 2.0 license. Espressif SDK included in this build is under Espressif MIT License. @@ -123,3 +123,15 @@ ESP8266 core files are licensed under LGPL. [BearSSL](https://bearssl.org) library written by Thomas Pornin, built from https://github.com/earlephilhower/bearssl-esp8266, is used in this project. It is distributed under the [MIT License](https://bearssl.org/#legal-details). [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md). + +[uzlib](https://github.com/pfalcon/uzlib) library written and (c) 2014-2018 Paul Sokolovsky, licensed under the ZLib license (https://www.zlib.net/zlib_license.html). uzlib is based on: tinf library by Joergen Ibsen (Deflate decompression); Deflate Static Huffman tree routines by Simon Tatham; LZ77 compressor by Paul Sokolovsky; with library integrated and maintained by Paul Sokolovsky. + +### Other useful links ### + +[Toolchain repo](https://github.com/earlephilhower/esp-quick-toolchain) + +[Lwip link layer repo](https://github.com/d-a-v/esp82xx-nonos-linklayer) + +[SoftwareSerial repo](https://github.com/plerup/espsoftwareserial) + +[Serial Monitor Arduino IDE plugin](https://github.com/mytrain/arduino-esp8266-serial-plugin) Original discussion [here](https://github.com/esp8266/Arduino/issues/1360), quick download [there](http://mytrain.fr/cms//images/mytrain/private/ESP8266SM.v3.zip). diff --git a/boards.txt b/boards.txt index e8e009f5f..bcbf48813 100644 --- a/boards.txt +++ b/boards.txt @@ -5,6 +5,8 @@ # menu.BoardModel=Model +menu.ESPModule=Module +menu.led=Builtin Led menu.baud=Upload Speed menu.xtal=CPU Frequency menu.CrystalFreq=Crystal Frequency @@ -12,13 +14,11 @@ menu.eesz=Flash Size menu.FlashMode=Flash Mode menu.FlashFreq=Flash Frequency menu.ResetMethod=Reset Method -menu.ESPModule=Module menu.dbg=Debug port menu.lvl=Debug Level menu.ip=lwIP Variant menu.vt=VTables menu.exception=Exceptions -menu.led=Builtin Led menu.wipe=Erase Flash menu.sdk=Espressif FW menu.ssl=SSL Support @@ -29,7 +29,7 @@ generic.build.board=ESP8266_GENERIC generic.upload.tool=esptool generic.upload.maximum_data_size=81920 generic.upload.wait_for_upload_port=true -generic.upload.erase_cmd=version +generic.upload.erase_cmd= generic.serial.disableDTR=true generic.serial.disableRTS=true generic.build.mcu=esp8266 @@ -61,14 +61,12 @@ generic.menu.ssl.all=All SSL ciphers (most compatible) generic.menu.ssl.all.build.sslflags= generic.menu.ssl.basic=Basic SSL ciphers (lower ROM use) generic.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -generic.menu.ResetMethod.ck=ck -generic.menu.ResetMethod.ck.upload.resetmethod=ck -generic.menu.ResetMethod.nodemcu=nodemcu -generic.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu -generic.menu.ResetMethod.none=none -generic.menu.ResetMethod.none.upload.resetmethod=none -generic.menu.ResetMethod.dtrset=dtrset -generic.menu.ResetMethod.dtrset.upload.resetmethod=dtrset +generic.menu.ResetMethod.nodemcu=dtr (aka nodemcu) +generic.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset +generic.menu.ResetMethod.ck=no dtr (aka ck) +generic.menu.ResetMethod.ck.upload.resetmethod=--before no_reset --after soft_reset +generic.menu.ResetMethod.nodtr_nosync=no dtr, no_sync +generic.menu.ResetMethod.nodtr_nosync.upload.resetmethod=--before no_reset_no_sync --after soft_reset generic.menu.CrystalFreq.26=26 MHz generic.menu.CrystalFreq.40=40 MHz generic.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266 @@ -374,10 +372,14 @@ generic.menu.led.15=15 generic.menu.led.15.build.led=-DLED_BUILTIN=15 generic.menu.led.16=16 generic.menu.led.16.build.led=-DLED_BUILTIN=16 -generic.menu.sdk.nonosdk222_100=nonos-sdk 2.2.1+100 (190703 approved) -generic.menu.sdk.nonosdk222_100.build.sdk=NONOSDK22x_190703 -generic.menu.sdk.nonosdk222_111=nonos-sdk 2.2.1+111 (191024 testing) -generic.menu.sdk.nonosdk222_111.build.sdk=NONOSDK22x_191024 +generic.menu.sdk.nonosdk_190703=nonos-sdk 2.2.1+100 (190703) +generic.menu.sdk.nonosdk_190703.build.sdk=NONOSDK22x_190703 +generic.menu.sdk.nonosdk_191122=nonos-sdk 2.2.1+119 (191122) +generic.menu.sdk.nonosdk_191122.build.sdk=NONOSDK22x_191122 +generic.menu.sdk.nonosdk_191105=nonos-sdk 2.2.1+113 (191105) +generic.menu.sdk.nonosdk_191105.build.sdk=NONOSDK22x_191105 +generic.menu.sdk.nonosdk_191024=nonos-sdk 2.2.1+111 (191024) +generic.menu.sdk.nonosdk_191024.build.sdk=NONOSDK22x_191024 generic.menu.sdk.nonosdk221=nonos-sdk 2.2.1 (legacy) generic.menu.sdk.nonosdk221.build.sdk=NONOSDK221 generic.menu.sdk.nonosdk3v0=nonos-sdk pre-3 (180626 known issues) @@ -472,7 +474,7 @@ generic.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO generic.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG generic.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG generic.menu.wipe.none=Only Sketch -generic.menu.wipe.none.upload.erase_cmd=version +generic.menu.wipe.none.upload.erase_cmd= generic.menu.wipe.sdk=Sketch + WiFi Settings generic.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 generic.menu.wipe.all=All Flash Contents @@ -503,7 +505,7 @@ esp8285.build.variant=esp8285 esp8285.upload.tool=esptool esp8285.upload.maximum_data_size=81920 esp8285.upload.wait_for_upload_port=true -esp8285.upload.erase_cmd=version +esp8285.upload.erase_cmd= esp8285.serial.disableDTR=true esp8285.serial.disableRTS=true esp8285.build.mcu=esp8266 @@ -534,14 +536,12 @@ esp8285.menu.ssl.all=All SSL ciphers (most compatible) esp8285.menu.ssl.all.build.sslflags= esp8285.menu.ssl.basic=Basic SSL ciphers (lower ROM use) esp8285.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -esp8285.menu.ResetMethod.ck=ck -esp8285.menu.ResetMethod.ck.upload.resetmethod=ck -esp8285.menu.ResetMethod.nodemcu=nodemcu -esp8285.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu -esp8285.menu.ResetMethod.none=none -esp8285.menu.ResetMethod.none.upload.resetmethod=none -esp8285.menu.ResetMethod.dtrset=dtrset -esp8285.menu.ResetMethod.dtrset.upload.resetmethod=dtrset +esp8285.menu.ResetMethod.nodemcu=dtr (aka nodemcu) +esp8285.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset +esp8285.menu.ResetMethod.ck=no dtr (aka ck) +esp8285.menu.ResetMethod.ck.upload.resetmethod=--before no_reset --after soft_reset +esp8285.menu.ResetMethod.nodtr_nosync=no dtr, no_sync +esp8285.menu.ResetMethod.nodtr_nosync.upload.resetmethod=--before no_reset_no_sync --after soft_reset esp8285.menu.CrystalFreq.26=26 MHz esp8285.menu.CrystalFreq.40=40 MHz esp8285.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266 @@ -749,7 +749,7 @@ esp8285.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO esp8285.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG esp8285.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG esp8285.menu.wipe.none=Only Sketch -esp8285.menu.wipe.none.upload.erase_cmd=version +esp8285.menu.wipe.none.upload.erase_cmd= esp8285.menu.wipe.sdk=Sketch + WiFi Settings esp8285.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 esp8285.menu.wipe.all=All Flash Contents @@ -778,9 +778,9 @@ espduino.name=ESPDuino (ESP-13 Module) espduino.build.board=ESP8266_ESP13 espduino.build.variant=ESPDuino espduino.menu.ResetMethod.v1=ESPduino-V1 -espduino.menu.ResetMethod.v1.upload.resetmethod=ck +espduino.menu.ResetMethod.v1.upload.resetmethod=--before no_reset --after soft_reset espduino.menu.ResetMethod.v2=ESPduino-V2 -espduino.menu.ResetMethod.v2.upload.resetmethod=nodemcu +espduino.menu.ResetMethod.v2.upload.resetmethod=--before default_reset --after hard_reset espduino.menu.UploadTool.espota=OTA espduino.menu.UploadTool.espota.upload.tool=espota espduino.menu.UploadTool.esptool=Serial @@ -789,7 +789,7 @@ espduino.menu.UploadTool.esptool.upload.verbose=--trace espduino.upload.tool=esptool espduino.upload.maximum_data_size=81920 espduino.upload.wait_for_upload_port=true -espduino.upload.erase_cmd=version +espduino.upload.erase_cmd= espduino.serial.disableDTR=true espduino.serial.disableRTS=true espduino.build.mcu=esp8266 @@ -950,7 +950,7 @@ espduino.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAO espduino.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG espduino.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG espduino.menu.wipe.none=Only Sketch -espduino.menu.wipe.none.upload.erase_cmd=version +espduino.menu.wipe.none.upload.erase_cmd= espduino.menu.wipe.sdk=Sketch + WiFi Settings espduino.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 espduino.menu.wipe.all=All Flash Contents @@ -981,7 +981,7 @@ huzzah.build.variant=adafruit huzzah.upload.tool=esptool huzzah.upload.maximum_data_size=81920 huzzah.upload.wait_for_upload_port=true -huzzah.upload.erase_cmd=version +huzzah.upload.erase_cmd= huzzah.serial.disableDTR=true huzzah.serial.disableRTS=true huzzah.build.mcu=esp8266 @@ -1012,7 +1012,7 @@ huzzah.menu.ssl.all=All SSL ciphers (most compatible) huzzah.menu.ssl.all.build.sslflags= huzzah.menu.ssl.basic=Basic SSL ciphers (lower ROM use) huzzah.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -huzzah.upload.resetmethod=nodemcu +huzzah.upload.resetmethod=--before default_reset --after hard_reset huzzah.build.flash_mode=qio huzzah.build.flash_flags=-DFLASHMODE_QIO huzzah.build.flash_freq=40 @@ -1143,7 +1143,7 @@ huzzah.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOM huzzah.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG huzzah.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG huzzah.menu.wipe.none=Only Sketch -huzzah.menu.wipe.none.upload.erase_cmd=version +huzzah.menu.wipe.none.upload.erase_cmd= huzzah.menu.wipe.sdk=Sketch + WiFi Settings huzzah.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 huzzah.menu.wipe.all=All Flash Contents @@ -1174,7 +1174,7 @@ inventone.build.variant=inventone inventone.upload.tool=esptool inventone.upload.maximum_data_size=81920 inventone.upload.wait_for_upload_port=true -inventone.upload.erase_cmd=version +inventone.upload.erase_cmd= inventone.serial.disableDTR=true inventone.serial.disableRTS=true inventone.build.mcu=esp8266 @@ -1205,7 +1205,7 @@ inventone.menu.ssl.all=All SSL ciphers (most compatible) inventone.menu.ssl.all.build.sslflags= inventone.menu.ssl.basic=Basic SSL ciphers (lower ROM use) inventone.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -inventone.upload.resetmethod=nodemcu +inventone.upload.resetmethod=--before default_reset --after hard_reset inventone.build.flash_mode=dio inventone.build.flash_flags=-DFLASHMODE_DIO inventone.build.flash_freq=40 @@ -1336,7 +1336,7 @@ inventone.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTA inventone.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG inventone.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG inventone.menu.wipe.none=Only Sketch -inventone.menu.wipe.none.upload.erase_cmd=version +inventone.menu.wipe.none.upload.erase_cmd= inventone.menu.wipe.sdk=Sketch + WiFi Settings inventone.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 inventone.menu.wipe.all=All Flash Contents @@ -1367,7 +1367,7 @@ cw01.build.variant=xinabox cw01.upload.tool=esptool cw01.upload.maximum_data_size=81920 cw01.upload.wait_for_upload_port=true -cw01.upload.erase_cmd=version +cw01.upload.erase_cmd= cw01.serial.disableDTR=true cw01.serial.disableRTS=true cw01.build.mcu=esp8266 @@ -1398,7 +1398,7 @@ cw01.menu.ssl.all=All SSL ciphers (most compatible) cw01.menu.ssl.all.build.sslflags= cw01.menu.ssl.basic=Basic SSL ciphers (lower ROM use) cw01.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -cw01.upload.resetmethod=nodemcu +cw01.upload.resetmethod=--before default_reset --after hard_reset cw01.menu.CrystalFreq.26=26 MHz cw01.menu.CrystalFreq.40=40 MHz cw01.menu.CrystalFreq.40.build.extra_flags=-DF_CRYSTAL=40000000 -DESP8266 @@ -1532,7 +1532,7 @@ cw01.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMD cw01.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG cw01.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG cw01.menu.wipe.none=Only Sketch -cw01.menu.wipe.none.upload.erase_cmd=version +cw01.menu.wipe.none.upload.erase_cmd= cw01.menu.wipe.sdk=Sketch + WiFi Settings cw01.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 cw01.menu.wipe.all=All Flash Contents @@ -1563,7 +1563,7 @@ espresso_lite_v1.build.variant=espresso_lite_v1 espresso_lite_v1.upload.tool=esptool espresso_lite_v1.upload.maximum_data_size=81920 espresso_lite_v1.upload.wait_for_upload_port=true -espresso_lite_v1.upload.erase_cmd=version +espresso_lite_v1.upload.erase_cmd= espresso_lite_v1.serial.disableDTR=true espresso_lite_v1.serial.disableRTS=true espresso_lite_v1.build.mcu=esp8266 @@ -1634,10 +1634,10 @@ espresso_lite_v1.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld espresso_lite_v1.menu.eesz.4M.build.spiffs_pagesize=256 espresso_lite_v1.menu.eesz.4M.upload.maximum_size=1044464 espresso_lite_v1.menu.eesz.4M.build.rfcal_addr=0x3FC000 -espresso_lite_v1.menu.ResetMethod.ck=ck -espresso_lite_v1.menu.ResetMethod.ck.upload.resetmethod=ck -espresso_lite_v1.menu.ResetMethod.nodemcu=nodemcu -espresso_lite_v1.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu +espresso_lite_v1.menu.ResetMethod.nodemcu=dtr (aka nodemcu) +espresso_lite_v1.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset +espresso_lite_v1.menu.ResetMethod.ck=no dtr (aka ck) +espresso_lite_v1.menu.ResetMethod.ck.upload.resetmethod=--before no_reset --after soft_reset espresso_lite_v1.menu.ip.lm2f=v2 Lower Memory espresso_lite_v1.menu.ip.lm2f.build.lwip_include=lwip2/include espresso_lite_v1.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat @@ -1728,7 +1728,7 @@ espresso_lite_v1.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPD espresso_lite_v1.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG espresso_lite_v1.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG espresso_lite_v1.menu.wipe.none=Only Sketch -espresso_lite_v1.menu.wipe.none.upload.erase_cmd=version +espresso_lite_v1.menu.wipe.none.upload.erase_cmd= espresso_lite_v1.menu.wipe.sdk=Sketch + WiFi Settings espresso_lite_v1.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 espresso_lite_v1.menu.wipe.all=All Flash Contents @@ -1759,7 +1759,7 @@ espresso_lite_v2.build.variant=espresso_lite_v2 espresso_lite_v2.upload.tool=esptool espresso_lite_v2.upload.maximum_data_size=81920 espresso_lite_v2.upload.wait_for_upload_port=true -espresso_lite_v2.upload.erase_cmd=version +espresso_lite_v2.upload.erase_cmd= espresso_lite_v2.serial.disableDTR=true espresso_lite_v2.serial.disableRTS=true espresso_lite_v2.build.mcu=esp8266 @@ -1830,10 +1830,10 @@ espresso_lite_v2.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld espresso_lite_v2.menu.eesz.4M.build.spiffs_pagesize=256 espresso_lite_v2.menu.eesz.4M.upload.maximum_size=1044464 espresso_lite_v2.menu.eesz.4M.build.rfcal_addr=0x3FC000 -espresso_lite_v2.menu.ResetMethod.ck=ck -espresso_lite_v2.menu.ResetMethod.ck.upload.resetmethod=ck -espresso_lite_v2.menu.ResetMethod.nodemcu=nodemcu -espresso_lite_v2.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu +espresso_lite_v2.menu.ResetMethod.nodemcu=dtr (aka nodemcu) +espresso_lite_v2.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset +espresso_lite_v2.menu.ResetMethod.ck=no dtr (aka ck) +espresso_lite_v2.menu.ResetMethod.ck.upload.resetmethod=--before no_reset --after soft_reset espresso_lite_v2.menu.ip.lm2f=v2 Lower Memory espresso_lite_v2.menu.ip.lm2f.build.lwip_include=lwip2/include espresso_lite_v2.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat @@ -1924,7 +1924,7 @@ espresso_lite_v2.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPD espresso_lite_v2.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG espresso_lite_v2.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG espresso_lite_v2.menu.wipe.none=Only Sketch -espresso_lite_v2.menu.wipe.none.upload.erase_cmd=version +espresso_lite_v2.menu.wipe.none.upload.erase_cmd= espresso_lite_v2.menu.wipe.sdk=Sketch + WiFi Settings espresso_lite_v2.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 espresso_lite_v2.menu.wipe.all=All Flash Contents @@ -1955,7 +1955,7 @@ phoenix_v1.build.variant=phoenix_v1 phoenix_v1.upload.tool=esptool phoenix_v1.upload.maximum_data_size=81920 phoenix_v1.upload.wait_for_upload_port=true -phoenix_v1.upload.erase_cmd=version +phoenix_v1.upload.erase_cmd= phoenix_v1.serial.disableDTR=true phoenix_v1.serial.disableRTS=true phoenix_v1.build.mcu=esp8266 @@ -2026,10 +2026,10 @@ phoenix_v1.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld phoenix_v1.menu.eesz.4M.build.spiffs_pagesize=256 phoenix_v1.menu.eesz.4M.upload.maximum_size=1044464 phoenix_v1.menu.eesz.4M.build.rfcal_addr=0x3FC000 -phoenix_v1.menu.ResetMethod.ck=ck -phoenix_v1.menu.ResetMethod.ck.upload.resetmethod=ck -phoenix_v1.menu.ResetMethod.nodemcu=nodemcu -phoenix_v1.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu +phoenix_v1.menu.ResetMethod.nodemcu=dtr (aka nodemcu) +phoenix_v1.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset +phoenix_v1.menu.ResetMethod.ck=no dtr (aka ck) +phoenix_v1.menu.ResetMethod.ck.upload.resetmethod=--before no_reset --after soft_reset phoenix_v1.menu.ip.lm2f=v2 Lower Memory phoenix_v1.menu.ip.lm2f.build.lwip_include=lwip2/include phoenix_v1.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat @@ -2120,7 +2120,7 @@ phoenix_v1.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROT phoenix_v1.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG phoenix_v1.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG phoenix_v1.menu.wipe.none=Only Sketch -phoenix_v1.menu.wipe.none.upload.erase_cmd=version +phoenix_v1.menu.wipe.none.upload.erase_cmd= phoenix_v1.menu.wipe.sdk=Sketch + WiFi Settings phoenix_v1.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 phoenix_v1.menu.wipe.all=All Flash Contents @@ -2151,7 +2151,7 @@ phoenix_v2.build.variant=phoenix_v2 phoenix_v2.upload.tool=esptool phoenix_v2.upload.maximum_data_size=81920 phoenix_v2.upload.wait_for_upload_port=true -phoenix_v2.upload.erase_cmd=version +phoenix_v2.upload.erase_cmd= phoenix_v2.serial.disableDTR=true phoenix_v2.serial.disableRTS=true phoenix_v2.build.mcu=esp8266 @@ -2222,10 +2222,10 @@ phoenix_v2.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld phoenix_v2.menu.eesz.4M.build.spiffs_pagesize=256 phoenix_v2.menu.eesz.4M.upload.maximum_size=1044464 phoenix_v2.menu.eesz.4M.build.rfcal_addr=0x3FC000 -phoenix_v2.menu.ResetMethod.ck=ck -phoenix_v2.menu.ResetMethod.ck.upload.resetmethod=ck -phoenix_v2.menu.ResetMethod.nodemcu=nodemcu -phoenix_v2.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu +phoenix_v2.menu.ResetMethod.nodemcu=dtr (aka nodemcu) +phoenix_v2.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset +phoenix_v2.menu.ResetMethod.ck=no dtr (aka ck) +phoenix_v2.menu.ResetMethod.ck.upload.resetmethod=--before no_reset --after soft_reset phoenix_v2.menu.ip.lm2f=v2 Lower Memory phoenix_v2.menu.ip.lm2f.build.lwip_include=lwip2/include phoenix_v2.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat @@ -2316,7 +2316,7 @@ phoenix_v2.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROT phoenix_v2.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG phoenix_v2.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG phoenix_v2.menu.wipe.none=Only Sketch -phoenix_v2.menu.wipe.none.upload.erase_cmd=version +phoenix_v2.menu.wipe.none.upload.erase_cmd= phoenix_v2.menu.wipe.sdk=Sketch + WiFi Settings phoenix_v2.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 phoenix_v2.menu.wipe.all=All Flash Contents @@ -2347,7 +2347,7 @@ nodemcu.build.variant=nodemcu nodemcu.upload.tool=esptool nodemcu.upload.maximum_data_size=81920 nodemcu.upload.wait_for_upload_port=true -nodemcu.upload.erase_cmd=version +nodemcu.upload.erase_cmd= nodemcu.serial.disableDTR=true nodemcu.serial.disableRTS=true nodemcu.build.mcu=esp8266 @@ -2378,7 +2378,7 @@ nodemcu.menu.ssl.all=All SSL ciphers (most compatible) nodemcu.menu.ssl.all.build.sslflags= nodemcu.menu.ssl.basic=Basic SSL ciphers (lower ROM use) nodemcu.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -nodemcu.upload.resetmethod=nodemcu +nodemcu.upload.resetmethod=--before default_reset --after hard_reset nodemcu.build.flash_mode=qio nodemcu.build.flash_flags=-DFLASHMODE_QIO nodemcu.build.flash_freq=40 @@ -2509,7 +2509,7 @@ nodemcu.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO nodemcu.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG nodemcu.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG nodemcu.menu.wipe.none=Only Sketch -nodemcu.menu.wipe.none.upload.erase_cmd=version +nodemcu.menu.wipe.none.upload.erase_cmd= nodemcu.menu.wipe.sdk=Sketch + WiFi Settings nodemcu.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 nodemcu.menu.wipe.all=All Flash Contents @@ -2540,7 +2540,7 @@ nodemcuv2.build.variant=nodemcu nodemcuv2.upload.tool=esptool nodemcuv2.upload.maximum_data_size=81920 nodemcuv2.upload.wait_for_upload_port=true -nodemcuv2.upload.erase_cmd=version +nodemcuv2.upload.erase_cmd= nodemcuv2.serial.disableDTR=true nodemcuv2.serial.disableRTS=true nodemcuv2.build.mcu=esp8266 @@ -2571,7 +2571,7 @@ nodemcuv2.menu.ssl.all=All SSL ciphers (most compatible) nodemcuv2.menu.ssl.all.build.sslflags= nodemcuv2.menu.ssl.basic=Basic SSL ciphers (lower ROM use) nodemcuv2.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -nodemcuv2.upload.resetmethod=nodemcu +nodemcuv2.upload.resetmethod=--before default_reset --after hard_reset nodemcuv2.build.flash_mode=dio nodemcuv2.build.flash_flags=-DFLASHMODE_DIO nodemcuv2.build.flash_freq=40 @@ -2612,6 +2612,10 @@ nodemcuv2.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld nodemcuv2.menu.eesz.4M.build.spiffs_pagesize=256 nodemcuv2.menu.eesz.4M.upload.maximum_size=1044464 nodemcuv2.menu.eesz.4M.build.rfcal_addr=0x3FC000 +nodemcuv2.menu.led.2=2 +nodemcuv2.menu.led.2.build.led=-DLED_BUILTIN=2 +nodemcuv2.menu.led.16=16 +nodemcuv2.menu.led.16.build.led=-DLED_BUILTIN=16 nodemcuv2.menu.ip.lm2f=v2 Lower Memory nodemcuv2.menu.ip.lm2f.build.lwip_include=lwip2/include nodemcuv2.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat @@ -2702,7 +2706,7 @@ nodemcuv2.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTA nodemcuv2.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG nodemcuv2.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG nodemcuv2.menu.wipe.none=Only Sketch -nodemcuv2.menu.wipe.none.upload.erase_cmd=version +nodemcuv2.menu.wipe.none.upload.erase_cmd= nodemcuv2.menu.wipe.sdk=Sketch + WiFi Settings nodemcuv2.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 nodemcuv2.menu.wipe.all=All Flash Contents @@ -2733,7 +2737,7 @@ modwifi.build.variant=modwifi modwifi.upload.tool=esptool modwifi.upload.maximum_data_size=81920 modwifi.upload.wait_for_upload_port=true -modwifi.upload.erase_cmd=version +modwifi.upload.erase_cmd= modwifi.serial.disableDTR=true modwifi.serial.disableRTS=true modwifi.build.mcu=esp8266 @@ -2764,7 +2768,7 @@ modwifi.menu.ssl.all=All SSL ciphers (most compatible) modwifi.menu.ssl.all.build.sslflags= modwifi.menu.ssl.basic=Basic SSL ciphers (lower ROM use) modwifi.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -modwifi.upload.resetmethod=ck +modwifi.upload.resetmethod=--before no_reset --after soft_reset modwifi.build.flash_mode=qio modwifi.build.flash_flags=-DFLASHMODE_QIO modwifi.build.flash_freq=40 @@ -2915,7 +2919,7 @@ modwifi.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO modwifi.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG modwifi.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG modwifi.menu.wipe.none=Only Sketch -modwifi.menu.wipe.none.upload.erase_cmd=version +modwifi.menu.wipe.none.upload.erase_cmd= modwifi.menu.wipe.sdk=Sketch + WiFi Settings modwifi.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 modwifi.menu.wipe.all=All Flash Contents @@ -2946,7 +2950,7 @@ thing.build.variant=thing thing.upload.tool=esptool thing.upload.maximum_data_size=81920 thing.upload.wait_for_upload_port=true -thing.upload.erase_cmd=version +thing.upload.erase_cmd= thing.serial.disableDTR=true thing.serial.disableRTS=true thing.build.mcu=esp8266 @@ -2977,7 +2981,7 @@ thing.menu.ssl.all=All SSL ciphers (most compatible) thing.menu.ssl.all.build.sslflags= thing.menu.ssl.basic=Basic SSL ciphers (lower ROM use) thing.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -thing.upload.resetmethod=ck +thing.upload.resetmethod=--before no_reset --after soft_reset thing.build.flash_mode=qio thing.build.flash_flags=-DFLASHMODE_QIO thing.build.flash_freq=40 @@ -3108,7 +3112,7 @@ thing.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMM thing.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG thing.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG thing.menu.wipe.none=Only Sketch -thing.menu.wipe.none.upload.erase_cmd=version +thing.menu.wipe.none.upload.erase_cmd= thing.menu.wipe.sdk=Sketch + WiFi Settings thing.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 thing.menu.wipe.all=All Flash Contents @@ -3139,7 +3143,7 @@ thingdev.build.variant=thing thingdev.upload.tool=esptool thingdev.upload.maximum_data_size=81920 thingdev.upload.wait_for_upload_port=true -thingdev.upload.erase_cmd=version +thingdev.upload.erase_cmd= thingdev.serial.disableDTR=true thingdev.serial.disableRTS=true thingdev.build.mcu=esp8266 @@ -3170,7 +3174,7 @@ thingdev.menu.ssl.all=All SSL ciphers (most compatible) thingdev.menu.ssl.all.build.sslflags= thingdev.menu.ssl.basic=Basic SSL ciphers (lower ROM use) thingdev.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -thingdev.upload.resetmethod=nodemcu +thingdev.upload.resetmethod=--before default_reset --after hard_reset thingdev.build.flash_mode=dio thingdev.build.flash_flags=-DFLASHMODE_DIO thingdev.build.flash_freq=40 @@ -3301,7 +3305,7 @@ thingdev.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAO thingdev.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG thingdev.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG thingdev.menu.wipe.none=Only Sketch -thingdev.menu.wipe.none.upload.erase_cmd=version +thingdev.menu.wipe.none.upload.erase_cmd= thingdev.menu.wipe.sdk=Sketch + WiFi Settings thingdev.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 thingdev.menu.wipe.all=All Flash Contents @@ -3325,13 +3329,206 @@ thingdev.menu.baud.921600.upload.speed=921600 thingdev.menu.baud.3000000=3000000 thingdev.menu.baud.3000000.upload.speed=3000000 +############################################################## +blynk.name=SparkFun Blynk Board +blynk.build.board=ESP8266_THING +blynk.build.variant=thing +blynk.upload.tool=esptool +blynk.upload.maximum_data_size=81920 +blynk.upload.wait_for_upload_port=true +blynk.upload.erase_cmd= +blynk.serial.disableDTR=true +blynk.serial.disableRTS=true +blynk.build.mcu=esp8266 +blynk.build.core=esp8266 +blynk.build.spiffs_pagesize=256 +blynk.build.debug_port= +blynk.build.debug_level= +blynk.menu.xtal.80=80 MHz +blynk.menu.xtal.80.build.f_cpu=80000000L +blynk.menu.xtal.160=160 MHz +blynk.menu.xtal.160.build.f_cpu=160000000L +blynk.menu.vt.flash=Flash +blynk.menu.vt.flash.build.vtable_flags=-DVTABLES_IN_FLASH +blynk.menu.vt.heap=Heap +blynk.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM +blynk.menu.vt.iram=IRAM +blynk.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM +blynk.menu.exception.legacy=Legacy (new can return nullptr) +blynk.menu.exception.legacy.build.exception_flags=-fno-exceptions +blynk.menu.exception.legacy.build.stdcpp_lib=-lstdc++ +blynk.menu.exception.disabled=Disabled (new can abort) +blynk.menu.exception.disabled.build.exception_flags=-fno-exceptions -DNEW_OOM_ABORT +blynk.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +blynk.menu.exception.enabled=Enabled +blynk.menu.exception.enabled.build.exception_flags=-fexceptions +blynk.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc +blynk.menu.ssl.all=All SSL ciphers (most compatible) +blynk.menu.ssl.all.build.sslflags= +blynk.menu.ssl.basic=Basic SSL ciphers (lower ROM use) +blynk.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +blynk.upload.resetmethod=--before default_reset --after hard_reset +blynk.build.flash_mode=qio +blynk.build.flash_flags=-DFLASHMODE_QIO +blynk.build.flash_freq=40 +blynk.menu.eesz.4M2M=4MB (FS:2MB OTA:~1019KB) +blynk.menu.eesz.4M2M.build.flash_size=4M +blynk.menu.eesz.4M2M.build.flash_size_bytes=0x400000 +blynk.menu.eesz.4M2M.build.flash_ld=eagle.flash.4m2m.ld +blynk.menu.eesz.4M2M.build.spiffs_pagesize=256 +blynk.menu.eesz.4M2M.upload.maximum_size=1044464 +blynk.menu.eesz.4M2M.build.rfcal_addr=0x3FC000 +blynk.menu.eesz.4M2M.build.spiffs_start=0x200000 +blynk.menu.eesz.4M2M.build.spiffs_end=0x3FA000 +blynk.menu.eesz.4M2M.build.spiffs_blocksize=8192 +blynk.menu.eesz.4M3M=4MB (FS:3MB OTA:~512KB) +blynk.menu.eesz.4M3M.build.flash_size=4M +blynk.menu.eesz.4M3M.build.flash_size_bytes=0x400000 +blynk.menu.eesz.4M3M.build.flash_ld=eagle.flash.4m3m.ld +blynk.menu.eesz.4M3M.build.spiffs_pagesize=256 +blynk.menu.eesz.4M3M.upload.maximum_size=1044464 +blynk.menu.eesz.4M3M.build.rfcal_addr=0x3FC000 +blynk.menu.eesz.4M3M.build.spiffs_start=0x100000 +blynk.menu.eesz.4M3M.build.spiffs_end=0x3FA000 +blynk.menu.eesz.4M3M.build.spiffs_blocksize=8192 +blynk.menu.eesz.4M1M=4MB (FS:1MB OTA:~1019KB) +blynk.menu.eesz.4M1M.build.flash_size=4M +blynk.menu.eesz.4M1M.build.flash_size_bytes=0x400000 +blynk.menu.eesz.4M1M.build.flash_ld=eagle.flash.4m1m.ld +blynk.menu.eesz.4M1M.build.spiffs_pagesize=256 +blynk.menu.eesz.4M1M.upload.maximum_size=1044464 +blynk.menu.eesz.4M1M.build.rfcal_addr=0x3FC000 +blynk.menu.eesz.4M1M.build.spiffs_start=0x300000 +blynk.menu.eesz.4M1M.build.spiffs_end=0x3FA000 +blynk.menu.eesz.4M1M.build.spiffs_blocksize=8192 +blynk.menu.eesz.4M=4MB (FS:none OTA:~1019KB) +blynk.menu.eesz.4M.build.flash_size=4M +blynk.menu.eesz.4M.build.flash_size_bytes=0x400000 +blynk.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld +blynk.menu.eesz.4M.build.spiffs_pagesize=256 +blynk.menu.eesz.4M.upload.maximum_size=1044464 +blynk.menu.eesz.4M.build.rfcal_addr=0x3FC000 +blynk.menu.ip.lm2f=v2 Lower Memory +blynk.menu.ip.lm2f.build.lwip_include=lwip2/include +blynk.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat +blynk.menu.ip.lm2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +blynk.menu.ip.hb2f=v2 Higher Bandwidth +blynk.menu.ip.hb2f.build.lwip_include=lwip2/include +blynk.menu.ip.hb2f.build.lwip_lib=-llwip2-1460-feat +blynk.menu.ip.hb2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +blynk.menu.ip.lm2n=v2 Lower Memory (no features) +blynk.menu.ip.lm2n.build.lwip_include=lwip2/include +blynk.menu.ip.lm2n.build.lwip_lib=-llwip2-536 +blynk.menu.ip.lm2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +blynk.menu.ip.hb2n=v2 Higher Bandwidth (no features) +blynk.menu.ip.hb2n.build.lwip_include=lwip2/include +blynk.menu.ip.hb2n.build.lwip_lib=-llwip2-1460 +blynk.menu.ip.hb2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +blynk.menu.ip.lm6f=v2 IPv6 Lower Memory +blynk.menu.ip.lm6f.build.lwip_include=lwip2/include +blynk.menu.ip.lm6f.build.lwip_lib=-llwip6-536-feat +blynk.menu.ip.lm6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +blynk.menu.ip.hb6f=v2 IPv6 Higher Bandwidth +blynk.menu.ip.hb6f.build.lwip_include=lwip2/include +blynk.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat +blynk.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +blynk.menu.ip.hb1=v1.4 Higher Bandwidth +blynk.menu.ip.hb1.build.lwip_lib=-llwip_gcc +blynk.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC +blynk.menu.ip.src=v1.4 Compile from source +blynk.menu.ip.src.build.lwip_lib=-llwip_src +blynk.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC +blynk.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" +blynk.menu.dbg.Disabled=Disabled +blynk.menu.dbg.Disabled.build.debug_port= +blynk.menu.dbg.Serial=Serial +blynk.menu.dbg.Serial.build.debug_port=-DDEBUG_ESP_PORT=Serial +blynk.menu.dbg.Serial1=Serial1 +blynk.menu.dbg.Serial1.build.debug_port=-DDEBUG_ESP_PORT=Serial1 +blynk.menu.lvl.None____=None +blynk.menu.lvl.None____.build.debug_level= +blynk.menu.lvl.SSL=SSL +blynk.menu.lvl.SSL.build.debug_level= -DDEBUG_ESP_SSL +blynk.menu.lvl.TLS_MEM=TLS_MEM +blynk.menu.lvl.TLS_MEM.build.debug_level= -DDEBUG_ESP_TLS_MEM +blynk.menu.lvl.HTTP_CLIENT=HTTP_CLIENT +blynk.menu.lvl.HTTP_CLIENT.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT +blynk.menu.lvl.HTTP_SERVER=HTTP_SERVER +blynk.menu.lvl.HTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.SSLTLS_MEM=SSL+TLS_MEM +blynk.menu.lvl.SSLTLS_MEM.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM +blynk.menu.lvl.SSLHTTP_CLIENT=SSL+HTTP_CLIENT +blynk.menu.lvl.SSLHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT +blynk.menu.lvl.SSLHTTP_SERVER=SSL+HTTP_SERVER +blynk.menu.lvl.SSLHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.TLS_MEMHTTP_CLIENT=TLS_MEM+HTTP_CLIENT +blynk.menu.lvl.TLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +blynk.menu.lvl.TLS_MEMHTTP_SERVER=TLS_MEM+HTTP_SERVER +blynk.menu.lvl.TLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.HTTP_CLIENTHTTP_SERVER=HTTP_CLIENT+HTTP_SERVER +blynk.menu.lvl.HTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.SSLTLS_MEMHTTP_CLIENT=SSL+TLS_MEM+HTTP_CLIENT +blynk.menu.lvl.SSLTLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +blynk.menu.lvl.SSLTLS_MEMHTTP_SERVER=SSL+TLS_MEM+HTTP_SERVER +blynk.menu.lvl.SSLTLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER=SSL+HTTP_CLIENT+HTTP_SERVER +blynk.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER=TLS_MEM+HTTP_CLIENT+HTTP_SERVER +blynk.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER +blynk.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +blynk.menu.lvl.CORE=CORE +blynk.menu.lvl.CORE.build.debug_level= -DDEBUG_ESP_CORE +blynk.menu.lvl.WIFI=WIFI +blynk.menu.lvl.WIFI.build.debug_level= -DDEBUG_ESP_WIFI +blynk.menu.lvl.HTTP_UPDATE=HTTP_UPDATE +blynk.menu.lvl.HTTP_UPDATE.build.debug_level= -DDEBUG_ESP_HTTP_UPDATE +blynk.menu.lvl.UPDATER=UPDATER +blynk.menu.lvl.UPDATER.build.debug_level= -DDEBUG_ESP_UPDATER +blynk.menu.lvl.OTA=OTA +blynk.menu.lvl.OTA.build.debug_level= -DDEBUG_ESP_OTA +blynk.menu.lvl.OOM=OOM +blynk.menu.lvl.OOM.build.debug_level= -DDEBUG_ESP_OOM +blynk.menu.lvl.MDNS=MDNS +blynk.menu.lvl.MDNS.build.debug_level= -DDEBUG_ESP_MDNS +blynk.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +blynk.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +blynk.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER+CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +blynk.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +blynk.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG +blynk.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG +blynk.menu.wipe.none=Only Sketch +blynk.menu.wipe.none.upload.erase_cmd= +blynk.menu.wipe.sdk=Sketch + WiFi Settings +blynk.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 +blynk.menu.wipe.all=All Flash Contents +blynk.menu.wipe.all.upload.erase_cmd=erase_flash +blynk.menu.baud.115200=115200 +blynk.menu.baud.115200.upload.speed=115200 +blynk.menu.baud.57600=57600 +blynk.menu.baud.57600.upload.speed=57600 +blynk.menu.baud.230400.linux=230400 +blynk.menu.baud.230400.macosx=230400 +blynk.menu.baud.230400.upload.speed=230400 +blynk.menu.baud.256000.windows=256000 +blynk.menu.baud.256000.upload.speed=256000 +blynk.menu.baud.460800.linux=460800 +blynk.menu.baud.460800.macosx=460800 +blynk.menu.baud.460800.upload.speed=460800 +blynk.menu.baud.512000.windows=512000 +blynk.menu.baud.512000.upload.speed=512000 +blynk.menu.baud.921600=921600 +blynk.menu.baud.921600.upload.speed=921600 +blynk.menu.baud.3000000=3000000 +blynk.menu.baud.3000000.upload.speed=3000000 + ############################################################## esp210.name=SweetPea ESP-210 esp210.build.board=ESP8266_ESP210 esp210.upload.tool=esptool esp210.upload.maximum_data_size=81920 esp210.upload.wait_for_upload_port=true -esp210.upload.erase_cmd=version +esp210.upload.erase_cmd= esp210.serial.disableDTR=true esp210.serial.disableRTS=true esp210.build.mcu=esp8266 @@ -3363,7 +3560,7 @@ esp210.menu.ssl.all=All SSL ciphers (most compatible) esp210.menu.ssl.all.build.sslflags= esp210.menu.ssl.basic=Basic SSL ciphers (lower ROM use) esp210.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -esp210.upload.resetmethod=ck +esp210.upload.resetmethod=--before no_reset --after soft_reset esp210.build.flash_mode=qio esp210.build.flash_flags=-DFLASHMODE_QIO esp210.build.flash_freq=40 @@ -3494,7 +3691,7 @@ esp210.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOM esp210.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG esp210.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG esp210.menu.wipe.none=Only Sketch -esp210.menu.wipe.none.upload.erase_cmd=version +esp210.menu.wipe.none.upload.erase_cmd= esp210.menu.wipe.sdk=Sketch + WiFi Settings esp210.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 esp210.menu.wipe.all=All Flash Contents @@ -3525,7 +3722,7 @@ d1_mini.build.variant=d1_mini d1_mini.upload.tool=esptool d1_mini.upload.maximum_data_size=81920 d1_mini.upload.wait_for_upload_port=true -d1_mini.upload.erase_cmd=version +d1_mini.upload.erase_cmd= d1_mini.serial.disableDTR=true d1_mini.serial.disableRTS=true d1_mini.build.mcu=esp8266 @@ -3556,7 +3753,7 @@ d1_mini.menu.ssl.all=All SSL ciphers (most compatible) d1_mini.menu.ssl.all.build.sslflags= d1_mini.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1_mini.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -d1_mini.upload.resetmethod=nodemcu +d1_mini.upload.resetmethod=--before default_reset --after hard_reset d1_mini.build.flash_mode=dio d1_mini.build.flash_flags=-DFLASHMODE_DIO d1_mini.build.flash_freq=40 @@ -3687,7 +3884,7 @@ d1_mini.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO d1_mini.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG d1_mini.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG d1_mini.menu.wipe.none=Only Sketch -d1_mini.menu.wipe.none.upload.erase_cmd=version +d1_mini.menu.wipe.none.upload.erase_cmd= d1_mini.menu.wipe.sdk=Sketch + WiFi Settings d1_mini.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 d1_mini.menu.wipe.all=All Flash Contents @@ -3718,7 +3915,7 @@ d1_mini_pro.build.variant=d1_mini d1_mini_pro.upload.tool=esptool d1_mini_pro.upload.maximum_data_size=81920 d1_mini_pro.upload.wait_for_upload_port=true -d1_mini_pro.upload.erase_cmd=version +d1_mini_pro.upload.erase_cmd= d1_mini_pro.serial.disableDTR=true d1_mini_pro.serial.disableRTS=true d1_mini_pro.build.mcu=esp8266 @@ -3749,7 +3946,7 @@ d1_mini_pro.menu.ssl.all=All SSL ciphers (most compatible) d1_mini_pro.menu.ssl.all.build.sslflags= d1_mini_pro.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1_mini_pro.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -d1_mini_pro.upload.resetmethod=nodemcu +d1_mini_pro.upload.resetmethod=--before default_reset --after hard_reset d1_mini_pro.build.flash_mode=dio d1_mini_pro.build.flash_flags=-DFLASHMODE_DIO d1_mini_pro.build.flash_freq=40 @@ -3863,7 +4060,7 @@ d1_mini_pro.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATERO d1_mini_pro.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG d1_mini_pro.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG d1_mini_pro.menu.wipe.none=Only Sketch -d1_mini_pro.menu.wipe.none.upload.erase_cmd=version +d1_mini_pro.menu.wipe.none.upload.erase_cmd= d1_mini_pro.menu.wipe.sdk=Sketch + WiFi Settings d1_mini_pro.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 d1_mini_pro.menu.wipe.all=All Flash Contents @@ -3894,7 +4091,7 @@ d1_mini_lite.build.variant=d1_mini d1_mini_lite.upload.tool=esptool d1_mini_lite.upload.maximum_data_size=81920 d1_mini_lite.upload.wait_for_upload_port=true -d1_mini_lite.upload.erase_cmd=version +d1_mini_lite.upload.erase_cmd= d1_mini_lite.serial.disableDTR=true d1_mini_lite.serial.disableRTS=true d1_mini_lite.build.mcu=esp8266 @@ -3925,7 +4122,7 @@ d1_mini_lite.menu.ssl.all=All SSL ciphers (most compatible) d1_mini_lite.menu.ssl.all.build.sslflags= d1_mini_lite.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1_mini_lite.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -d1_mini_lite.upload.resetmethod=nodemcu +d1_mini_lite.upload.resetmethod=--before default_reset --after hard_reset d1_mini_lite.build.flash_mode=dout d1_mini_lite.build.flash_flags=-DFLASHMODE_DOUT d1_mini_lite.build.flash_freq=40 @@ -4096,7 +4293,7 @@ d1_mini_lite.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATER d1_mini_lite.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG d1_mini_lite.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG d1_mini_lite.menu.wipe.none=Only Sketch -d1_mini_lite.menu.wipe.none.upload.erase_cmd=version +d1_mini_lite.menu.wipe.none.upload.erase_cmd= d1_mini_lite.menu.wipe.sdk=Sketch + WiFi Settings d1_mini_lite.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 d1_mini_lite.menu.wipe.all=All Flash Contents @@ -4127,7 +4324,7 @@ d1.build.variant=d1 d1.upload.tool=esptool d1.upload.maximum_data_size=81920 d1.upload.wait_for_upload_port=true -d1.upload.erase_cmd=version +d1.upload.erase_cmd= d1.serial.disableDTR=true d1.serial.disableRTS=true d1.build.mcu=esp8266 @@ -4158,7 +4355,7 @@ d1.menu.ssl.all=All SSL ciphers (most compatible) d1.menu.ssl.all.build.sslflags= d1.menu.ssl.basic=Basic SSL ciphers (lower ROM use) d1.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -d1.upload.resetmethod=nodemcu +d1.upload.resetmethod=--before default_reset --after hard_reset d1.build.flash_mode=dio d1.build.flash_flags=-DFLASHMODE_DIO d1.build.flash_freq=40 @@ -4289,7 +4486,7 @@ d1.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS d1.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG d1.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG d1.menu.wipe.none=Only Sketch -d1.menu.wipe.none.upload.erase_cmd=version +d1.menu.wipe.none.upload.erase_cmd= d1.menu.wipe.sdk=Sketch + WiFi Settings d1.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 d1.menu.wipe.all=All Flash Contents @@ -4320,7 +4517,7 @@ espino.build.variant=espino espino.upload.tool=esptool espino.upload.maximum_data_size=81920 espino.upload.wait_for_upload_port=true -espino.upload.erase_cmd=version +espino.upload.erase_cmd= espino.serial.disableDTR=true espino.serial.disableRTS=true espino.build.mcu=esp8266 @@ -4351,10 +4548,10 @@ espino.menu.ssl.all=All SSL ciphers (most compatible) espino.menu.ssl.all.build.sslflags= espino.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -espino.menu.ResetMethod.ck=ck -espino.menu.ResetMethod.ck.upload.resetmethod=ck -espino.menu.ResetMethod.nodemcu=nodemcu -espino.menu.ResetMethod.nodemcu.upload.resetmethod=nodemcu +espino.menu.ResetMethod.nodemcu=dtr (aka nodemcu) +espino.menu.ResetMethod.nodemcu.upload.resetmethod=--before default_reset --after hard_reset +espino.menu.ResetMethod.ck=no dtr (aka ck) +espino.menu.ResetMethod.ck.upload.resetmethod=--before no_reset --after soft_reset espino.build.flash_mode=qio espino.build.flash_flags=-DFLASHMODE_QIO espino.build.flash_freq=40 @@ -4485,7 +4682,7 @@ espino.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOM espino.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG espino.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG espino.menu.wipe.none=Only Sketch -espino.menu.wipe.none.upload.erase_cmd=version +espino.menu.wipe.none.upload.erase_cmd= espino.menu.wipe.sdk=Sketch + WiFi Settings espino.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 espino.menu.wipe.all=All Flash Contents @@ -4516,7 +4713,7 @@ espinotee.build.variant=espinotee espinotee.upload.tool=esptool espinotee.upload.maximum_data_size=81920 espinotee.upload.wait_for_upload_port=true -espinotee.upload.erase_cmd=version +espinotee.upload.erase_cmd= espinotee.serial.disableDTR=true espinotee.serial.disableRTS=true espinotee.build.mcu=esp8266 @@ -4547,7 +4744,7 @@ espinotee.menu.ssl.all=All SSL ciphers (most compatible) espinotee.menu.ssl.all.build.sslflags= espinotee.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espinotee.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -espinotee.upload.resetmethod=nodemcu +espinotee.upload.resetmethod=--before default_reset --after hard_reset espinotee.build.flash_mode=qio espinotee.build.flash_flags=-DFLASHMODE_QIO espinotee.build.flash_freq=40 @@ -4678,7 +4875,7 @@ espinotee.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTA espinotee.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG espinotee.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG espinotee.menu.wipe.none=Only Sketch -espinotee.menu.wipe.none.upload.erase_cmd=version +espinotee.menu.wipe.none.upload.erase_cmd= espinotee.menu.wipe.sdk=Sketch + WiFi Settings espinotee.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 espinotee.menu.wipe.all=All Flash Contents @@ -4726,7 +4923,7 @@ wifinfo.menu.ESPModule.ESP12.upload.maximum_size=1044464 wifinfo.upload.tool=esptool wifinfo.upload.maximum_data_size=81920 wifinfo.upload.wait_for_upload_port=true -wifinfo.upload.erase_cmd=version +wifinfo.upload.erase_cmd= wifinfo.serial.disableDTR=true wifinfo.serial.disableRTS=true wifinfo.build.mcu=esp8266 @@ -4757,7 +4954,7 @@ wifinfo.menu.ssl.all=All SSL ciphers (most compatible) wifinfo.menu.ssl.all.build.sslflags= wifinfo.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wifinfo.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -wifinfo.upload.resetmethod=nodemcu +wifinfo.upload.resetmethod=--before default_reset --after hard_reset wifinfo.build.flash_mode=qio wifinfo.build.flash_flags=-DFLASHMODE_QIO wifinfo.menu.FlashFreq.40=40MHz @@ -4935,7 +5132,7 @@ wifinfo.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO wifinfo.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG wifinfo.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG wifinfo.menu.wipe.none=Only Sketch -wifinfo.menu.wipe.none.upload.erase_cmd=version +wifinfo.menu.wipe.none.upload.erase_cmd= wifinfo.menu.wipe.sdk=Sketch + WiFi Settings wifinfo.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 wifinfo.menu.wipe.all=All Flash Contents @@ -4977,7 +5174,7 @@ arduino-esp8266.menu.BoardModel.unowifideved.build.variant=arduino_uart arduino-esp8266.upload.tool=esptool arduino-esp8266.upload.maximum_data_size=81920 arduino-esp8266.upload.wait_for_upload_port=true -arduino-esp8266.upload.erase_cmd=version +arduino-esp8266.upload.erase_cmd= arduino-esp8266.serial.disableDTR=true arduino-esp8266.serial.disableRTS=true arduino-esp8266.build.mcu=esp8266 @@ -5009,7 +5206,7 @@ arduino-esp8266.menu.ssl.all=All SSL ciphers (most compatible) arduino-esp8266.menu.ssl.all.build.sslflags= arduino-esp8266.menu.ssl.basic=Basic SSL ciphers (lower ROM use) arduino-esp8266.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -arduino-esp8266.upload.resetmethod=ck +arduino-esp8266.upload.resetmethod=--before no_reset --after soft_reset arduino-esp8266.build.flash_mode=qio arduino-esp8266.build.flash_flags=-DFLASHMODE_QIO arduino-esp8266.build.flash_freq=40 @@ -5140,7 +5337,7 @@ arduino-esp8266.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDA arduino-esp8266.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG arduino-esp8266.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG arduino-esp8266.menu.wipe.none=Only Sketch -arduino-esp8266.menu.wipe.none.upload.erase_cmd=version +arduino-esp8266.menu.wipe.none.upload.erase_cmd= arduino-esp8266.menu.wipe.sdk=Sketch + WiFi Settings arduino-esp8266.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 arduino-esp8266.menu.wipe.all=All Flash Contents @@ -5172,7 +5369,7 @@ gen4iod.build.variant=generic gen4iod.upload.tool=esptool gen4iod.upload.maximum_data_size=81920 gen4iod.upload.wait_for_upload_port=true -gen4iod.upload.erase_cmd=version +gen4iod.upload.erase_cmd= gen4iod.serial.disableDTR=true gen4iod.serial.disableRTS=true gen4iod.build.mcu=esp8266 @@ -5203,7 +5400,7 @@ gen4iod.menu.ssl.all=All SSL ciphers (most compatible) gen4iod.menu.ssl.all.build.sslflags= gen4iod.menu.ssl.basic=Basic SSL ciphers (lower ROM use) gen4iod.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -gen4iod.upload.resetmethod=nodemcu +gen4iod.upload.resetmethod=--before default_reset --after hard_reset gen4iod.build.flash_mode=dio gen4iod.build.flash_flags=-DFLASHMODE_DIO gen4iod.build.flash_freq=80 @@ -5334,7 +5531,7 @@ gen4iod.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO gen4iod.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG gen4iod.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG gen4iod.menu.wipe.none=Only Sketch -gen4iod.menu.wipe.none.upload.erase_cmd=version +gen4iod.menu.wipe.none.upload.erase_cmd= gen4iod.menu.wipe.sdk=Sketch + WiFi Settings gen4iod.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 gen4iod.menu.wipe.all=All Flash Contents @@ -5366,7 +5563,7 @@ oak.upload.maximum_size=1040368 oak.upload.tool=esptool oak.upload.maximum_data_size=81920 oak.upload.wait_for_upload_port=true -oak.upload.erase_cmd=version +oak.upload.erase_cmd= oak.serial.disableDTR=true oak.serial.disableRTS=true oak.build.mcu=esp8266 @@ -5397,7 +5594,7 @@ oak.menu.ssl.all=All SSL ciphers (most compatible) oak.menu.ssl.all.build.sslflags= oak.menu.ssl.basic=Basic SSL ciphers (lower ROM use) oak.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -oak.upload.resetmethod=none +oak.upload.resetmethod=--before no_reset --after soft_reset oak.build.flash_mode=dio oak.build.flash_flags=-DFLASHMODE_DIO oak.build.flash_freq=40 @@ -5528,7 +5725,7 @@ oak.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDN oak.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG oak.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG oak.menu.wipe.none=Only Sketch -oak.menu.wipe.none.upload.erase_cmd=version +oak.menu.wipe.none.upload.erase_cmd= oak.menu.wipe.sdk=Sketch + WiFi Settings oak.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 oak.menu.wipe.all=All Flash Contents @@ -5559,7 +5756,7 @@ wifiduino.build.variant=wifiduino wifiduino.upload.tool=esptool wifiduino.upload.maximum_data_size=81920 wifiduino.upload.wait_for_upload_port=true -wifiduino.upload.erase_cmd=version +wifiduino.upload.erase_cmd= wifiduino.serial.disableDTR=true wifiduino.serial.disableRTS=true wifiduino.build.mcu=esp8266 @@ -5590,7 +5787,7 @@ wifiduino.menu.ssl.all=All SSL ciphers (most compatible) wifiduino.menu.ssl.all.build.sslflags= wifiduino.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wifiduino.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -wifiduino.upload.resetmethod=nodemcu +wifiduino.upload.resetmethod=--before default_reset --after hard_reset wifiduino.build.flash_mode=dio wifiduino.build.flash_flags=-DFLASHMODE_DIO wifiduino.build.flash_freq=40 @@ -5721,7 +5918,7 @@ wifiduino.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTA wifiduino.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG wifiduino.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG wifiduino.menu.wipe.none=Only Sketch -wifiduino.menu.wipe.none.upload.erase_cmd=version +wifiduino.menu.wipe.none.upload.erase_cmd= wifiduino.menu.wipe.sdk=Sketch + WiFi Settings wifiduino.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 wifiduino.menu.wipe.all=All Flash Contents @@ -5752,7 +5949,7 @@ wifi_slot.build.variant=wifi_slot wifi_slot.upload.tool=esptool wifi_slot.upload.maximum_data_size=81920 wifi_slot.upload.wait_for_upload_port=true -wifi_slot.upload.erase_cmd=version +wifi_slot.upload.erase_cmd= wifi_slot.serial.disableDTR=true wifi_slot.serial.disableRTS=true wifi_slot.build.mcu=esp8266 @@ -5783,7 +5980,7 @@ wifi_slot.menu.ssl.all=All SSL ciphers (most compatible) wifi_slot.menu.ssl.all.build.sslflags= wifi_slot.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wifi_slot.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -wifi_slot.upload.resetmethod=nodemcu +wifi_slot.upload.resetmethod=--before default_reset --after hard_reset wifi_slot.menu.FlashFreq.40=40MHz wifi_slot.menu.FlashFreq.40.build.flash_freq=40 wifi_slot.menu.FlashFreq.80=80MHz @@ -6028,7 +6225,7 @@ wifi_slot.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTA wifi_slot.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG wifi_slot.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG wifi_slot.menu.wipe.none=Only Sketch -wifi_slot.menu.wipe.none.upload.erase_cmd=version +wifi_slot.menu.wipe.none.upload.erase_cmd= wifi_slot.menu.wipe.sdk=Sketch + WiFi Settings wifi_slot.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 wifi_slot.menu.wipe.all=All Flash Contents @@ -6059,7 +6256,7 @@ wiolink.build.variant=wiolink wiolink.upload.tool=esptool wiolink.upload.maximum_data_size=81920 wiolink.upload.wait_for_upload_port=true -wiolink.upload.erase_cmd=version +wiolink.upload.erase_cmd= wiolink.serial.disableDTR=true wiolink.serial.disableRTS=true wiolink.build.mcu=esp8266 @@ -6090,7 +6287,7 @@ wiolink.menu.ssl.all=All SSL ciphers (most compatible) wiolink.menu.ssl.all.build.sslflags= wiolink.menu.ssl.basic=Basic SSL ciphers (lower ROM use) wiolink.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -wiolink.upload.resetmethod=nodemcu +wiolink.upload.resetmethod=--before default_reset --after hard_reset wiolink.build.flash_mode=qio wiolink.build.flash_flags=-DFLASHMODE_QIO wiolink.build.flash_freq=40 @@ -6221,7 +6418,7 @@ wiolink.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOO wiolink.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG wiolink.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG wiolink.menu.wipe.none=Only Sketch -wiolink.menu.wipe.none.upload.erase_cmd=version +wiolink.menu.wipe.none.upload.erase_cmd= wiolink.menu.wipe.sdk=Sketch + WiFi Settings wiolink.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 wiolink.menu.wipe.all=All Flash Contents @@ -6252,7 +6449,7 @@ espectro.build.variant=espectro espectro.upload.tool=esptool espectro.upload.maximum_data_size=81920 espectro.upload.wait_for_upload_port=true -espectro.upload.erase_cmd=version +espectro.upload.erase_cmd= espectro.serial.disableDTR=true espectro.serial.disableRTS=true espectro.build.mcu=esp8266 @@ -6283,7 +6480,7 @@ espectro.menu.ssl.all=All SSL ciphers (most compatible) espectro.menu.ssl.all.build.sslflags= espectro.menu.ssl.basic=Basic SSL ciphers (lower ROM use) espectro.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC -espectro.upload.resetmethod=nodemcu +espectro.upload.resetmethod=--before default_reset --after hard_reset espectro.build.flash_mode=dio espectro.build.flash_flags=-DFLASHMODE_DIO espectro.build.flash_freq=40 @@ -6414,7 +6611,7 @@ espectro.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAO espectro.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG espectro.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG espectro.menu.wipe.none=Only Sketch -espectro.menu.wipe.none.upload.erase_cmd=version +espectro.menu.wipe.none.upload.erase_cmd= espectro.menu.wipe.sdk=Sketch + WiFi Settings espectro.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 espectro.menu.wipe.all=All Flash Contents @@ -6438,3 +6635,673 @@ espectro.menu.baud.921600.upload.speed=921600 espectro.menu.baud.3000000=3000000 espectro.menu.baud.3000000.upload.speed=3000000 +############################################################## +eduinowifi.name=Schirmilabs Eduino WiFi +eduinowifi.build.board=ESP8266_SCHIRMILABS_EDUINO_WIFI +eduinowifi.build.variant=eduinowifi +eduinowifi.upload.tool=esptool +eduinowifi.upload.maximum_data_size=81920 +eduinowifi.upload.wait_for_upload_port=true +eduinowifi.upload.erase_cmd= +eduinowifi.serial.disableDTR=true +eduinowifi.serial.disableRTS=true +eduinowifi.build.mcu=esp8266 +eduinowifi.build.core=esp8266 +eduinowifi.build.spiffs_pagesize=256 +eduinowifi.build.debug_port= +eduinowifi.build.debug_level= +eduinowifi.menu.xtal.80=80 MHz +eduinowifi.menu.xtal.80.build.f_cpu=80000000L +eduinowifi.menu.xtal.160=160 MHz +eduinowifi.menu.xtal.160.build.f_cpu=160000000L +eduinowifi.menu.vt.flash=Flash +eduinowifi.menu.vt.flash.build.vtable_flags=-DVTABLES_IN_FLASH +eduinowifi.menu.vt.heap=Heap +eduinowifi.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM +eduinowifi.menu.vt.iram=IRAM +eduinowifi.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM +eduinowifi.menu.exception.legacy=Legacy (new can return nullptr) +eduinowifi.menu.exception.legacy.build.exception_flags=-fno-exceptions +eduinowifi.menu.exception.legacy.build.stdcpp_lib=-lstdc++ +eduinowifi.menu.exception.disabled=Disabled (new can abort) +eduinowifi.menu.exception.disabled.build.exception_flags=-fno-exceptions -DNEW_OOM_ABORT +eduinowifi.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +eduinowifi.menu.exception.enabled=Enabled +eduinowifi.menu.exception.enabled.build.exception_flags=-fexceptions +eduinowifi.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc +eduinowifi.menu.ssl.all=All SSL ciphers (most compatible) +eduinowifi.menu.ssl.all.build.sslflags= +eduinowifi.menu.ssl.basic=Basic SSL ciphers (lower ROM use) +eduinowifi.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +eduinowifi.upload.resetmethod=--before default_reset --after hard_reset +eduinowifi.build.flash_mode=dio +eduinowifi.build.flash_flags=-DFLASHMODE_DIO +eduinowifi.build.flash_freq=40 +eduinowifi.menu.eesz.4M2M=4MB (FS:2MB OTA:~1019KB) +eduinowifi.menu.eesz.4M2M.build.flash_size=4M +eduinowifi.menu.eesz.4M2M.build.flash_size_bytes=0x400000 +eduinowifi.menu.eesz.4M2M.build.flash_ld=eagle.flash.4m2m.ld +eduinowifi.menu.eesz.4M2M.build.spiffs_pagesize=256 +eduinowifi.menu.eesz.4M2M.upload.maximum_size=1044464 +eduinowifi.menu.eesz.4M2M.build.rfcal_addr=0x3FC000 +eduinowifi.menu.eesz.4M2M.build.spiffs_start=0x200000 +eduinowifi.menu.eesz.4M2M.build.spiffs_end=0x3FA000 +eduinowifi.menu.eesz.4M2M.build.spiffs_blocksize=8192 +eduinowifi.menu.eesz.4M3M=4MB (FS:3MB OTA:~512KB) +eduinowifi.menu.eesz.4M3M.build.flash_size=4M +eduinowifi.menu.eesz.4M3M.build.flash_size_bytes=0x400000 +eduinowifi.menu.eesz.4M3M.build.flash_ld=eagle.flash.4m3m.ld +eduinowifi.menu.eesz.4M3M.build.spiffs_pagesize=256 +eduinowifi.menu.eesz.4M3M.upload.maximum_size=1044464 +eduinowifi.menu.eesz.4M3M.build.rfcal_addr=0x3FC000 +eduinowifi.menu.eesz.4M3M.build.spiffs_start=0x100000 +eduinowifi.menu.eesz.4M3M.build.spiffs_end=0x3FA000 +eduinowifi.menu.eesz.4M3M.build.spiffs_blocksize=8192 +eduinowifi.menu.eesz.4M1M=4MB (FS:1MB OTA:~1019KB) +eduinowifi.menu.eesz.4M1M.build.flash_size=4M +eduinowifi.menu.eesz.4M1M.build.flash_size_bytes=0x400000 +eduinowifi.menu.eesz.4M1M.build.flash_ld=eagle.flash.4m1m.ld +eduinowifi.menu.eesz.4M1M.build.spiffs_pagesize=256 +eduinowifi.menu.eesz.4M1M.upload.maximum_size=1044464 +eduinowifi.menu.eesz.4M1M.build.rfcal_addr=0x3FC000 +eduinowifi.menu.eesz.4M1M.build.spiffs_start=0x300000 +eduinowifi.menu.eesz.4M1M.build.spiffs_end=0x3FA000 +eduinowifi.menu.eesz.4M1M.build.spiffs_blocksize=8192 +eduinowifi.menu.eesz.4M=4MB (FS:none OTA:~1019KB) +eduinowifi.menu.eesz.4M.build.flash_size=4M +eduinowifi.menu.eesz.4M.build.flash_size_bytes=0x400000 +eduinowifi.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld +eduinowifi.menu.eesz.4M.build.spiffs_pagesize=256 +eduinowifi.menu.eesz.4M.upload.maximum_size=1044464 +eduinowifi.menu.eesz.4M.build.rfcal_addr=0x3FC000 +eduinowifi.menu.ip.lm2f=v2 Lower Memory +eduinowifi.menu.ip.lm2f.build.lwip_include=lwip2/include +eduinowifi.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat +eduinowifi.menu.ip.lm2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +eduinowifi.menu.ip.hb2f=v2 Higher Bandwidth +eduinowifi.menu.ip.hb2f.build.lwip_include=lwip2/include +eduinowifi.menu.ip.hb2f.build.lwip_lib=-llwip2-1460-feat +eduinowifi.menu.ip.hb2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +eduinowifi.menu.ip.lm2n=v2 Lower Memory (no features) +eduinowifi.menu.ip.lm2n.build.lwip_include=lwip2/include +eduinowifi.menu.ip.lm2n.build.lwip_lib=-llwip2-536 +eduinowifi.menu.ip.lm2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +eduinowifi.menu.ip.hb2n=v2 Higher Bandwidth (no features) +eduinowifi.menu.ip.hb2n.build.lwip_include=lwip2/include +eduinowifi.menu.ip.hb2n.build.lwip_lib=-llwip2-1460 +eduinowifi.menu.ip.hb2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +eduinowifi.menu.ip.lm6f=v2 IPv6 Lower Memory +eduinowifi.menu.ip.lm6f.build.lwip_include=lwip2/include +eduinowifi.menu.ip.lm6f.build.lwip_lib=-llwip6-536-feat +eduinowifi.menu.ip.lm6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +eduinowifi.menu.ip.hb6f=v2 IPv6 Higher Bandwidth +eduinowifi.menu.ip.hb6f.build.lwip_include=lwip2/include +eduinowifi.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat +eduinowifi.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +eduinowifi.menu.ip.hb1=v1.4 Higher Bandwidth +eduinowifi.menu.ip.hb1.build.lwip_lib=-llwip_gcc +eduinowifi.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC +eduinowifi.menu.ip.src=v1.4 Compile from source +eduinowifi.menu.ip.src.build.lwip_lib=-llwip_src +eduinowifi.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC +eduinowifi.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" +eduinowifi.menu.dbg.Disabled=Disabled +eduinowifi.menu.dbg.Disabled.build.debug_port= +eduinowifi.menu.dbg.Serial=Serial +eduinowifi.menu.dbg.Serial.build.debug_port=-DDEBUG_ESP_PORT=Serial +eduinowifi.menu.dbg.Serial1=Serial1 +eduinowifi.menu.dbg.Serial1.build.debug_port=-DDEBUG_ESP_PORT=Serial1 +eduinowifi.menu.lvl.None____=None +eduinowifi.menu.lvl.None____.build.debug_level= +eduinowifi.menu.lvl.SSL=SSL +eduinowifi.menu.lvl.SSL.build.debug_level= -DDEBUG_ESP_SSL +eduinowifi.menu.lvl.TLS_MEM=TLS_MEM +eduinowifi.menu.lvl.TLS_MEM.build.debug_level= -DDEBUG_ESP_TLS_MEM +eduinowifi.menu.lvl.HTTP_CLIENT=HTTP_CLIENT +eduinowifi.menu.lvl.HTTP_CLIENT.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT +eduinowifi.menu.lvl.HTTP_SERVER=HTTP_SERVER +eduinowifi.menu.lvl.HTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.SSLTLS_MEM=SSL+TLS_MEM +eduinowifi.menu.lvl.SSLTLS_MEM.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM +eduinowifi.menu.lvl.SSLHTTP_CLIENT=SSL+HTTP_CLIENT +eduinowifi.menu.lvl.SSLHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT +eduinowifi.menu.lvl.SSLHTTP_SERVER=SSL+HTTP_SERVER +eduinowifi.menu.lvl.SSLHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.TLS_MEMHTTP_CLIENT=TLS_MEM+HTTP_CLIENT +eduinowifi.menu.lvl.TLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +eduinowifi.menu.lvl.TLS_MEMHTTP_SERVER=TLS_MEM+HTTP_SERVER +eduinowifi.menu.lvl.TLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.HTTP_CLIENTHTTP_SERVER=HTTP_CLIENT+HTTP_SERVER +eduinowifi.menu.lvl.HTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_CLIENT=SSL+TLS_MEM+HTTP_CLIENT +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_SERVER=SSL+TLS_MEM+HTTP_SERVER +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER=SSL+HTTP_CLIENT+HTTP_SERVER +eduinowifi.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER=TLS_MEM+HTTP_CLIENT+HTTP_SERVER +eduinowifi.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +eduinowifi.menu.lvl.CORE=CORE +eduinowifi.menu.lvl.CORE.build.debug_level= -DDEBUG_ESP_CORE +eduinowifi.menu.lvl.WIFI=WIFI +eduinowifi.menu.lvl.WIFI.build.debug_level= -DDEBUG_ESP_WIFI +eduinowifi.menu.lvl.HTTP_UPDATE=HTTP_UPDATE +eduinowifi.menu.lvl.HTTP_UPDATE.build.debug_level= -DDEBUG_ESP_HTTP_UPDATE +eduinowifi.menu.lvl.UPDATER=UPDATER +eduinowifi.menu.lvl.UPDATER.build.debug_level= -DDEBUG_ESP_UPDATER +eduinowifi.menu.lvl.OTA=OTA +eduinowifi.menu.lvl.OTA.build.debug_level= -DDEBUG_ESP_OTA +eduinowifi.menu.lvl.OOM=OOM +eduinowifi.menu.lvl.OOM.build.debug_level= -DDEBUG_ESP_OOM +eduinowifi.menu.lvl.MDNS=MDNS +eduinowifi.menu.lvl.MDNS.build.debug_level= -DDEBUG_ESP_MDNS +eduinowifi.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +eduinowifi.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER+CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +eduinowifi.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +eduinowifi.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG +eduinowifi.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG +eduinowifi.menu.wipe.none=Only Sketch +eduinowifi.menu.wipe.none.upload.erase_cmd= +eduinowifi.menu.wipe.sdk=Sketch + WiFi Settings +eduinowifi.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 +eduinowifi.menu.wipe.all=All Flash Contents +eduinowifi.menu.wipe.all.upload.erase_cmd=erase_flash +eduinowifi.menu.baud.512000.windows=512000 +eduinowifi.menu.baud.512000.upload.speed=512000 +eduinowifi.menu.baud.57600=57600 +eduinowifi.menu.baud.57600.upload.speed=57600 +eduinowifi.menu.baud.115200=115200 +eduinowifi.menu.baud.115200.upload.speed=115200 +eduinowifi.menu.baud.230400.linux=230400 +eduinowifi.menu.baud.230400.macosx=230400 +eduinowifi.menu.baud.230400.upload.speed=230400 +eduinowifi.menu.baud.256000.windows=256000 +eduinowifi.menu.baud.256000.upload.speed=256000 +eduinowifi.menu.baud.460800.linux=460800 +eduinowifi.menu.baud.460800.macosx=460800 +eduinowifi.menu.baud.460800.upload.speed=460800 +eduinowifi.menu.baud.921600=921600 +eduinowifi.menu.baud.921600.upload.speed=921600 +eduinowifi.menu.baud.3000000=3000000 +eduinowifi.menu.baud.3000000.upload.speed=3000000 + +############################################################## +sonoff.name=ITEAD Sonoff +sonoff.build.board=ESP8266_SONOFF_SV +sonoff.build.extra_flags=-DESP8266 +sonoff.build.flash_size=1M +sonoff.build.variant=itead +sonoff.menu.BoardModel.sonoffBasic=ITEAD Sonoff Basic +sonoff.menu.BoardModel.sonoffBasic.build.board=ESP8266_SONOFF_BASIC +sonoff.menu.BoardModel.sonoffS20=ITEAD Sonoff S20 +sonoff.menu.BoardModel.sonoffS20.build.board=ESP8266_SONOFF_S20 +sonoff.menu.BoardModel.sonoffSV=ITEAD Sonoff SV +sonoff.menu.BoardModel.sonoffSV.build.board=ESP8266_SONOFF_SV +sonoff.menu.BoardModel.sonoffTH=ITEAD Sonoff TH +sonoff.menu.BoardModel.sonoffTH.build.board=ESP8266_SONOFF_TH +sonoff.upload.tool=esptool +sonoff.upload.maximum_data_size=81920 +sonoff.upload.wait_for_upload_port=true +sonoff.upload.erase_cmd= +sonoff.serial.disableDTR=true +sonoff.serial.disableRTS=true +sonoff.build.mcu=esp8266 +sonoff.build.core=esp8266 +sonoff.build.spiffs_pagesize=256 +sonoff.build.debug_port= +sonoff.build.debug_level= +sonoff.menu.xtal.80=80 MHz +sonoff.menu.xtal.80.build.f_cpu=80000000L +sonoff.menu.xtal.160=160 MHz +sonoff.menu.xtal.160.build.f_cpu=160000000L +sonoff.menu.vt.flash=Flash +sonoff.menu.vt.flash.build.vtable_flags=-DVTABLES_IN_FLASH +sonoff.menu.vt.heap=Heap +sonoff.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM +sonoff.menu.vt.iram=IRAM +sonoff.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM +sonoff.menu.exception.legacy=Legacy (new can return nullptr) +sonoff.menu.exception.legacy.build.exception_flags=-fno-exceptions +sonoff.menu.exception.legacy.build.stdcpp_lib=-lstdc++ +sonoff.menu.exception.disabled=Disabled (new can abort) +sonoff.menu.exception.disabled.build.exception_flags=-fno-exceptions -DNEW_OOM_ABORT +sonoff.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +sonoff.menu.exception.enabled=Enabled +sonoff.menu.exception.enabled.build.exception_flags=-fexceptions +sonoff.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc +sonoff.menu.ssl.all=All SSL ciphers (most compatible) +sonoff.menu.ssl.all.build.sslflags= +sonoff.menu.ssl.basic=Basic SSL ciphers (lower ROM use) +sonoff.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +sonoff.upload.resetmethod=--before no_reset --after soft_reset +sonoff.build.flash_mode=dout +sonoff.build.flash_flags=-DFLASHMODE_DOUT +sonoff.build.flash_freq=40 +sonoff.menu.eesz.1M64=1MB (FS:64KB OTA:~470KB) +sonoff.menu.eesz.1M64.build.flash_size=1M +sonoff.menu.eesz.1M64.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M64.build.flash_ld=eagle.flash.1m64.ld +sonoff.menu.eesz.1M64.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M64.upload.maximum_size=958448 +sonoff.menu.eesz.1M64.build.rfcal_addr=0xFC000 +sonoff.menu.eesz.1M64.build.spiffs_start=0xEB000 +sonoff.menu.eesz.1M64.build.spiffs_end=0xFB000 +sonoff.menu.eesz.1M64.build.spiffs_blocksize=4096 +sonoff.menu.eesz.1M128=1MB (FS:128KB OTA:~438KB) +sonoff.menu.eesz.1M128.build.flash_size=1M +sonoff.menu.eesz.1M128.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M128.build.flash_ld=eagle.flash.1m128.ld +sonoff.menu.eesz.1M128.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M128.upload.maximum_size=892912 +sonoff.menu.eesz.1M128.build.rfcal_addr=0xFC000 +sonoff.menu.eesz.1M128.build.spiffs_start=0xDB000 +sonoff.menu.eesz.1M128.build.spiffs_end=0xFB000 +sonoff.menu.eesz.1M128.build.spiffs_blocksize=4096 +sonoff.menu.eesz.1M144=1MB (FS:144KB OTA:~430KB) +sonoff.menu.eesz.1M144.build.flash_size=1M +sonoff.menu.eesz.1M144.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M144.build.flash_ld=eagle.flash.1m144.ld +sonoff.menu.eesz.1M144.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M144.upload.maximum_size=876528 +sonoff.menu.eesz.1M144.build.rfcal_addr=0xFC000 +sonoff.menu.eesz.1M144.build.spiffs_start=0xD7000 +sonoff.menu.eesz.1M144.build.spiffs_end=0xFB000 +sonoff.menu.eesz.1M144.build.spiffs_blocksize=4096 +sonoff.menu.eesz.1M160=1MB (FS:160KB OTA:~422KB) +sonoff.menu.eesz.1M160.build.flash_size=1M +sonoff.menu.eesz.1M160.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M160.build.flash_ld=eagle.flash.1m160.ld +sonoff.menu.eesz.1M160.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M160.upload.maximum_size=860144 +sonoff.menu.eesz.1M160.build.rfcal_addr=0xFC000 +sonoff.menu.eesz.1M160.build.spiffs_start=0xD3000 +sonoff.menu.eesz.1M160.build.spiffs_end=0xFB000 +sonoff.menu.eesz.1M160.build.spiffs_blocksize=4096 +sonoff.menu.eesz.1M192=1MB (FS:192KB OTA:~406KB) +sonoff.menu.eesz.1M192.build.flash_size=1M +sonoff.menu.eesz.1M192.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M192.build.flash_ld=eagle.flash.1m192.ld +sonoff.menu.eesz.1M192.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M192.upload.maximum_size=827376 +sonoff.menu.eesz.1M192.build.rfcal_addr=0xFC000 +sonoff.menu.eesz.1M192.build.spiffs_start=0xCB000 +sonoff.menu.eesz.1M192.build.spiffs_end=0xFB000 +sonoff.menu.eesz.1M192.build.spiffs_blocksize=4096 +sonoff.menu.eesz.1M256=1MB (FS:256KB OTA:~374KB) +sonoff.menu.eesz.1M256.build.flash_size=1M +sonoff.menu.eesz.1M256.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M256.build.flash_ld=eagle.flash.1m256.ld +sonoff.menu.eesz.1M256.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M256.upload.maximum_size=761840 +sonoff.menu.eesz.1M256.build.rfcal_addr=0xFC000 +sonoff.menu.eesz.1M256.build.spiffs_start=0xBB000 +sonoff.menu.eesz.1M256.build.spiffs_end=0xFB000 +sonoff.menu.eesz.1M256.build.spiffs_blocksize=4096 +sonoff.menu.eesz.1M512=1MB (FS:512KB OTA:~246KB) +sonoff.menu.eesz.1M512.build.flash_size=1M +sonoff.menu.eesz.1M512.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M512.build.flash_ld=eagle.flash.1m512.ld +sonoff.menu.eesz.1M512.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M512.upload.maximum_size=499696 +sonoff.menu.eesz.1M512.build.rfcal_addr=0xFC000 +sonoff.menu.eesz.1M512.build.spiffs_start=0x7B000 +sonoff.menu.eesz.1M512.build.spiffs_end=0xFB000 +sonoff.menu.eesz.1M512.build.spiffs_blocksize=8192 +sonoff.menu.eesz.1M=1MB (FS:none OTA:~502KB) +sonoff.menu.eesz.1M.build.flash_size=1M +sonoff.menu.eesz.1M.build.flash_size_bytes=0x100000 +sonoff.menu.eesz.1M.build.flash_ld=eagle.flash.1m.ld +sonoff.menu.eesz.1M.build.spiffs_pagesize=256 +sonoff.menu.eesz.1M.upload.maximum_size=1023984 +sonoff.menu.eesz.1M.build.rfcal_addr=0xFC000 +sonoff.menu.ip.lm2f=v2 Lower Memory +sonoff.menu.ip.lm2f.build.lwip_include=lwip2/include +sonoff.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat +sonoff.menu.ip.lm2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +sonoff.menu.ip.hb2f=v2 Higher Bandwidth +sonoff.menu.ip.hb2f.build.lwip_include=lwip2/include +sonoff.menu.ip.hb2f.build.lwip_lib=-llwip2-1460-feat +sonoff.menu.ip.hb2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +sonoff.menu.ip.lm2n=v2 Lower Memory (no features) +sonoff.menu.ip.lm2n.build.lwip_include=lwip2/include +sonoff.menu.ip.lm2n.build.lwip_lib=-llwip2-536 +sonoff.menu.ip.lm2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +sonoff.menu.ip.hb2n=v2 Higher Bandwidth (no features) +sonoff.menu.ip.hb2n.build.lwip_include=lwip2/include +sonoff.menu.ip.hb2n.build.lwip_lib=-llwip2-1460 +sonoff.menu.ip.hb2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +sonoff.menu.ip.lm6f=v2 IPv6 Lower Memory +sonoff.menu.ip.lm6f.build.lwip_include=lwip2/include +sonoff.menu.ip.lm6f.build.lwip_lib=-llwip6-536-feat +sonoff.menu.ip.lm6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +sonoff.menu.ip.hb6f=v2 IPv6 Higher Bandwidth +sonoff.menu.ip.hb6f.build.lwip_include=lwip2/include +sonoff.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat +sonoff.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +sonoff.menu.ip.hb1=v1.4 Higher Bandwidth +sonoff.menu.ip.hb1.build.lwip_lib=-llwip_gcc +sonoff.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC +sonoff.menu.ip.src=v1.4 Compile from source +sonoff.menu.ip.src.build.lwip_lib=-llwip_src +sonoff.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC +sonoff.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" +sonoff.menu.dbg.Disabled=Disabled +sonoff.menu.dbg.Disabled.build.debug_port= +sonoff.menu.dbg.Serial=Serial +sonoff.menu.dbg.Serial.build.debug_port=-DDEBUG_ESP_PORT=Serial +sonoff.menu.dbg.Serial1=Serial1 +sonoff.menu.dbg.Serial1.build.debug_port=-DDEBUG_ESP_PORT=Serial1 +sonoff.menu.lvl.None____=None +sonoff.menu.lvl.None____.build.debug_level= +sonoff.menu.lvl.SSL=SSL +sonoff.menu.lvl.SSL.build.debug_level= -DDEBUG_ESP_SSL +sonoff.menu.lvl.TLS_MEM=TLS_MEM +sonoff.menu.lvl.TLS_MEM.build.debug_level= -DDEBUG_ESP_TLS_MEM +sonoff.menu.lvl.HTTP_CLIENT=HTTP_CLIENT +sonoff.menu.lvl.HTTP_CLIENT.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT +sonoff.menu.lvl.HTTP_SERVER=HTTP_SERVER +sonoff.menu.lvl.HTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.SSLTLS_MEM=SSL+TLS_MEM +sonoff.menu.lvl.SSLTLS_MEM.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM +sonoff.menu.lvl.SSLHTTP_CLIENT=SSL+HTTP_CLIENT +sonoff.menu.lvl.SSLHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT +sonoff.menu.lvl.SSLHTTP_SERVER=SSL+HTTP_SERVER +sonoff.menu.lvl.SSLHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.TLS_MEMHTTP_CLIENT=TLS_MEM+HTTP_CLIENT +sonoff.menu.lvl.TLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +sonoff.menu.lvl.TLS_MEMHTTP_SERVER=TLS_MEM+HTTP_SERVER +sonoff.menu.lvl.TLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.HTTP_CLIENTHTTP_SERVER=HTTP_CLIENT+HTTP_SERVER +sonoff.menu.lvl.HTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.SSLTLS_MEMHTTP_CLIENT=SSL+TLS_MEM+HTTP_CLIENT +sonoff.menu.lvl.SSLTLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +sonoff.menu.lvl.SSLTLS_MEMHTTP_SERVER=SSL+TLS_MEM+HTTP_SERVER +sonoff.menu.lvl.SSLTLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER=SSL+HTTP_CLIENT+HTTP_SERVER +sonoff.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER=TLS_MEM+HTTP_CLIENT+HTTP_SERVER +sonoff.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER +sonoff.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +sonoff.menu.lvl.CORE=CORE +sonoff.menu.lvl.CORE.build.debug_level= -DDEBUG_ESP_CORE +sonoff.menu.lvl.WIFI=WIFI +sonoff.menu.lvl.WIFI.build.debug_level= -DDEBUG_ESP_WIFI +sonoff.menu.lvl.HTTP_UPDATE=HTTP_UPDATE +sonoff.menu.lvl.HTTP_UPDATE.build.debug_level= -DDEBUG_ESP_HTTP_UPDATE +sonoff.menu.lvl.UPDATER=UPDATER +sonoff.menu.lvl.UPDATER.build.debug_level= -DDEBUG_ESP_UPDATER +sonoff.menu.lvl.OTA=OTA +sonoff.menu.lvl.OTA.build.debug_level= -DDEBUG_ESP_OTA +sonoff.menu.lvl.OOM=OOM +sonoff.menu.lvl.OOM.build.debug_level= -DDEBUG_ESP_OOM +sonoff.menu.lvl.MDNS=MDNS +sonoff.menu.lvl.MDNS.build.debug_level= -DDEBUG_ESP_MDNS +sonoff.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +sonoff.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +sonoff.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER+CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +sonoff.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +sonoff.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG +sonoff.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG +sonoff.menu.wipe.none=Only Sketch +sonoff.menu.wipe.none.upload.erase_cmd= +sonoff.menu.wipe.sdk=Sketch + WiFi Settings +sonoff.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 +sonoff.menu.wipe.all=All Flash Contents +sonoff.menu.wipe.all.upload.erase_cmd=erase_flash +sonoff.menu.baud.115200=115200 +sonoff.menu.baud.115200.upload.speed=115200 +sonoff.menu.baud.57600=57600 +sonoff.menu.baud.57600.upload.speed=57600 +sonoff.menu.baud.230400.linux=230400 +sonoff.menu.baud.230400.macosx=230400 +sonoff.menu.baud.230400.upload.speed=230400 +sonoff.menu.baud.256000.windows=256000 +sonoff.menu.baud.256000.upload.speed=256000 +sonoff.menu.baud.460800.linux=460800 +sonoff.menu.baud.460800.macosx=460800 +sonoff.menu.baud.460800.upload.speed=460800 +sonoff.menu.baud.512000.windows=512000 +sonoff.menu.baud.512000.upload.speed=512000 +sonoff.menu.baud.921600=921600 +sonoff.menu.baud.921600.upload.speed=921600 +sonoff.menu.baud.3000000=3000000 +sonoff.menu.baud.3000000.upload.speed=3000000 + +############################################################## +espmxdevkit.name=DOIT ESP-Mx DevKit (ESP8285) +espmxdevkit.build.board=ESP8266_ESP01 +espmxdevkit.build.led=-DLED_BUILTIN=16 +espmxdevkit.build.variant=esp8285 +espmxdevkit.upload.tool=esptool +espmxdevkit.upload.maximum_data_size=81920 +espmxdevkit.upload.wait_for_upload_port=true +espmxdevkit.upload.erase_cmd= +espmxdevkit.serial.disableDTR=true +espmxdevkit.serial.disableRTS=true +espmxdevkit.build.mcu=esp8266 +espmxdevkit.build.core=esp8266 +espmxdevkit.build.spiffs_pagesize=256 +espmxdevkit.build.debug_port= +espmxdevkit.build.debug_level= +espmxdevkit.menu.xtal.80=80 MHz +espmxdevkit.menu.xtal.80.build.f_cpu=80000000L +espmxdevkit.menu.xtal.160=160 MHz +espmxdevkit.menu.xtal.160.build.f_cpu=160000000L +espmxdevkit.menu.vt.flash=Flash +espmxdevkit.menu.vt.flash.build.vtable_flags=-DVTABLES_IN_FLASH +espmxdevkit.menu.vt.heap=Heap +espmxdevkit.menu.vt.heap.build.vtable_flags=-DVTABLES_IN_DRAM +espmxdevkit.menu.vt.iram=IRAM +espmxdevkit.menu.vt.iram.build.vtable_flags=-DVTABLES_IN_IRAM +espmxdevkit.menu.exception.legacy=Legacy (new can return nullptr) +espmxdevkit.menu.exception.legacy.build.exception_flags=-fno-exceptions +espmxdevkit.menu.exception.legacy.build.stdcpp_lib=-lstdc++ +espmxdevkit.menu.exception.disabled=Disabled (new can abort) +espmxdevkit.menu.exception.disabled.build.exception_flags=-fno-exceptions -DNEW_OOM_ABORT +espmxdevkit.menu.exception.disabled.build.stdcpp_lib=-lstdc++ +espmxdevkit.menu.exception.enabled=Enabled +espmxdevkit.menu.exception.enabled.build.exception_flags=-fexceptions +espmxdevkit.menu.exception.enabled.build.stdcpp_lib=-lstdc++-exc +espmxdevkit.menu.ssl.all=All SSL ciphers (most compatible) +espmxdevkit.menu.ssl.all.build.sslflags= +espmxdevkit.menu.ssl.basic=Basic SSL ciphers (lower ROM use) +espmxdevkit.menu.ssl.basic.build.sslflags=-DBEARSSL_SSL_BASIC +espmxdevkit.upload.resetmethod=--before default_reset --after hard_reset +espmxdevkit.build.flash_mode=dout +espmxdevkit.build.flash_flags=-DFLASHMODE_DOUT +espmxdevkit.build.flash_freq=40 +espmxdevkit.menu.eesz.1M64=1MB (FS:64KB OTA:~470KB) +espmxdevkit.menu.eesz.1M64.build.flash_size=1M +espmxdevkit.menu.eesz.1M64.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M64.build.flash_ld=eagle.flash.1m64.ld +espmxdevkit.menu.eesz.1M64.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M64.upload.maximum_size=958448 +espmxdevkit.menu.eesz.1M64.build.rfcal_addr=0xFC000 +espmxdevkit.menu.eesz.1M64.build.spiffs_start=0xEB000 +espmxdevkit.menu.eesz.1M64.build.spiffs_end=0xFB000 +espmxdevkit.menu.eesz.1M64.build.spiffs_blocksize=4096 +espmxdevkit.menu.eesz.1M128=1MB (FS:128KB OTA:~438KB) +espmxdevkit.menu.eesz.1M128.build.flash_size=1M +espmxdevkit.menu.eesz.1M128.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M128.build.flash_ld=eagle.flash.1m128.ld +espmxdevkit.menu.eesz.1M128.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M128.upload.maximum_size=892912 +espmxdevkit.menu.eesz.1M128.build.rfcal_addr=0xFC000 +espmxdevkit.menu.eesz.1M128.build.spiffs_start=0xDB000 +espmxdevkit.menu.eesz.1M128.build.spiffs_end=0xFB000 +espmxdevkit.menu.eesz.1M128.build.spiffs_blocksize=4096 +espmxdevkit.menu.eesz.1M144=1MB (FS:144KB OTA:~430KB) +espmxdevkit.menu.eesz.1M144.build.flash_size=1M +espmxdevkit.menu.eesz.1M144.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M144.build.flash_ld=eagle.flash.1m144.ld +espmxdevkit.menu.eesz.1M144.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M144.upload.maximum_size=876528 +espmxdevkit.menu.eesz.1M144.build.rfcal_addr=0xFC000 +espmxdevkit.menu.eesz.1M144.build.spiffs_start=0xD7000 +espmxdevkit.menu.eesz.1M144.build.spiffs_end=0xFB000 +espmxdevkit.menu.eesz.1M144.build.spiffs_blocksize=4096 +espmxdevkit.menu.eesz.1M160=1MB (FS:160KB OTA:~422KB) +espmxdevkit.menu.eesz.1M160.build.flash_size=1M +espmxdevkit.menu.eesz.1M160.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M160.build.flash_ld=eagle.flash.1m160.ld +espmxdevkit.menu.eesz.1M160.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M160.upload.maximum_size=860144 +espmxdevkit.menu.eesz.1M160.build.rfcal_addr=0xFC000 +espmxdevkit.menu.eesz.1M160.build.spiffs_start=0xD3000 +espmxdevkit.menu.eesz.1M160.build.spiffs_end=0xFB000 +espmxdevkit.menu.eesz.1M160.build.spiffs_blocksize=4096 +espmxdevkit.menu.eesz.1M192=1MB (FS:192KB OTA:~406KB) +espmxdevkit.menu.eesz.1M192.build.flash_size=1M +espmxdevkit.menu.eesz.1M192.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M192.build.flash_ld=eagle.flash.1m192.ld +espmxdevkit.menu.eesz.1M192.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M192.upload.maximum_size=827376 +espmxdevkit.menu.eesz.1M192.build.rfcal_addr=0xFC000 +espmxdevkit.menu.eesz.1M192.build.spiffs_start=0xCB000 +espmxdevkit.menu.eesz.1M192.build.spiffs_end=0xFB000 +espmxdevkit.menu.eesz.1M192.build.spiffs_blocksize=4096 +espmxdevkit.menu.eesz.1M256=1MB (FS:256KB OTA:~374KB) +espmxdevkit.menu.eesz.1M256.build.flash_size=1M +espmxdevkit.menu.eesz.1M256.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M256.build.flash_ld=eagle.flash.1m256.ld +espmxdevkit.menu.eesz.1M256.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M256.upload.maximum_size=761840 +espmxdevkit.menu.eesz.1M256.build.rfcal_addr=0xFC000 +espmxdevkit.menu.eesz.1M256.build.spiffs_start=0xBB000 +espmxdevkit.menu.eesz.1M256.build.spiffs_end=0xFB000 +espmxdevkit.menu.eesz.1M256.build.spiffs_blocksize=4096 +espmxdevkit.menu.eesz.1M512=1MB (FS:512KB OTA:~246KB) +espmxdevkit.menu.eesz.1M512.build.flash_size=1M +espmxdevkit.menu.eesz.1M512.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M512.build.flash_ld=eagle.flash.1m512.ld +espmxdevkit.menu.eesz.1M512.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M512.upload.maximum_size=499696 +espmxdevkit.menu.eesz.1M512.build.rfcal_addr=0xFC000 +espmxdevkit.menu.eesz.1M512.build.spiffs_start=0x7B000 +espmxdevkit.menu.eesz.1M512.build.spiffs_end=0xFB000 +espmxdevkit.menu.eesz.1M512.build.spiffs_blocksize=8192 +espmxdevkit.menu.eesz.1M=1MB (FS:none OTA:~502KB) +espmxdevkit.menu.eesz.1M.build.flash_size=1M +espmxdevkit.menu.eesz.1M.build.flash_size_bytes=0x100000 +espmxdevkit.menu.eesz.1M.build.flash_ld=eagle.flash.1m.ld +espmxdevkit.menu.eesz.1M.build.spiffs_pagesize=256 +espmxdevkit.menu.eesz.1M.upload.maximum_size=1023984 +espmxdevkit.menu.eesz.1M.build.rfcal_addr=0xFC000 +espmxdevkit.menu.ip.lm2f=v2 Lower Memory +espmxdevkit.menu.ip.lm2f.build.lwip_include=lwip2/include +espmxdevkit.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat +espmxdevkit.menu.ip.lm2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +espmxdevkit.menu.ip.hb2f=v2 Higher Bandwidth +espmxdevkit.menu.ip.hb2f.build.lwip_include=lwip2/include +espmxdevkit.menu.ip.hb2f.build.lwip_lib=-llwip2-1460-feat +espmxdevkit.menu.ip.hb2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=0 +espmxdevkit.menu.ip.lm2n=v2 Lower Memory (no features) +espmxdevkit.menu.ip.lm2n.build.lwip_include=lwip2/include +espmxdevkit.menu.ip.lm2n.build.lwip_lib=-llwip2-536 +espmxdevkit.menu.ip.lm2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +espmxdevkit.menu.ip.hb2n=v2 Higher Bandwidth (no features) +espmxdevkit.menu.ip.hb2n.build.lwip_include=lwip2/include +espmxdevkit.menu.ip.hb2n.build.lwip_lib=-llwip2-1460 +espmxdevkit.menu.ip.hb2n.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=0 -DLWIP_IPV6=0 +espmxdevkit.menu.ip.lm6f=v2 IPv6 Lower Memory +espmxdevkit.menu.ip.lm6f.build.lwip_include=lwip2/include +espmxdevkit.menu.ip.lm6f.build.lwip_lib=-llwip6-536-feat +espmxdevkit.menu.ip.lm6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +espmxdevkit.menu.ip.hb6f=v2 IPv6 Higher Bandwidth +espmxdevkit.menu.ip.hb6f.build.lwip_include=lwip2/include +espmxdevkit.menu.ip.hb6f.build.lwip_lib=-llwip6-1460-feat +espmxdevkit.menu.ip.hb6f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=1460 -DLWIP_FEATURES=1 -DLWIP_IPV6=1 +espmxdevkit.menu.ip.hb1=v1.4 Higher Bandwidth +espmxdevkit.menu.ip.hb1.build.lwip_lib=-llwip_gcc +espmxdevkit.menu.ip.hb1.build.lwip_flags=-DLWIP_OPEN_SRC +espmxdevkit.menu.ip.src=v1.4 Compile from source +espmxdevkit.menu.ip.src.build.lwip_lib=-llwip_src +espmxdevkit.menu.ip.src.build.lwip_flags=-DLWIP_OPEN_SRC +espmxdevkit.menu.ip.src.recipe.hooks.sketch.prebuild.1.pattern=make -C "{runtime.platform.path}/tools/sdk/lwip/src" install TOOLS_PATH="{runtime.tools.xtensa-lx106-elf-gcc.path}/bin/xtensa-lx106-elf-" +espmxdevkit.menu.dbg.Disabled=Disabled +espmxdevkit.menu.dbg.Disabled.build.debug_port= +espmxdevkit.menu.dbg.Serial=Serial +espmxdevkit.menu.dbg.Serial.build.debug_port=-DDEBUG_ESP_PORT=Serial +espmxdevkit.menu.dbg.Serial1=Serial1 +espmxdevkit.menu.dbg.Serial1.build.debug_port=-DDEBUG_ESP_PORT=Serial1 +espmxdevkit.menu.lvl.None____=None +espmxdevkit.menu.lvl.None____.build.debug_level= +espmxdevkit.menu.lvl.SSL=SSL +espmxdevkit.menu.lvl.SSL.build.debug_level= -DDEBUG_ESP_SSL +espmxdevkit.menu.lvl.TLS_MEM=TLS_MEM +espmxdevkit.menu.lvl.TLS_MEM.build.debug_level= -DDEBUG_ESP_TLS_MEM +espmxdevkit.menu.lvl.HTTP_CLIENT=HTTP_CLIENT +espmxdevkit.menu.lvl.HTTP_CLIENT.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT +espmxdevkit.menu.lvl.HTTP_SERVER=HTTP_SERVER +espmxdevkit.menu.lvl.HTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.SSLTLS_MEM=SSL+TLS_MEM +espmxdevkit.menu.lvl.SSLTLS_MEM.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM +espmxdevkit.menu.lvl.SSLHTTP_CLIENT=SSL+HTTP_CLIENT +espmxdevkit.menu.lvl.SSLHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT +espmxdevkit.menu.lvl.SSLHTTP_SERVER=SSL+HTTP_SERVER +espmxdevkit.menu.lvl.SSLHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.TLS_MEMHTTP_CLIENT=TLS_MEM+HTTP_CLIENT +espmxdevkit.menu.lvl.TLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +espmxdevkit.menu.lvl.TLS_MEMHTTP_SERVER=TLS_MEM+HTTP_SERVER +espmxdevkit.menu.lvl.TLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.HTTP_CLIENTHTTP_SERVER=HTTP_CLIENT+HTTP_SERVER +espmxdevkit.menu.lvl.HTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_CLIENT=SSL+TLS_MEM+HTTP_CLIENT +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_CLIENT.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_SERVER=SSL+TLS_MEM+HTTP_SERVER +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER=SSL+HTTP_CLIENT+HTTP_SERVER +espmxdevkit.menu.lvl.SSLHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER=TLS_MEM+HTTP_CLIENT+HTTP_SERVER +espmxdevkit.menu.lvl.TLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVER.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER +espmxdevkit.menu.lvl.CORE=CORE +espmxdevkit.menu.lvl.CORE.build.debug_level= -DDEBUG_ESP_CORE +espmxdevkit.menu.lvl.WIFI=WIFI +espmxdevkit.menu.lvl.WIFI.build.debug_level= -DDEBUG_ESP_WIFI +espmxdevkit.menu.lvl.HTTP_UPDATE=HTTP_UPDATE +espmxdevkit.menu.lvl.HTTP_UPDATE.build.debug_level= -DDEBUG_ESP_HTTP_UPDATE +espmxdevkit.menu.lvl.UPDATER=UPDATER +espmxdevkit.menu.lvl.UPDATER.build.debug_level= -DDEBUG_ESP_UPDATER +espmxdevkit.menu.lvl.OTA=OTA +espmxdevkit.menu.lvl.OTA.build.debug_level= -DDEBUG_ESP_OTA +espmxdevkit.menu.lvl.OOM=OOM +espmxdevkit.menu.lvl.OOM.build.debug_level= -DDEBUG_ESP_OOM +espmxdevkit.menu.lvl.MDNS=MDNS +espmxdevkit.menu.lvl.MDNS.build.debug_level= -DDEBUG_ESP_MDNS +espmxdevkit.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +espmxdevkit.menu.lvl.COREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS=SSL+TLS_MEM+HTTP_CLIENT+HTTP_SERVER+CORE+WIFI+HTTP_UPDATE+UPDATER+OTA+OOM+MDNS +espmxdevkit.menu.lvl.SSLTLS_MEMHTTP_CLIENTHTTP_SERVERCOREWIFIHTTP_UPDATEUPDATEROTAOOMMDNS.build.debug_level= -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_OOM -DDEBUG_ESP_MDNS +espmxdevkit.menu.lvl.NoAssert-NDEBUG=NoAssert-NDEBUG +espmxdevkit.menu.lvl.NoAssert-NDEBUG.build.debug_level= -DNDEBUG +espmxdevkit.menu.wipe.none=Only Sketch +espmxdevkit.menu.wipe.none.upload.erase_cmd= +espmxdevkit.menu.wipe.sdk=Sketch + WiFi Settings +espmxdevkit.menu.wipe.sdk.upload.erase_cmd=erase_region "{build.rfcal_addr}" 0x4000 +espmxdevkit.menu.wipe.all=All Flash Contents +espmxdevkit.menu.wipe.all.upload.erase_cmd=erase_flash +espmxdevkit.menu.baud.115200=115200 +espmxdevkit.menu.baud.115200.upload.speed=115200 +espmxdevkit.menu.baud.57600=57600 +espmxdevkit.menu.baud.57600.upload.speed=57600 +espmxdevkit.menu.baud.230400.linux=230400 +espmxdevkit.menu.baud.230400.macosx=230400 +espmxdevkit.menu.baud.230400.upload.speed=230400 +espmxdevkit.menu.baud.256000.windows=256000 +espmxdevkit.menu.baud.256000.upload.speed=256000 +espmxdevkit.menu.baud.460800.linux=460800 +espmxdevkit.menu.baud.460800.macosx=460800 +espmxdevkit.menu.baud.460800.upload.speed=460800 +espmxdevkit.menu.baud.512000.windows=512000 +espmxdevkit.menu.baud.512000.upload.speed=512000 +espmxdevkit.menu.baud.921600=921600 +espmxdevkit.menu.baud.921600.upload.speed=921600 +espmxdevkit.menu.baud.3000000=3000000 +espmxdevkit.menu.baud.3000000.upload.speed=3000000 + diff --git a/bootloaders/eboot/Makefile b/bootloaders/eboot/Makefile index 3e25eb139..ff4489e47 100644 --- a/bootloaders/eboot/Makefile +++ b/bootloaders/eboot/Makefile @@ -6,49 +6,57 @@ TARGET_DIR := ./ TARGET_OBJ_FILES := \ eboot.o \ - eboot_command.o \ - + eboot_command.o TARGET_OBJ_PATHS := $(addprefix $(TARGET_DIR)/,$(TARGET_OBJ_FILES)) +UZLIB_PATH := ../../tools/sdk/uzlib/src +UZLIB_FLAGS := -DRUNTIME_BITS_TABLES + CC := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-gcc CXX := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-g++ AR := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-ar LD := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-gcc OBJDUMP := $(XTENSA_TOOLCHAIN)xtensa-lx106-elf-objdump -INC += -I../../tools/sdk/include +INC += -I../../tools/sdk/include -I../../tools/sdk/uzlib/src + CFLAGS += -std=gnu99 -CFLAGS += -O0 -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mno-text-section-literals +CFLAGS += -Os -g -Wall -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mno-text-section-literals -ffunction-sections -fdata-sections CFLAGS += $(INC) -LDFLAGS += -nostdlib -Wl,--no-check-sections -umain +CFLAGS += $(UZLIB_FLAGS) + +LDFLAGS += -nostdlib -Wl,--no-check-sections -Wl,--gc-sections -umain -Wl,-Map,$(@:.elf=.map) LD_SCRIPT := -Teboot.ld -APP_OUT:= eboot.elf -APP_AR := eboot.a -APP_FW := eboot.bin +APP_OUT := eboot.elf +APP_AR := eboot.a +APP_FW := eboot.bin -all: $(APP_FW) -$(APP_AR): $(TARGET_OBJ_PATHS) +all: $(APP_OUT) + +tinflate.o: $(UZLIB_PATH)/tinflate.c $(UZLIB_PATH)/uzlib.h $(UZLIB_PATH)/uzlib_conf.h + $(CC) $(CFLAGS) -c -o tinflate.o $(UZLIB_PATH)/tinflate.c + +tinfgzip.o: $(UZLIB_PATH)/tinfgzip.c $(UZLIB_PATH)/uzlib.h $(UZLIB_PATH)/uzlib_conf.h + $(CC) $(CFLAGS) -c -o tinfgzip.o $(UZLIB_PATH)/tinfgzip.c + +$(APP_AR): $(TARGET_OBJ_PATHS) tinflate.o tinfgzip.o $(AR) cru $@ $^ - -$(APP_OUT): $(APP_AR) +$(APP_OUT): $(APP_AR) eboot.ld | Makefile $(LD) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group -Wl,--whole-archive $(APP_AR) -Wl,--end-group -o $@ -$(APP_FW): $(APP_OUT) - $(ESPTOOL) -vvv -eo $(APP_OUT) -bo $@ -bs .text -bs .data -bs .rodata -bc -ec || true - - clean: rm -f *.o rm -f $(APP_AR) rm -f $(APP_OUT) + rm -f *.map .PHONY: all clean default diff --git a/bootloaders/eboot/eboot.c b/bootloaders/eboot/eboot.c index 69bc692e9..c7cf285c0 100644 --- a/bootloaders/eboot/eboot.c +++ b/bootloaders/eboot/eboot.c @@ -12,6 +12,9 @@ #include #include "flash.h" #include "eboot_command.h" +#include + +extern unsigned char _gzip_dict; #define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0); @@ -24,10 +27,14 @@ int print_version(const uint32_t flash_addr) if (SPIRead(flash_addr + APP_START_OFFSET + sizeof(image_header_t) + sizeof(section_header_t), &ver, sizeof(ver))) { return 1; } - const char* __attribute__ ((aligned (4))) fmtt = "v%08x\n\0\0"; - uint32_t fmt[2]; - fmt[0] = ((uint32_t*) fmtt)[0]; - fmt[1] = ((uint32_t*) fmtt)[1]; + char fmt[7]; + fmt[0] = 'v'; + fmt[1] = '%'; + fmt[2] = '0'; + fmt[3] = '8'; + fmt[4] = 'x'; + fmt[5] = '\n'; + fmt[6] = 0; ets_printf((const char*) fmt, ver); return 0; } @@ -80,37 +87,96 @@ int load_app_from_flash_raw(const uint32_t flash_addr) pos += section_header.size; } - register uint32_t sp asm("a1") = 0x3ffffff0; - register uint32_t pc asm("a3") = image_header.entry; - __asm__ __volatile__ ("jx a3"); + asm volatile("" ::: "memory"); + asm volatile ("mov.n a1, %0\n" + "mov.n a3, %1\n" + "jx a3\n" : : "r" (0x3ffffff0), "r" (image_header.entry) ); + __builtin_unreachable(); // Save a few bytes by letting GCC know no need to pop regs/return return 0; } +uint8_t read_flash_byte(const uint32_t addr) +{ + uint8_t __attribute__((aligned(4))) buff[4]; + SPIRead(addr & ~3, buff, 4); + return buff[addr & 3]; +} +unsigned char __attribute__((aligned(4))) uzlib_flash_read_cb_buff[4096]; +uint32_t uzlib_flash_read_cb_addr; +int uzlib_flash_read_cb(struct uzlib_uncomp *m) +{ + m->source = uzlib_flash_read_cb_buff; + m->source_limit = uzlib_flash_read_cb_buff + sizeof(uzlib_flash_read_cb_buff); + SPIRead(uzlib_flash_read_cb_addr, uzlib_flash_read_cb_buff, sizeof(uzlib_flash_read_cb_buff)); + uzlib_flash_read_cb_addr += sizeof(uzlib_flash_read_cb_buff); + return *(m->source++); +} +unsigned char gzip_dict[32768]; int copy_raw(const uint32_t src_addr, const uint32_t dst_addr, const uint32_t size) { // require regions to be aligned - if (src_addr & 0xfff != 0 || - dst_addr & 0xfff != 0) { + if ((src_addr & 0xfff) != 0 || + (dst_addr & 0xfff) != 0) { return 1; } const uint32_t buffer_size = FLASH_SECTOR_SIZE; uint8_t buffer[buffer_size]; - uint32_t left = ((size+buffer_size-1) & ~(buffer_size-1)); + int32_t left = ((size+buffer_size-1) & ~(buffer_size-1)); uint32_t saddr = src_addr; uint32_t daddr = dst_addr; + struct uzlib_uncomp m_uncomp; + bool gzip = false; - while (left) { + // Check if we are uncompressing a GZIP upload or not + if ((read_flash_byte(saddr) == 0x1f) && (read_flash_byte(saddr + 1) == 0x8b)) { + // GZIP signature matched. Find real size as encoded at the end + left = read_flash_byte(saddr + size - 4); + left += read_flash_byte(saddr + size - 3)<<8; + left += read_flash_byte(saddr + size - 2)<<16; + left += read_flash_byte(saddr + size - 1)<<24; + + uzlib_init(); + + /* all 3 fields below must be initialized by user */ + m_uncomp.source = NULL; + m_uncomp.source_limit = NULL; + uzlib_flash_read_cb_addr = src_addr; + m_uncomp.source_read_cb = uzlib_flash_read_cb; + uzlib_uncompress_init(&m_uncomp, gzip_dict, sizeof(gzip_dict)); + + int res = uzlib_gzip_parse_header(&m_uncomp); + if (res != TINF_OK) { + return 5; // Error uncompress header read + } + gzip = true; + } + while (left > 0) { if (SPIEraseSector(daddr/buffer_size)) { return 2; } - if (SPIRead(saddr, buffer, buffer_size)) { - return 3; + if (!gzip) { + if (SPIRead(saddr, buffer, buffer_size)) { + return 3; + } + } else { + m_uncomp.dest_start = buffer; + m_uncomp.dest = buffer; + int to_read = (left > buffer_size) ? buffer_size : left; + m_uncomp.dest_limit = buffer + to_read; + int res = uzlib_uncompress(&m_uncomp); + if ((res != TINF_DONE) && (res != TINF_OK)) { + return 6; + } + // Fill any remaining with 0xff + for (int i = to_read; i < buffer_size; i++) { + buffer[i] = 0xff; + } } if (SPIWrite(daddr, buffer, buffer_size)) { return 4; @@ -124,17 +190,17 @@ int copy_raw(const uint32_t src_addr, } - -void main() +int main() { int res = 9; + bool clear_cmd = false; struct eboot_command cmd; - + print_version(0); if (eboot_command_read(&cmd) == 0) { // valid command was passed via RTC_MEM - eboot_command_clear(); + clear_cmd = true; ets_putc('@'); } else { // no valid command found @@ -155,6 +221,10 @@ void main() } } + if (clear_cmd) { + eboot_command_clear(); + } + if (cmd.action == ACTION_LOAD_APP) { ets_putc('l'); ets_putc('d'); ets_putc('\n'); res = load_app_from_flash_raw(cmd.args[0]); @@ -167,4 +237,7 @@ void main() } while(true){} + + __builtin_unreachable(); + return 0; } diff --git a/bootloaders/eboot/eboot.elf b/bootloaders/eboot/eboot.elf index da0f84527..0d862f6a9 100755 Binary files a/bootloaders/eboot/eboot.elf and b/bootloaders/eboot/eboot.elf differ diff --git a/bootloaders/eboot/eboot.ld b/bootloaders/eboot/eboot.ld index 303ae8a56..c664daf66 100644 --- a/bootloaders/eboot/eboot.ld +++ b/bootloaders/eboot/eboot.ld @@ -68,6 +68,8 @@ SECTIONS .data : ALIGN(4) { + *(COMMON) /* Global vars */ + . = ALIGN(4); _heap_start = ABSOLUTE(.); /* _stack_sentry = ALIGN(0x8); */ } >dram0_0_seg :dram0_0_bss_phdr @@ -150,9 +152,26 @@ SECTIONS *(.bss) *(.bss.*) *(.gnu.linkonce.b.*) - *(COMMON) . = ALIGN (8); _bss_end = ABSOLUTE(.); + _free_space = 4096 - 17 - (. - _stext); +/* +The boot loader checksum must be before the CRC, which is written by elf2bin.py. +This leaves 16 bytes after the checksum for the CRC placed at the end of the +4096-byte sector. */ + _cs_here = (ALIGN((. + 1), 16) == ALIGN(16)) ? (ALIGN(16) - 1) : (. + 0x0F); + +/* +The filling (padding) and values for _crc_size and _crc_val are handled by +elf2bin.py. With this, we give values to the symbols without explicitly +assigning space. This avoids the linkers back *fill* operation that causes +trouble. + +The CRC info is stored in last 8 bytes. */ + _crc_size = _stext + 4096 - 8; + _crc_val = _stext + 4096 - 4; + ASSERT((4096 > (17 + (. - _stext))), "Error: No space for CS and CRC in bootloader sector."); + ASSERT((_crc_size > _cs_here), "Error: CRC must be located after CS."); } >iram1_0_seg :iram1_0_phdr .lit4 : ALIGN(4) diff --git a/bootloaders/eboot/eboot_command.c b/bootloaders/eboot/eboot_command.c index 648039e48..54d4895c9 100644 --- a/bootloaders/eboot/eboot_command.c +++ b/bootloaders/eboot/eboot_command.c @@ -37,7 +37,7 @@ int eboot_command_read(struct eboot_command* cmd) } uint32_t crc32 = eboot_command_calculate_crc32(cmd); - if (cmd->magic & EBOOT_MAGIC_MASK != EBOOT_MAGIC || + if ((cmd->magic & EBOOT_MAGIC_MASK) != EBOOT_MAGIC || cmd->crc32 != crc32) { return 1; } diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 54919ba10..a4e00ec73 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -204,6 +204,7 @@ void setup(void); void loop(void); void yield(void); + void optimistic_yield(uint32_t interval_us); #define _PORT_GPIO16 1 @@ -281,6 +282,13 @@ void configTime(int timezone, int daylightOffset_sec, const char* server1, void configTime(const char* tz, const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); +// esp32 api compatibility +inline void configTzTime(const char* tz, const char* server1, + const char* server2 = nullptr, const char* server3 = nullptr) +{ + configTime(tz, server1, server2, server3); +} + #endif // __cplusplus #include "pins_arduino.h" diff --git a/cores/esp8266/CallBackList.h b/cores/esp8266/CallBackList.h new file mode 100644 index 000000000..187c86c2a --- /dev/null +++ b/cores/esp8266/CallBackList.h @@ -0,0 +1,84 @@ +#ifndef __CALLBACKLIST_H__ +#define __CALLBACKLIST_H__ + + +/* + CallBackList, An implemention for handling callback execution + + Copyright (c) 2019 Herman Reintke. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +namespace experimental +{ +namespace CBListImplentation +{ + +template +class CallBackList +{ +public: + CallBackList (){}; + + struct CallBackInfo + { + CallBackInfo(cbFunctionT f) : cbFunction(f, true){}; + CallBackInfo(cbFunctionT f, bool ar) : cbFunction(f), _allowRemove(ar) {}; + cbFunctionT cbFunction; + bool _allowRemove = true; + bool allowRemove() + { + return _allowRemove; + } + }; + using CallBackHandler = std::shared_ptr ; + std::list callBackEventList; + + CallBackHandler add(cbFunctionT af, bool ad = true) { + CallBackHandler handler = std::make_shared(CallBackInfo(af,ad)); + callBackEventList.emplace_back(handler); + return handler; + } + + void remove(CallBackHandler& dh) { + callBackEventList.remove(dh); + } + + template + void execute(Args... params) { + for(auto it = std::begin(callBackEventList); it != std::end(callBackEventList); ) { + CallBackHandler &handler = *it; + if (handler->allowRemove() && handler.unique()) { + it = callBackEventList.erase(it); + } + else { + handler->cbFunction(params...); + ++it; + } + } + } +}; + +} //CBListImplementation +}//experimental + +#endif // __CALLBACKLIST_H__ diff --git a/cores/esp8266/Esp-version.cpp b/cores/esp8266/Esp-version.cpp index bdc610864..f92aa2a54 100644 --- a/cores/esp8266/Esp-version.cpp +++ b/cores/esp8266/Esp-version.cpp @@ -28,29 +28,41 @@ #define STRHELPER(x) #x #define STR(x) STRHELPER(x) // stringifier -static const char arduino_esp8266_git_ver [] PROGMEM = STR(ARDUINO_ESP8266_GIT_DESC); +static const char arduino_esp8266_git_ver [] PROGMEM = "/Core:" STR(ARDUINO_ESP8266_GIT_DESC) "="; +#if LWIP_VERSION_MAJOR > 1 +#if LWIP_IPV6 +static const char lwip_version [] PROGMEM = "/lwIP:IPv6+" LWIP_HASH_STR; +#else +static const char lwip_version [] PROGMEM = "/lwIP:" LWIP_HASH_STR; +#endif +#endif static const char bearssl_version [] PROGMEM = "/BearSSL:" STR(BEARSSL_GIT); -String EspClass::getFullVersion() -{ - return String(F("SDK:")) + system_get_sdk_version() - + F("/Core:") + FPSTR(arduino_esp8266_git_ver) - + F("=") + String(esp8266::coreVersionNumeric()) +String EspClass::getFullVersion() { + String s(F("SDK:")); + s.reserve(127); + + s += system_get_sdk_version(); + s += FPSTR(arduino_esp8266_git_ver); + s += String(esp8266::coreVersionNumeric()); #if LWIP_VERSION_MAJOR == 1 - + F("/lwIP:") + String(LWIP_VERSION_MAJOR) + "." + String(LWIP_VERSION_MINOR) + "." + String(LWIP_VERSION_REVISION) + s += F("/lwIP:"); + s += LWIP_VERSION_MAJOR; + s += '.'; + s += LWIP_VERSION_MINOR; + s += '.'; + s += LWIP_VERSION_REVISION; #if LWIP_VERSION_IS_DEVELOPMENT - + F("-dev") + s += F("-dev"); #endif #if LWIP_VERSION_IS_RC - + F("rc") + String(LWIP_VERSION_RC) + s += F("rc"); + s += String(LWIP_VERSION_RC); #endif #else // LWIP_VERSION_MAJOR != 1 - + F("/lwIP:") -#if LWIP_IPV6 - + F("IPv6+") -#endif // LWIP_IPV6 - + F(LWIP_HASH_STR) + s += FPSTR(lwip_version); #endif // LWIP_VERSION_MAJOR != 1 - + FPSTR(bearssl_version) - ; + s += FPSTR(bearssl_version); + + return s; } diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 29222d6df..a0e525f2b 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -26,6 +26,7 @@ #include "MD5Builder.h" #include "umm_malloc/umm_malloc.h" #include "cont.h" +#include "coredecls.h" extern "C" { #include "user_interface.h" @@ -447,35 +448,57 @@ bool EspClass::checkFlashConfig(bool needsEquals) { return false; } +bool EspClass::checkFlashCRC() { + // The CRC and total length are placed in extra space at the end of the 4K chunk + // of flash occupied by the bootloader. If the bootloader grows to >4K-8 bytes, + // we'll need to adjust this. + uint32_t flashsize = *((uint32_t*)(0x40200000 + 4088)); // Start of PROGMEM plus 4K-8 + uint32_t flashcrc = *((uint32_t*)(0x40200000 + 4092)); // Start of PROGMEM plus 4K-4 + uint32_t z[2]; + z[0] = z[1] = 0; + + // Start the checksum + uint32_t crc = crc32((const void*)0x40200000, 4096-8, 0xffffffff); + // Pretend the 2 words of crc/len are zero to be idempotent + crc = crc32(z, 8, crc); + // Finish the CRC calculation over the rest of flash + crc = crc32((const void*)0x40201000, flashsize-4096, crc); + return crc == flashcrc; +} + + String EspClass::getResetReason(void) { - char buff[32]; - if (resetInfo.reason == REASON_DEFAULT_RST) { // normal startup by power on - strcpy_P(buff, PSTR("Power on")); - } else if (resetInfo.reason == REASON_WDT_RST) { // hardware watch dog reset - strcpy_P(buff, PSTR("Hardware Watchdog")); - } else if (resetInfo.reason == REASON_EXCEPTION_RST) { // exception reset, GPIO status won’t change - strcpy_P(buff, PSTR("Exception")); - } else if (resetInfo.reason == REASON_SOFT_WDT_RST) { // software watch dog reset, GPIO status won’t change - strcpy_P(buff, PSTR("Software Watchdog")); - } else if (resetInfo.reason == REASON_SOFT_RESTART) { // software restart ,system_restart , GPIO status won’t change - strcpy_P(buff, PSTR("Software/System restart")); - } else if (resetInfo.reason == REASON_DEEP_SLEEP_AWAKE) { // wake up from deep-sleep - strcpy_P(buff, PSTR("Deep-Sleep Wake")); - } else if (resetInfo.reason == REASON_EXT_SYS_RST) { // external system reset - strcpy_P(buff, PSTR("External System")); - } else { - strcpy_P(buff, PSTR("Unknown")); + const __FlashStringHelper* buff; + + switch(resetInfo.reason) { + // normal startup by power on + case REASON_DEFAULT_RST: buff = F("Power On"); break; + // hardware watch dog reset + case REASON_WDT_RST: buff = F("Hardware Watchdog"); break; + // exception reset, GPIO status won’t change + case REASON_EXCEPTION_RST: buff = F("Exception"); break; + // software watch dog reset, GPIO status won’t change + case REASON_SOFT_WDT_RST: buff = F("Software Watchdog"); break; + // software restart ,system_restart , GPIO status won’t change + case REASON_SOFT_RESTART: buff = F("Software/System restart"); break; + // wake up from deep-sleep + case REASON_DEEP_SLEEP_AWAKE: buff = F("Deep-Sleep Wake"); break; + // // external system reset + case REASON_EXT_SYS_RST: buff = F("External System"); break; + default: buff = F("Unknown"); break; } return String(buff); } String EspClass::getResetInfo(void) { - if(resetInfo.reason != 0) { + if (resetInfo.reason >= REASON_WDT_RST && resetInfo.reason <= REASON_SOFT_WDT_RST) { char buff[200]; - sprintf(&buff[0], "Fatal exception:%d flag:%d (%s) epc1:0x%08x epc2:0x%08x epc3:0x%08x excvaddr:0x%08x depc:0x%08x", resetInfo.exccause, resetInfo.reason, (resetInfo.reason == 0 ? "DEFAULT" : resetInfo.reason == 1 ? "WDT" : resetInfo.reason == 2 ? "EXCEPTION" : resetInfo.reason == 3 ? "SOFT_WDT" : resetInfo.reason == 4 ? "SOFT_RESTART" : resetInfo.reason == 5 ? "DEEP_SLEEP_AWAKE" : resetInfo.reason == 6 ? "EXT_SYS_RST" : "???"), resetInfo.epc1, resetInfo.epc2, resetInfo.epc3, resetInfo.excvaddr, resetInfo.depc); + sprintf_P(buff, PSTR("Fatal exception:%d flag:%d (%s) epc1:0x%08x epc2:0x%08x epc3:0x%08x excvaddr:0x%08x depc:0x%08x"), + resetInfo.exccause, resetInfo.reason, getResetReason().c_str(), + resetInfo.epc1, resetInfo.epc2, resetInfo.epc3, resetInfo.excvaddr, resetInfo.depc); return String(buff); } - return String("flag: 0"); + return getResetReason(); } struct rst_info * EspClass::getResetInfoPtr(void) { diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index 726633d61..f4529c839 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -176,6 +176,8 @@ class EspClass { bool checkFlashConfig(bool needsEquals = false); + bool checkFlashCRC(); + bool flashEraseSector(uint32_t sector); bool flashWrite(uint32_t offset, uint32_t *data, size_t size); bool flashRead(uint32_t offset, uint32_t *data, size_t size); diff --git a/cores/esp8266/FS.cpp b/cores/esp8266/FS.cpp index d7baa4306..392955d49 100644 --- a/cores/esp8266/FS.cpp +++ b/cores/esp8266/FS.cpp @@ -180,6 +180,26 @@ String File::readString() return ret; } +time_t File::getLastWrite() { + if (!_p) + return 0; + + return _p->getLastWrite(); +} + +time_t File::getCreationTime() { + if (!_p) + return 0; + + return _p->getCreationTime(); +} + +void File::setTimeCallback(time_t (*cb)(void)) { + if (!_p) + return; + _p->setTimeCallback(cb); +} + File Dir::openFile(const char* mode) { if (!_impl) { return File(); @@ -192,7 +212,9 @@ File Dir::openFile(const char* mode) { return File(); } - return File(_impl->openFile(om, am), _baseFS); + File f(_impl->openFile(om, am), _baseFS); + f.setTimeCallback(timeCallback); + return f; } String Dir::fileName() { @@ -203,6 +225,18 @@ String Dir::fileName() { return _impl->fileName(); } +time_t Dir::fileTime() { + if (!_impl) + return 0; + return _impl->fileTime(); +} + +time_t Dir::fileCreationTime() { + if (!_impl) + return 0; + return _impl->fileCreationTime(); +} + size_t Dir::fileSize() { if (!_impl) { return 0; @@ -241,6 +275,14 @@ bool Dir::rewind() { return _impl->rewind(); } +void Dir::setTimeCallback(time_t (*cb)(void)) { + if (!_impl) + return; + _impl->setTimeCallback(cb); + timeCallback = cb; +} + + bool FS::setConfig(const FSConfig &cfg) { if (!_impl) { return false; @@ -254,6 +296,7 @@ bool FS::begin() { DEBUGV("#error: FS: no implementation"); return false; } + _impl->setTimeCallback(timeCallback); bool ret = _impl->begin(); DEBUGV("%s\n", ret? "": "#error: FS could not start"); return ret; @@ -315,7 +358,9 @@ File FS::open(const char* path, const char* mode) { DEBUGV("FS::open: invalid mode `%s`\r\n", mode); return File(); } - return File(_impl->open(path, om, am), this); + File f(_impl->open(path, om, am), this); + f.setTimeCallback(timeCallback); + return f; } bool FS::exists(const char* path) { @@ -334,7 +379,9 @@ Dir FS::openDir(const char* path) { return Dir(); } DirImplPtr p = _impl->openDir(path); - return Dir(p, this); + Dir d(p, this); + d.setTimeCallback(timeCallback); + return d; } Dir FS::openDir(const String& path) { @@ -385,6 +432,11 @@ bool FS::rename(const String& pathFrom, const String& pathTo) { return rename(pathFrom.c_str(), pathTo.c_str()); } +void FS::setTimeCallback(time_t (*cb)(void)) { + if (!_impl) + return; + _impl->setTimeCallback(cb); +} static bool sflags(const char* mode, OpenMode& om, AccessMode& am) { diff --git a/cores/esp8266/FS.h b/cores/esp8266/FS.h index 669287876..aa4752781 100644 --- a/cores/esp8266/FS.h +++ b/cores/esp8266/FS.h @@ -23,6 +23,7 @@ #include #include +#include <../include/time.h> // See issue #6714 class SDClass; @@ -110,6 +111,10 @@ public: String readString() override; + time_t getLastWrite(); + time_t getCreationTime(); + void setTimeCallback(time_t (*cb)(void)); + protected: FileImplPtr _p; @@ -126,15 +131,20 @@ public: String fileName(); size_t fileSize(); + time_t fileTime(); + time_t fileCreationTime(); bool isFile() const; bool isDirectory() const; bool next(); bool rewind(); + void setTimeCallback(time_t (*cb)(void)); + protected: DirImplPtr _impl; FS *_baseFS; + time_t (*timeCallback)(void) = nullptr; }; // Backwards compatible, <4GB filesystem usage @@ -161,12 +171,10 @@ struct FSInfo64 { class FSConfig { public: - FSConfig(bool autoFormat = true) { - _type = FSConfig::fsid::FSId; - _autoFormat = autoFormat; - } + static constexpr uint32_t FSId = 0x00000000; + + FSConfig(uint32_t type = FSId, bool autoFormat = true) : _type(type), _autoFormat(autoFormat) { } - enum fsid { FSId = 0x00000000 }; FSConfig setAutoFormat(bool val = true) { _autoFormat = val; return *this; @@ -179,17 +187,17 @@ public: class SPIFFSConfig : public FSConfig { public: - SPIFFSConfig(bool autoFormat = true) { - _type = SPIFFSConfig::fsid::FSId; - _autoFormat = autoFormat; - } - enum fsid { FSId = 0x53504946 }; + static constexpr uint32_t FSId = 0x53504946; + SPIFFSConfig(bool autoFormat = true) : FSConfig(FSId, autoFormat) { } + + // Inherit _type and _autoFormat + // nothing yet, enableTime TBD when SPIFFS has metadate }; class FS { public: - FS(FSImplPtr impl) : _impl(impl) { } + FS(FSImplPtr impl) : _impl(impl) { timeCallback = _defaultTimeCB; } bool setConfig(const FSConfig &cfg); @@ -225,14 +233,25 @@ public: bool gc(); bool check(); + void setTimeCallback(time_t (*cb)(void)); + friend class ::SDClass; // More of a frenemy, but SD needs internal implementation to get private FAT bits protected: FSImplPtr _impl; FSImplPtr getImpl() { return _impl; } + time_t (*timeCallback)(void); + static time_t _defaultTimeCB(void) { return time(NULL); } }; } // namespace fs +extern "C" +{ +void close_all_fs(void); +void littlefs_request_end(void); +void spiffs_request_end(void); +} + #ifndef FS_NO_GLOBALS using fs::FS; using fs::File; diff --git a/cores/esp8266/FSImpl.h b/cores/esp8266/FSImpl.h index b7cf4a7a6..1a3566f2c 100644 --- a/cores/esp8266/FSImpl.h +++ b/cores/esp8266/FSImpl.h @@ -41,6 +41,21 @@ public: virtual const char* fullName() const = 0; virtual bool isFile() const = 0; virtual bool isDirectory() const = 0; + + // Filesystems *may* support a timestamp per-file, so allow the user to override with + // their own callback for *this specific* file (as opposed to the FSImpl call of the + // same name. The default implementation simply returns time(&null) + virtual void setTimeCallback(time_t (*cb)(void)) { timeCallback = cb; } + + // Return the last written time for a file. Undefined when called on a writable file + // as the FS is allowed to return either the time of the last write() operation or the + // time present in the filesystem metadata (often the last time the file was closed) + virtual time_t getLastWrite() { return 0; } // Default is to not support timestamps + // Same for creation time. + virtual time_t getCreationTime() { return 0; } // Default is to not support timestamps + +protected: + time_t (*timeCallback)(void) = nullptr; }; enum OpenMode { @@ -62,10 +77,23 @@ public: virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0; virtual const char* fileName() = 0; virtual size_t fileSize() = 0; + // Return the last written time for a file. Undefined when called on a writable file + // as the FS is allowed to return either the time of the last write() operation or the + // time present in the filesystem metadata (often the last time the file was closed) + virtual time_t fileTime() { return 0; } // By default, FS doesn't report file times + virtual time_t fileCreationTime() { return 0; } // By default, FS doesn't report file times virtual bool isFile() const = 0; virtual bool isDirectory() const = 0; virtual bool next() = 0; virtual bool rewind() = 0; + + // Filesystems *may* support a timestamp per-file, so allow the user to override with + // their own callback for *this specific* file (as opposed to the FSImpl call of the + // same name. The default implementation simply returns time(&null) + virtual void setTimeCallback(time_t (*cb)(void)) { timeCallback = cb; } + +protected: + time_t (*timeCallback)(void) = nullptr; }; class FSImpl { @@ -86,6 +114,14 @@ public: virtual bool rmdir(const char* path) = 0; virtual bool gc() { return true; } // May not be implemented in all file systems. virtual bool check() { return true; } // May not be implemented in all file systems. + + // Filesystems *may* support a timestamp per-file, so allow the user to override with + // their own callback for all files on this FS. The default implementation simply + // returns the present time as reported by time(&null) + virtual void setTimeCallback(time_t (*cb)(void)) { timeCallback = cb; } + +protected: + time_t (*timeCallback)(void) = nullptr; }; } // namespace fs diff --git a/cores/esp8266/FSnoop.cpp b/cores/esp8266/FSnoop.cpp new file mode 100644 index 000000000..6cead006f --- /dev/null +++ b/cores/esp8266/FSnoop.cpp @@ -0,0 +1,33 @@ +/* + * no-op implementations + * used/linked when no strong implementation already exists elsewhere + */ + +#include + +extern "C" +{ + +void close_all_fs(void) +{ + littlefs_request_end(); + spiffs_request_end(); +} + +// default weak definitions +// they are overriden in their respective real implementation +// hint: https://github.com/esp8266/Arduino/pull/6699#issuecomment-549085382 + +void littlefs_request_end(void) __attribute__((weak)); +void littlefs_request_end(void) +{ + //ets_printf("debug: noop: littlefs_request_end\n"); +} + +void spiffs_request_end(void) __attribute__((weak)); +void spiffs_request_end(void) +{ + //ets_printf("debug: noop: spiffs_request_end\n"); +} + +} diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp index 129b55eda..5f7ea141c 100644 --- a/cores/esp8266/HardwareSerial.cpp +++ b/cores/esp8266/HardwareSerial.cpp @@ -36,10 +36,10 @@ HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _rx_size(256) {} -void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) +void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin, bool invert) { end(); - _uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size); + _uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size, invert); #if defined(DEBUG_ESP_PORT) && !defined(NDEBUG) if (static_cast(this) == static_cast(&DEBUG_ESP_PORT)) { @@ -133,7 +133,7 @@ unsigned long HardwareSerial::testBaudrate() unsigned long HardwareSerial::detectBaudrate(time_t timeoutMillis) { esp8266::polledTimeout::oneShotFastMs timeOut(timeoutMillis); - unsigned long detectedBaudrate; + unsigned long detectedBaudrate = 0; while (!timeOut) { if ((detectedBaudrate = testBaudrate())) { break; diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h index 2d7f631db..dd12e96d2 100644 --- a/cores/esp8266/HardwareSerial.h +++ b/cores/esp8266/HardwareSerial.h @@ -28,7 +28,7 @@ #define HardwareSerial_h #include -#include +#include <../include/time.h> // See issue #6714 #include "Stream.h" #include "uart.h" @@ -73,18 +73,23 @@ public: void begin(unsigned long baud) { - begin(baud, SERIAL_8N1, SERIAL_FULL, 1); + begin(baud, SERIAL_8N1, SERIAL_FULL, 1, false); } void begin(unsigned long baud, SerialConfig config) { - begin(baud, config, SERIAL_FULL, 1); + begin(baud, config, SERIAL_FULL, 1, false); } void begin(unsigned long baud, SerialConfig config, SerialMode mode) { - begin(baud, config, mode, 1); + begin(baud, config, mode, 1, false); } - void begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin); + void begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) + { + begin(baud, config, mode, tx_pin, false); + } + + void begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin, bool invert); void end(); diff --git a/cores/esp8266/IPAddress.h b/cores/esp8266/IPAddress.h index bf5ef1010..cdd4b2499 100644 --- a/cores/esp8266/IPAddress.h +++ b/cores/esp8266/IPAddress.h @@ -32,6 +32,7 @@ #define LWIP_IPV6_NUM_ADDRESSES 0 #define ip_2_ip4(x) (x) #define ipv4_addr ip_addr +#define ipv4_addr_t ip_addr_t #define IP_IS_V4_VAL(x) (1) #define IP_SET_TYPE_VAL(x,y) do { (void)0; } while (0) #define IP_ANY_TYPE (&ip_addr_any) diff --git a/cores/esp8266/Print.cpp b/cores/esp8266/Print.cpp index ff640edae..d93293ee8 100644 --- a/cores/esp8266/Print.cpp +++ b/cores/esp8266/Print.cpp @@ -104,11 +104,19 @@ size_t Print::printf_P(PGM_P format, ...) { size_t Print::print(const __FlashStringHelper *ifsh) { PGM_P p = reinterpret_cast(ifsh); + char buff[128] __attribute__ ((aligned(4))); + auto len = strlen_P(p); size_t n = 0; - while (1) { - uint8_t c = pgm_read_byte(p++); - if (c == 0) break; - n += write(c); + while (n < len) { + int to_write = std::min(sizeof(buff), len - n); + memcpy_P(buff, p, to_write); + auto written = write(buff, to_write); + n += written; + p += written; + if (!written) { + // Some error, write() should write at least 1 byte before returning + break; + } } return n; } @@ -260,47 +268,6 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { } size_t Print::printFloat(double number, uint8_t digits) { - size_t n = 0; - - if(isnan(number)) - return print("nan"); - if(isinf(number)) - return print("inf"); - if(number > 4294967040.0) - return print("ovf"); // constant determined empirically - if(number < -4294967040.0) - return print("ovf"); // constant determined empirically - - // Handle negative numbers - if(number < 0.0) { - n += print('-'); - number = -number; - } - - // Round correctly so that print(1.999, 2) prints as "2.00" - double rounding = 0.5; - for(uint8_t i = 0; i < digits; ++i) - rounding /= 10.0; - - number += rounding; - - // Extract the integer part of the number and print it - unsigned long int_part = (unsigned long) number; - double remainder = number - (double) int_part; - n += print(int_part); - - // Print the decimal point, but only if there are digits beyond - if(digits > 0) { - n += print("."); - } - - // Extract digits from the remainder one at a time - while(digits-- > 0) { - remainder *= 10.0; - int toPrint = int(remainder); - n += print(toPrint); - remainder -= toPrint; - } - - return n; + char buf[40]; + return write(dtostrf(number, 0, digits, buf)); } diff --git a/cores/esp8266/Print.h b/cores/esp8266/Print.h index e620f14ad..e43883b39 100644 --- a/cores/esp8266/Print.h +++ b/cores/esp8266/Print.h @@ -26,6 +26,8 @@ #include "WString.h" #include "Printable.h" +#include "stdlib_noniso.h" + #define DEC 10 #define HEX 16 #define OCT 8 diff --git a/cores/esp8266/Schedule.cpp b/cores/esp8266/Schedule.cpp index 465521e51..9cb86c8d1 100644 --- a/cores/esp8266/Schedule.cpp +++ b/cores/esp8266/Schedule.cpp @@ -119,23 +119,33 @@ void run_scheduled_functions() { esp8266::polledTimeout::periodicFastMs yieldNow(100); // yield every 100ms - while (sFirst) + // prevent scheduling of new functions during this run + auto stop = sLast; + bool done = false; + while (sFirst && !done) { + done = sFirst == stop; + sFirst->mFunc(); { + // remove function from stack esp8266::InterruptLock lockAllInterruptsInThisScope; auto to_recycle = sFirst; - sFirst = sFirst->mNext; - if (!sFirst) + + // removing rLast + if (sLast == sFirst) sLast = nullptr; + + sFirst = sFirst->mNext; + recycle_fn_unsafe(to_recycle); } if (yieldNow) { - // because scheduled function are allowed to last: + // because scheduled functions might last too long for watchdog etc, // this is yield() in cont stack: esp_schedule(); cont_yield(g_pcont); diff --git a/cores/esp8266/Schedule.h b/cores/esp8266/Schedule.h index a02241fa6..d33a7c08b 100644 --- a/cores/esp8266/Schedule.h +++ b/cores/esp8266/Schedule.h @@ -46,7 +46,7 @@ void run_scheduled_functions(); // recurrent scheduled function: // -// * Internal queue may not be a FIFO. +// * Internal queue is a FIFO. // * Run the lambda periodically about every microseconds until // it returns false. // * Note that it may be more than microseconds between calls if @@ -60,6 +60,7 @@ void run_scheduled_functions(); // recurrent function. // * If alarm is used, anytime during scheduling when it returns true, // any remaining delay from repeat_us is disregarded, and fn is executed. + bool schedule_recurrent_function_us(const std::function& fn, uint32_t repeat_us, const std::function& alarm = nullptr); diff --git a/cores/esp8266/StackThunk.cpp b/cores/esp8266/StackThunk.cpp index 68e80278d..541cd440f 100644 --- a/cores/esp8266/StackThunk.cpp +++ b/cores/esp8266/StackThunk.cpp @@ -36,7 +36,8 @@ uint32_t *stack_thunk_top = NULL; uint32_t *stack_thunk_save = NULL; /* Saved A1 while in BearSSL */ uint32_t stack_thunk_refcnt = 0; -#define _stackSize (5748/4) +/* Largest stack usage seen in the wild at 6120 */ +#define _stackSize (6200/4) #define _stackPaint 0xdeadbeef /* Add a reference, and allocate the stack if necessary */ @@ -110,14 +111,14 @@ uint32_t stack_thunk_get_max_usage() /* Print the stack from the first used 16-byte chunk to the top, decodable by the exception decoder */ void stack_thunk_dump_stack() { - uint32_t *pos = stack_thunk_top; - while (pos < stack_thunk_ptr) { + uint32_t *pos = stack_thunk_ptr; + while (pos < stack_thunk_top) { if ((pos[0] != _stackPaint) || (pos[1] != _stackPaint) || (pos[2] != _stackPaint) || (pos[3] != _stackPaint)) break; pos += 4; } ets_printf(">>>stack>>>\n"); - while (pos < stack_thunk_ptr) { + while (pos < stack_thunk_top) { ets_printf("%08x: %08x %08x %08x %08x\n", (int32_t)pos, pos[0], pos[1], pos[2], pos[3]); pos += 4; } diff --git a/cores/esp8266/TZ.h b/cores/esp8266/TZ.h index 95b609e61..ef3ed3d44 100644 --- a/cores/esp8266/TZ.h +++ b/cores/esp8266/TZ.h @@ -1,7 +1,7 @@ // autogenerated from https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv // by script /tools/TZupdate.sh -// Mon Sep 9 20:58:30 UTC 2019 +// Mon Dec 16 13:08:18 UTC 2019 // // This database is autogenerated from IANA timezone database // https://www.iana.org/time-zones @@ -407,7 +407,7 @@ #define TZ_Pacific_Efate PSTR("<+11>-11") #define TZ_Pacific_Enderbury PSTR("<+13>-13") #define TZ_Pacific_Fakaofo PSTR("<+13>-13") -#define TZ_Pacific_Fiji PSTR("<+12>-12<+13>,M11.1.0,M1.2.2/123") +#define TZ_Pacific_Fiji PSTR("<+12>-12<+13>,M11.2.0,M1.2.3/99") #define TZ_Pacific_Funafuti PSTR("<+12>-12") #define TZ_Pacific_Galapagos PSTR("<-06>6") #define TZ_Pacific_Gambier PSTR("<-09>9") @@ -422,7 +422,7 @@ #define TZ_Pacific_Midway PSTR("SST11") #define TZ_Pacific_Nauru PSTR("<+12>-12") #define TZ_Pacific_Niue PSTR("<-11>11") -#define TZ_Pacific_Norfolk PSTR("<+11>-11") +#define TZ_Pacific_Norfolk PSTR("<+11>-11<+12>,M10.1.0,M4.1.0/3") #define TZ_Pacific_Noumea PSTR("<+11>-11") #define TZ_Pacific_Pago_Pago PSTR("SST11") #define TZ_Pacific_Palau PSTR("<+09>-9") diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index b028e19b9..70d16a55e 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -104,7 +104,9 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) { _reset(); clearError(); // _error = 0 +#ifndef HOST_MOCK wifi_set_sleep_type(NONE_SLEEP_T); +#endif //address where we will start writing the update uintptr_t updateStartAddress = 0; @@ -329,7 +331,8 @@ bool UpdaterClass::_writeBuffer(){ bool modifyFlashMode = false; FlashMode_t flashMode = FM_QIO; FlashMode_t bufferFlashMode = FM_QIO; - if (_currentAddress == _startAddress + FLASH_MODE_PAGE) { + //TODO - GZIP can't do this + if ((_currentAddress == _startAddress + FLASH_MODE_PAGE) && (_buffer[0] != 0x1f) && (_command == U_FLASH)) { flashMode = ESP.getFlashChipMode(); #ifdef DEBUG_UPDATER DEBUG_UPDATER.printf_P(PSTR("Header: 0x%1X %1X %1X %1X\n"), _buffer[0], _buffer[1], _buffer[2], _buffer[3]); @@ -377,9 +380,7 @@ size_t UpdaterClass::write(uint8_t *data, size_t len) { if(hasError() || !isRunning()) return 0; - if(len > remaining()){ - //len = remaining(); - //fail instead + if(progress() + _bufferLen + len > _size) { _setError(UPDATE_ERROR_SPACE); return 0; } @@ -411,7 +412,7 @@ size_t UpdaterClass::write(uint8_t *data, size_t len) { bool UpdaterClass::_verifyHeader(uint8_t data) { if(_command == U_FLASH) { // check for valid first magic byte (is always 0xE9) - if(data != 0xE9) { + if ((data != 0xE9) && (data != 0x1f)) { _currentAddress = (_startAddress + _size); _setError(UPDATE_ERROR_MAGIC_BYTE); return false; @@ -435,7 +436,12 @@ bool UpdaterClass::_verifyEnd() { } // check for valid first magic byte - if(buf[0] != 0xE9) { + // + // TODO: GZIP compresses the chipsize flags, so can't do check here + if ((buf[0] == 0x1f) && (buf[1] == 0x8b)) { + // GZIP, just assume OK + return true; + } else if (buf[0] != 0xE9) { _currentAddress = (_startAddress); _setError(UPDATE_ERROR_MAGIC_BYTE); return false; diff --git a/cores/esp8266/WMath.cpp b/cores/esp8266/WMath.cpp index 1f0c8d7db..2cc20b9f5 100644 --- a/cores/esp8266/WMath.cpp +++ b/cores/esp8266/WMath.cpp @@ -70,11 +70,11 @@ long secureRandom(long howsmall, long howbig) { } long map(long x, long in_min, long in_max, long out_min, long out_max) { - long divisor = (in_max - in_min); - if(divisor == 0){ - return -1; //AVR returns -1, SAM returns 0 - } - return (x - in_min) * (out_max - out_min) / divisor + out_min; + const long dividend = out_max - out_min; + const long divisor = in_max - in_min; + const long delta = x - in_min; + + return (delta * dividend + (divisor / 2)) / divisor + out_min; } unsigned int makeWord(unsigned int w) { diff --git a/cores/esp8266/WString.cpp b/cores/esp8266/WString.cpp index 5e31b2770..7b9d9db93 100644 --- a/cores/esp8266/WString.cpp +++ b/cores/esp8266/WString.cpp @@ -156,9 +156,9 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) { if (maxStrLen < sizeof(sso.buff) - 1) { if (isSSO() || !buffer()) { // Already using SSO, nothing to do - uint16_t oldLen = len(); + uint16_t oldLen = len(); setSSO(true); - setLen(oldLen); + setLen(oldLen); return 1; } else { // if bufptr && !isSSO() // Using bufptr, need to shrink into sso.buff @@ -167,7 +167,7 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) { free(wbuffer()); uint16_t oldLen = len(); setSSO(true); - setLen(oldLen); + setLen(oldLen); memcpy(wbuffer(), temp, maxStrLen); return 1; } @@ -204,7 +204,7 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) { // /*********************************************/ String & String::copy(const char *cstr, unsigned int length) { - if(!reserve(length)) { + if (!reserve(length)) { invalidate(); return *this; } @@ -225,11 +225,11 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) { #ifdef __GXX_EXPERIMENTAL_CXX0X__ void String::move(String &rhs) { - if(buffer()) { - if(capacity() >= rhs.len()) { + if (buffer()) { + if (capacity() >= rhs.len()) { memmove_P(wbuffer(), rhs.buffer(), rhs.length() + 1); setLen(rhs.len()); - rhs.invalidate(); + rhs.invalidate(); return; } else { if (!isSSO()) { @@ -255,10 +255,10 @@ void String::move(String &rhs) { #endif String & String::operator =(const String &rhs) { - if(this == &rhs) + if (this == &rhs) return *this; - if(rhs.buffer()) + if (rhs.buffer()) copy(rhs.buffer(), rhs.len()); else invalidate(); @@ -268,20 +268,20 @@ String & String::operator =(const String &rhs) { #ifdef __GXX_EXPERIMENTAL_CXX0X__ String & String::operator =(String &&rval) { - if(this != &rval) + if (this != &rval) move(rval); return *this; } String & String::operator =(StringSumHelper &&rval) { - if(this != &rval) + if (this != &rval) move(rval); return *this; } #endif String & String::operator =(const char *cstr) { - if(cstr) + if (cstr) copy(cstr, strlen(cstr)); else invalidate(); @@ -323,19 +323,20 @@ unsigned char String::concat(const String &s) { unsigned char String::concat(const char *cstr, unsigned int length) { unsigned int newlen = len() + length; - if(!cstr) + if (!cstr) return 0; - if(length == 0) + if (length == 0) return 1; - if(!reserve(newlen)) + if (!reserve(newlen)) return 0; memmove_P(wbuffer() + len(), cstr, length + 1); setLen(newlen); + wbuffer()[newlen] = 0; return 1; } unsigned char String::concat(const char *cstr) { - if(!cstr) + if (!cstr) return 0; return concat(cstr, strlen(cstr)); } @@ -406,70 +407,70 @@ unsigned char String::concat(const __FlashStringHelper * str) { StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(rhs.buffer(), rhs.len())) + if (!a.concat(rhs.buffer(), rhs.len())) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr) { StringSumHelper &a = const_cast(lhs); - if(!cstr || !a.concat(cstr, strlen(cstr))) + if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, char c) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(c)) + if (!a.concat(c)) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(num)) + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, int num) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(num)) + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(num)) + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, long num) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(num)) + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(num)) + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, float num) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(num)) + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator +(const StringSumHelper &lhs, double num) { StringSumHelper &a = const_cast(lhs); - if(!a.concat(num)) + if (!a.concat(num)) a.invalidate(); return a; } @@ -502,9 +503,9 @@ unsigned char String::equals(const String &s2) const { } unsigned char String::equals(const char *cstr) const { - if(len() == 0) + if (len() == 0) return (cstr == NULL || *cstr == 0); - if(cstr == NULL) + if (cstr == NULL) return buffer()[0] == 0; return strcmp(buffer(), cstr) == 0; } @@ -526,16 +527,16 @@ unsigned char String::operator>=(const String &rhs) const { } unsigned char String::equalsIgnoreCase(const String &s2) const { - if(this == &s2) + if (this == &s2) return 1; - if(len() != s2.len()) + if (len() != s2.len()) return 0; - if(len() == 0) + if (len() == 0) return 1; const char *p1 = buffer(); const char *p2 = s2.buffer(); - while(*p1) { - if(tolower(*p1++) != tolower(*p2++)) + while (*p1) { + if (tolower(*p1++) != tolower(*p2++)) return 0; } return 1; @@ -544,18 +545,18 @@ unsigned char String::equalsIgnoreCase(const String &s2) const { unsigned char String::equalsConstantTime(const String &s2) const { // To avoid possible time-based attacks present function // compares given strings in a constant time. - if(len() != s2.len()) + if (len() != s2.len()) return 0; //at this point lengths are the same - if(len() == 0) + if (len() == 0) return 1; //at this point lenghts are the same and non-zero const char *p1 = buffer(); const char *p2 = s2.buffer(); unsigned int equalchars = 0; unsigned int diffchars = 0; - while(*p1) { - if(*p1 == *p2) + while (*p1) { + if (*p1 == *p2) ++equalchars; else ++diffchars; @@ -595,13 +596,13 @@ char String::charAt(unsigned int loc) const { } void String::setCharAt(unsigned int loc, char c) { - if(loc < len()) + if (loc < len()) wbuffer()[loc] = c; } char & String::operator[](unsigned int index) { static char dummy_writable_char; - if(index >= len() || !buffer()) { + if (index >= len() || !buffer()) { dummy_writable_char = 0; return dummy_writable_char; } @@ -609,20 +610,20 @@ char & String::operator[](unsigned int index) { } char String::operator[](unsigned int index) const { - if(index >= len() || !buffer()) + if (index >= len() || !buffer()) return 0; return buffer()[index]; } void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const { - if(!bufsize || !buf) + if (!bufsize || !buf) return; - if(index >= len()) { + if (index >= len()) { buf[0] = 0; return; } unsigned int n = bufsize - 1; - if(n > len() - index) + if (n > len() - index) n = len() - index; strncpy((char *) buf, buffer() + index, n); buf[n] = 0; @@ -637,10 +638,10 @@ int String::indexOf(char c) const { } int String::indexOf(char ch, unsigned int fromIndex) const { - if(fromIndex >= len()) + if (fromIndex >= len()) return -1; const char* temp = strchr(buffer() + fromIndex, ch); - if(temp == NULL) + if (temp == NULL) return -1; return temp - buffer(); } @@ -650,10 +651,10 @@ int String::indexOf(const String &s2) const { } int String::indexOf(const String &s2, unsigned int fromIndex) const { - if(fromIndex >= len()) + if (fromIndex >= len()) return -1; const char *found = strstr(buffer() + fromIndex, s2.buffer()); - if(found == NULL) + if (found == NULL) return -1; return found - buffer(); } @@ -663,13 +664,13 @@ int String::lastIndexOf(char theChar) const { } int String::lastIndexOf(char ch, unsigned int fromIndex) const { - if(fromIndex >= len()) + if (fromIndex >= len()) return -1; char tempchar = buffer()[fromIndex + 1]; wbuffer()[fromIndex + 1] = '\0'; char* temp = strrchr(wbuffer(), ch); wbuffer()[fromIndex + 1] = tempchar; - if(temp == NULL) + if (temp == NULL) return -1; return temp - buffer(); } @@ -679,31 +680,31 @@ int String::lastIndexOf(const String &s2) const { } int String::lastIndexOf(const String &s2, unsigned int fromIndex) const { - if(s2.len() == 0 || len() == 0 || s2.len() > len()) + if (s2.len() == 0 || len() == 0 || s2.len() > len()) return -1; - if(fromIndex >= len()) + if (fromIndex >= len()) fromIndex = len() - 1; int found = -1; - for(char *p = wbuffer(); p <= wbuffer() + fromIndex; p++) { + for (char *p = wbuffer(); p <= wbuffer() + fromIndex; p++) { p = strstr(p, s2.buffer()); - if(!p) + if (!p) break; - if((unsigned int) (p - wbuffer()) <= fromIndex) + if ((unsigned int) (p - wbuffer()) <= fromIndex) found = p - buffer(); } return found; } String String::substring(unsigned int left, unsigned int right) const { - if(left > right) { + if (left > right) { unsigned int temp = right; right = left; left = temp; } String out; - if(left >= len()) + if (left >= len()) return out; - if(right > len()) + if (right > len()) right = len(); char temp = buffer()[right]; // save the replaced character wbuffer()[right] = '\0'; @@ -717,28 +718,28 @@ String String::substring(unsigned int left, unsigned int right) const { // /*********************************************/ void String::replace(char find, char replace) { - if(!buffer()) + if (!buffer()) return; - for(char *p = wbuffer(); *p; p++) { - if(*p == find) + for (char *p = wbuffer(); *p; p++) { + if (*p == find) *p = replace; } } void String::replace(const String& find, const String& replace) { - if(len() == 0 || find.len() == 0) + if (len() == 0 || find.len() == 0) return; int diff = replace.len() - find.len(); char *readFrom = wbuffer(); char *foundAt; - if(diff == 0) { - while((foundAt = strstr(readFrom, find.buffer())) != NULL) { + if (diff == 0) { + while ((foundAt = strstr(readFrom, find.buffer())) != NULL) { memmove_P(foundAt, replace.buffer(), replace.len()); readFrom = foundAt + replace.len(); } - } else if(diff < 0) { + } else if (diff < 0) { char *writeTo = wbuffer(); - while((foundAt = strstr(readFrom, find.buffer())) != NULL) { + while ((foundAt = strstr(readFrom, find.buffer())) != NULL) { unsigned int n = foundAt - readFrom; memmove_P(writeTo, readFrom, n); writeTo += n; @@ -750,19 +751,19 @@ void String::replace(const String& find, const String& replace) { memmove_P(writeTo, readFrom, strlen(readFrom)+1); } else { unsigned int size = len(); // compute size needed for result - while((foundAt = strstr(readFrom, find.buffer())) != NULL) { + while ((foundAt = strstr(readFrom, find.buffer())) != NULL) { readFrom = foundAt + find.len(); size += diff; } - if(size == len()) + if (size == len()) return; - if(size > capacity() && !changeBuffer(size)) + if (size > capacity() && !changeBuffer(size)) return; // XXX: tell user! int index = len() - 1; - while(index >= 0 && (index = lastIndexOf(find, index)) >= 0) { + while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { readFrom = wbuffer() + index + find.len(); memmove_P(readFrom + diff, readFrom, len() - (readFrom - buffer())); - int newLen = len() + diff; + int newLen = len() + diff; memmove_P(wbuffer() + index, replace.buffer(), replace.len()); setLen(newLen); wbuffer()[newLen] = 0; @@ -779,13 +780,13 @@ void String::remove(unsigned int index) { } void String::remove(unsigned int index, unsigned int count) { - if(index >= len()) { + if (index >= len()) { return; } - if(count <= 0) { + if (count <= 0) { return; } - if(count > len() - index) { + if (count > len() - index) { count = len() - index; } char *writeTo = wbuffer() + index; @@ -796,33 +797,33 @@ void String::remove(unsigned int index, unsigned int count) { } void String::toLowerCase(void) { - if(!buffer()) + if (!buffer()) return; - for(char *p = wbuffer(); *p; p++) { + for (char *p = wbuffer(); *p; p++) { *p = tolower(*p); } } void String::toUpperCase(void) { - if(!buffer()) + if (!buffer()) return; - for(char *p = wbuffer(); *p; p++) { + for (char *p = wbuffer(); *p; p++) { *p = toupper(*p); } } void String::trim(void) { - if(!buffer() || len() == 0) + if (!buffer() || len() == 0) return; char *begin = wbuffer(); - while(isspace(*begin)) + while (isspace(*begin)) begin++; char *end = wbuffer() + len() - 1; - while(isspace(*end) && end >= begin) + while (isspace(*end) && end >= begin) end--; unsigned int newlen = end + 1 - begin; setLen(newlen); - if(begin > buffer()) + if (begin > buffer()) memmove_P(wbuffer(), begin, newlen); wbuffer()[newlen] = 0; } diff --git a/cores/esp8266/WString.h b/cores/esp8266/WString.h index 8c970abf1..fb2f0797f 100644 --- a/cores/esp8266/WString.h +++ b/cores/esp8266/WString.h @@ -116,6 +116,7 @@ class String { unsigned char concat(float num); unsigned char concat(double num); unsigned char concat(const __FlashStringHelper * str); + unsigned char concat(const char *cstr, unsigned int length); // if there's not enough memory for the concatenated value, the string // will be left unchanged (but this isn't signalled in any way) @@ -202,8 +203,20 @@ class String { unsigned char equalsIgnoreCase(const String &s) const; unsigned char equalsConstantTime(const String &s) const; unsigned char startsWith(const String &prefix) const; + unsigned char startsWith(const char * prefix) const { + return this->startsWith(String(prefix)); + } + unsigned char startsWith(const __FlashStringHelper * prefix) const { + return this->startsWith(String(prefix)); + } unsigned char startsWith(const String &prefix, unsigned int offset) const; unsigned char endsWith(const String &suffix) const; + unsigned char endsWith(const char * suffix) const { + return this->endsWith(String(suffix)); + } + unsigned char endsWith(const __FlashStringHelper * suffix) const { + return this->endsWith(String(suffix)); + } // character access char charAt(unsigned int index) const; @@ -238,6 +251,21 @@ class String { // modification void replace(char find, char replace); void replace(const String& find, const String& replace); + void replace(const char * find, const String& replace) { + this->replace(String(find), replace); + } + void replace(const __FlashStringHelper * find, const String& replace) { + this->replace(String(find), replace); + } + void replace(const char * find, const char * replace) { + this->replace(String(find), String(replace)); + } + void replace(const __FlashStringHelper * find, const char * replace) { + this->replace(String(find), String(replace)); + } + void replace(const __FlashStringHelper * find, const __FlashStringHelper * replace) { + this->replace(String(find), String(replace)); + } void remove(unsigned int index); void remove(unsigned int index, unsigned int count); void toLowerCase(void); @@ -284,7 +312,6 @@ class String { void init(void); void invalidate(void); unsigned char changeBuffer(unsigned int maxStrLen); - unsigned char concat(const char *cstr, unsigned int length); // copy and move String & copy(const char *cstr, unsigned int length); diff --git a/cores/esp8266/avr/dtostrf.h b/cores/esp8266/avr/dtostrf.h new file mode 100644 index 000000000..7fa7e5a36 --- /dev/null +++ b/cores/esp8266/avr/dtostrf.h @@ -0,0 +1 @@ +#include diff --git a/cores/esp8266/base64.cpp b/cores/esp8266/base64.cpp index f0d079352..271fca4f9 100644 --- a/cores/esp8266/base64.cpp +++ b/cores/esp8266/base64.cpp @@ -24,7 +24,6 @@ #include "Arduino.h" extern "C" { -#include "libb64/cdecode.h" #include "libb64/cencode.h" } #include "base64.h" @@ -35,14 +34,19 @@ extern "C" { * @param length size_t * @return String */ -String base64::encode(const uint8_t * data, size_t length, bool doNewLines) { +String base64::encode(const uint8_t * data, size_t length, bool doNewLines) +{ + String base64; + // base64 needs more size then the source data, use cencode.h macros - size_t size = ((doNewLines ? base64_encode_expected_len(length) - : base64_encode_expected_len_nonewlines(length)) + 1); - char * buffer = (char *) malloc(size); - if(buffer) { + size_t size = ((doNewLines ? base64_encode_expected_len( length ) + : base64_encode_expected_len_nonewlines( length )) + 1); + + if (base64.reserve(size)) + { + base64_encodestate _state; - if(doNewLines) + if (doNewLines) { base64_init_encodestate(&_state); } @@ -50,22 +54,23 @@ String base64::encode(const uint8_t * data, size_t length, bool doNewLines) { { base64_init_encodestate_nonewlines(&_state); } - int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state); - len = base64_encode_blockend((buffer + len), &_state); - String base64 = String(buffer); - free(buffer); - return base64; + constexpr size_t BUFSIZE = 48; + char buf[BUFSIZE + 1 /* newline */ + 1 /* NUL */]; + for (size_t len = 0; len < length; len += BUFSIZE * 3 / 4) + { + size_t blocklen = base64_encode_block((const char*) data + len, + std::min( BUFSIZE * 3 / 4, length - len ), buf, &_state); + buf[blocklen] = '\0'; + base64 += buf; + } + if (base64_encode_blockend(buf, &_state)) + base64 += buf; + } + else + { + base64 = F("-FAIL-"); } - return String("-FAIL-"); -} -/** - * convert input data to base64 - * @param text const String& - * @return String - */ -String base64::encode(const String& text, bool doNewLines) { - return base64::encode((const uint8_t *) text.c_str(), text.length(), doNewLines); + return base64; } - diff --git a/cores/esp8266/base64.h b/cores/esp8266/base64.h index 1d6e22fac..20f00f81f 100644 --- a/cores/esp8266/base64.h +++ b/cores/esp8266/base64.h @@ -25,14 +25,18 @@ #ifndef CORE_BASE64_H_ #define CORE_BASE64_H_ -class base64 { - public: - // NOTE: The default behaviour of backend (lib64) - // is to add a newline every 72 (encoded) characters output. - // This may 'break' longer uris and json variables - static String encode(const uint8_t * data, size_t length, bool doNewLines = true); - static String encode(const String& text, bool doNewLines = true); - private: +class base64 +{ +public: + // NOTE: The default behaviour of backend (lib64) + // is to add a newline every 72 (encoded) characters output. + // This may 'break' longer uris and json variables + static String encode(const uint8_t * data, size_t length, bool doNewLines = true); + static String inline encode(const String& text, bool doNewLines = true) + { + return encode( (const uint8_t *) text.c_str(), text.length(), doNewLines ); + } +private: }; diff --git a/cores/esp8266/core_esp8266_features.cpp b/cores/esp8266/core_esp8266_features.cpp new file mode 100644 index 000000000..03396e500 --- /dev/null +++ b/cores/esp8266/core_esp8266_features.cpp @@ -0,0 +1,50 @@ + +/* + core_esp8266_features.cpp + + Copyright (c) 2019 Mike Nix. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +/* precache() + * pre-loads flash data into the flash cache + * if f==0, preloads instructions starting at the address we were called from. + * otherwise preloads flash at the given address. + * All preloads are word aligned. + */ +#ifdef __cplusplus +extern "C" { +#endif + +void precache(void *f, uint32_t bytes) { + // Size of a cache page in bytes. We only need to read one word per + // page (ie 1 word in 8) for this to work. + #define CACHE_PAGE_SIZE 32 + + register uint32_t a0 asm("a0"); + register uint32_t lines = (bytes/CACHE_PAGE_SIZE)+2; + volatile uint32_t *p = (uint32_t*)((f ? (uint32_t)f : a0) & ~0x03); + uint32_t x; + for (uint32_t i=0; i // malloc() #include // size_t +#include + +#ifdef __cplusplus namespace arduino { @@ -93,4 +94,26 @@ inline uint32_t esp_get_cycle_count() { } #endif // not CORE_MOCK + +// Tools for preloading code into the flash cache +#define PRECACHE_ATTR __attribute__((optimize("no-reorder-blocks"))) \ + __attribute__((noinline)) + +#define PRECACHE_START(tag) \ + precache(NULL,(uint8_t *)&&_precache_end_##tag - (uint8_t*)&&_precache_start_##tag); \ + _precache_start_##tag: + +#define PRECACHE_END(tag) \ + _precache_end_##tag: + +#ifdef __cplusplus +extern "C" { +#endif + +void precache(void *f, uint32_t bytes); + +#ifdef __cplusplus +} +#endif + #endif // CORE_ESP8266_FEATURES_H diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 61c07da90..a95c4b2c1 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -37,7 +37,6 @@ extern "C" { #define LOOP_TASK_PRIORITY 1 #define LOOP_QUEUE_SIZE 1 -#define OPTIMISTIC_YIELD_TIME_US 16000 extern "C" void call_user_start(); extern void loop(); @@ -58,7 +57,7 @@ cont_t* g_pcont __attribute__((section(".noinit"))); static os_event_t s_loop_queue[LOOP_QUEUE_SIZE]; /* Used to implement optimistic_yield */ -static uint32_t s_micros_at_task_start; +static uint32_t s_cycles_at_yield_start; /* For ets_intr_lock_nest / ets_intr_unlock_nest * Max nesting seen by SDK so far is 2. @@ -90,26 +89,31 @@ void preloop_update_frequency() { #endif } +extern "C" bool can_yield() { + return cont_can_yield(g_pcont); +} static inline void esp_yield_within_cont() __attribute__((always_inline)); static void esp_yield_within_cont() { cont_yield(g_pcont); + s_cycles_at_yield_start = ESP.getCycleCount(); run_scheduled_recurrent_functions(); } -extern "C" void esp_yield() { - if (cont_can_yield(g_pcont)) { +extern "C" void __esp_yield() { + if (can_yield()) { esp_yield_within_cont(); } } -extern "C" void esp_schedule() { - // always on CONT stack here +extern "C" void esp_yield() __attribute__ ((weak, alias("__esp_yield"))); + +extern "C" IRAM_ATTR void esp_schedule() { ets_post(LOOP_TASK_PRIORITY, 0, 0); } extern "C" void __yield() { - if (cont_can_yield(g_pcont)) { + if (can_yield()) { esp_schedule(); esp_yield_within_cont(); } @@ -121,14 +125,19 @@ extern "C" void __yield() { extern "C" void yield(void) __attribute__ ((weak, alias("__yield"))); extern "C" void optimistic_yield(uint32_t interval_us) { - if (cont_can_yield(g_pcont) && - (system_get_time() - s_micros_at_task_start) > interval_us) + const uint32_t intvl_cycles = interval_us * +#if defined(F_CPU) + clockCyclesPerMicrosecond(); +#else + ESP.getCpuFreqMHz(); +#endif + if ((ESP.getCycleCount() - s_cycles_at_yield_start) > intvl_cycles && + can_yield()) { yield(); } } - // Replace ets_intr_(un)lock with nestable versions extern "C" void IRAM_ATTR ets_intr_lock() { if (ets_intr_lock_stack_ptr < ETS_INTR_LOCK_NEST_MAX) @@ -179,7 +188,7 @@ static void loop_wrapper() { static void loop_task(os_event_t *events) { (void) events; - s_micros_at_task_start = system_get_time(); + s_cycles_at_yield_start = ESP.getCycleCount(); cont_run(g_pcont, &loop_wrapper); if (cont_check(g_pcont) != 0) { panic(); @@ -207,7 +216,7 @@ extern void __unhandled_exception(const char *str); static void __unhandled_exception_cpp() { #ifndef __EXCEPTIONS - abort(); + abort(); #else static bool terminating; if (terminating) diff --git a/cores/esp8266/core_esp8266_noniso.cpp b/cores/esp8266/core_esp8266_noniso.cpp index b39edbb28..c742904d2 100644 --- a/cores/esp8266/core_esp8266_noniso.cpp +++ b/cores/esp8266/core_esp8266_noniso.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "stdlib_noniso.h" extern "C" { @@ -77,11 +78,15 @@ char * dtostrf(double number, signed char width, unsigned char prec, char *s) { // Figure out how big our number really is double tenpow = 1.0; int digitcount = 1; - while (number >= 10.0 * tenpow) { - tenpow *= 10.0; + double nextpow; + while (number >= (nextpow = (10.0 * tenpow))) { + tenpow = nextpow; digitcount++; } + // minimal compensation for possible lack of precision (#7087 addition) + number *= 1 + std::numeric_limits::epsilon(); + number /= tenpow; fillme -= digitcount; diff --git a/cores/esp8266/core_esp8266_postmortem.cpp b/cores/esp8266/core_esp8266_postmortem.cpp index 0486ee573..84aad50a0 100644 --- a/cores/esp8266/core_esp8266_postmortem.cpp +++ b/cores/esp8266/core_esp8266_postmortem.cpp @@ -89,7 +89,7 @@ static void ets_printf_P(const char *str, ...) { vsnprintf(destStr, sizeof(destStr), str, argPtr); va_end(argPtr); while (*c) { - ets_putc(*(c++)); + ets_uart_putc1(*(c++)); } } @@ -147,10 +147,10 @@ void __wrap_system_restart_local() { // (determined empirically, might break) uint32_t offset = 0; if (rst_info.reason == REASON_SOFT_WDT_RST) { - offset = 0x1b0; + offset = 0x1a0; } else if (rst_info.reason == REASON_EXCEPTION_RST) { - offset = 0x1a0; + offset = 0x190; } else if (rst_info.reason == REASON_WDT_RST) { offset = 0x10; diff --git a/cores/esp8266/core_esp8266_si2c.cpp b/cores/esp8266/core_esp8266_si2c.cpp index 281b19680..dff91ce0f 100644 --- a/cores/esp8266/core_esp8266_si2c.cpp +++ b/cores/esp8266/core_esp8266_si2c.cpp @@ -22,6 +22,7 @@ #include "twi.h" #include "pins_arduino.h" #include "wiring_private.h" +#include "PolledTimeout.h" @@ -30,13 +31,39 @@ extern "C" { #include "ets_sys.h" }; + // Inline helpers + static inline __attribute__((always_inline)) void SDA_LOW(const int twi_sda) + { + GPES = (1 << twi_sda); + } + static inline __attribute__((always_inline)) void SDA_HIGH(const int twi_sda) + { + GPEC = (1 << twi_sda); + } + static inline __attribute__((always_inline)) bool SDA_READ(const int twi_sda) + { + return (GPI & (1 << twi_sda)) != 0; + } + static inline __attribute__((always_inline)) void SCL_LOW(const int twi_scl) + { + GPES = (1 << twi_scl); + } + static inline __attribute__((always_inline)) void SCL_HIGH(const int twi_scl) + { + GPEC = (1 << twi_scl); + } + static inline __attribute__((always_inline)) bool SCL_READ(const int twi_scl) + { + return (GPI & (1 << twi_scl)) != 0; + } + // Implement as a class to reduce code size by allowing access to many global variables with a single base pointer class Twi { private: unsigned int preferred_si2c_clock = 100000; - unsigned char twi_dcount = 18; + uint32_t twi_dcount = 18; unsigned char twi_sda = 0; unsigned char twi_scl = 0; unsigned char twi_addr = 0; @@ -85,7 +112,7 @@ private: bool _slaveEnabled = false; // Internal use functions - void ICACHE_RAM_ATTR busywait(unsigned char v); + void ICACHE_RAM_ATTR busywait(unsigned int v); bool write_start(void); bool write_stop(void); bool write_bit(bool bit); @@ -94,37 +121,15 @@ private: unsigned char read_byte(bool nack); void ICACHE_RAM_ATTR onTwipEvent(uint8_t status); - // Inline helpers - inline void SDA_LOW() - { - GPES = (1 << twi_sda); - } - inline void SDA_HIGH() - { - GPEC = (1 << twi_sda); - } - inline bool SDA_READ() - { - return (GPI & (1 << twi_sda)) != 0; - } - inline void SCL_LOW() - { - GPES = (1 << twi_scl); - } - inline void SCL_HIGH() - { - GPEC = (1 << twi_scl); - } - inline bool SCL_READ() - { - return (GPI & (1 << twi_scl)) != 0; - } // Handle the case where a slave needs to stretch the clock with a time-limited busy wait inline void WAIT_CLOCK_STRETCH() { - for (unsigned int t = 0; !SCL_READ() && (t < twi_clockStretchLimit); t++) - { - /* noop */ + esp8266::polledTimeout::oneShotFastUs timeout(twi_clockStretchLimit); + esp8266::polledTimeout::periodicFastUs yieldTimeout(5000); + while(!timeout && !SCL_READ(twi_scl)) // outer loop is stretch duration up to stretch limit + { + if (yieldTimeout) // inner loop yields every 5ms + yield(); } } @@ -142,9 +147,8 @@ public: uint8_t transmit(const uint8_t* data, uint8_t length); void attachSlaveRxEvent(void (*function)(uint8_t*, size_t)); void attachSlaveTxEvent(void (*function)(void)); - inline void ICACHE_RAM_ATTR reply(uint8_t ack); - inline void ICACHE_RAM_ATTR stop(void); - inline void ICACHE_RAM_ATTR releaseBus(void); + void ICACHE_RAM_ATTR reply(uint8_t ack); + void ICACHE_RAM_ATTR releaseBus(void); void enableSlave(); }; @@ -154,80 +158,33 @@ static Twi twi; #define FCPU80 80000000L #endif -#if F_CPU == FCPU80 -#define TWI_CLOCK_STRETCH_MULTIPLIER 3 -#else -#define TWI_CLOCK_STRETCH_MULTIPLIER 6 -#endif - - void Twi::setClock(unsigned int freq) { + if (freq < 1000) // minimum freq 1000Hz to minimize slave timeouts and WDT resets + freq = 1000; + preferred_si2c_clock = freq; + #if F_CPU == FCPU80 - if (freq <= 50000) - { - twi_dcount = 38; //about 50KHz - } - else if (freq <= 100000) - { - twi_dcount = 19; //about 100KHz - } - else if (freq <= 200000) - { - twi_dcount = 8; //about 200KHz - } - else if (freq <= 300000) - { - twi_dcount = 3; //about 300KHz - } - else if (freq <= 400000) - { - twi_dcount = 1; //about 400KHz - } - else - { - twi_dcount = 1; //about 400KHz - } + + if (freq > 400000) + freq = 400000; + twi_dcount = (500000000 / freq); // half-cycle period in ns + twi_dcount = (1000*(twi_dcount - 1120)) / 62500; // (half cycle - overhead) / busywait loop time + #else - if (freq <= 50000) - { - twi_dcount = 64; //about 50KHz - } - else if (freq <= 100000) - { - twi_dcount = 32; //about 100KHz - } - else if (freq <= 200000) - { - twi_dcount = 14; //about 200KHz - } - else if (freq <= 300000) - { - twi_dcount = 8; //about 300KHz - } - else if (freq <= 400000) - { - twi_dcount = 5; //about 400KHz - } - else if (freq <= 500000) - { - twi_dcount = 3; //about 500KHz - } - else if (freq <= 600000) - { - twi_dcount = 2; //about 600KHz - } - else - { - twi_dcount = 1; //about 700KHz - } + + if (freq > 800000) + freq = 800000; + twi_dcount = (500000000 / freq); // half-cycle period in ns + twi_dcount = (1000*(twi_dcount - 560)) / 31250; // (half cycle - overhead) / busywait loop time + #endif } void Twi::setClockStretchLimit(uint32_t limit) { - twi_clockStretchLimit = limit * TWI_CLOCK_STRETCH_MULTIPLIER; + twi_clockStretchLimit = limit; } @@ -245,7 +202,7 @@ void Twi::init(unsigned char sda, unsigned char scl) pinMode(twi_sda, INPUT_PULLUP); pinMode(twi_scl, INPUT_PULLUP); twi_setClock(preferred_si2c_clock); - twi_setClockStretchLimit(230); // default value is 230 uS + twi_setClockStretchLimit(150000L); // default value is 150 mS } void Twi::setAddress(uint8_t address) @@ -264,60 +221,55 @@ void Twi::enableSlave() } } -void ICACHE_RAM_ATTR Twi::busywait(unsigned char v) + void ICACHE_RAM_ATTR Twi::busywait(unsigned int v) { unsigned int i; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" - unsigned int reg; - for (i = 0; i < v; i++) + for (i = 0; i < v; i++) // loop time is 5 machine cycles: 31.25ns @ 160MHz, 62.5ns @ 80MHz { - reg = GPI; + asm("nop"); // minimum element to keep GCC from optimizing this function out. } - (void)reg; -#pragma GCC diagnostic pop } bool Twi::write_start(void) { - SCL_HIGH(); - SDA_HIGH(); - if (!SDA_READ()) + SCL_HIGH(twi_scl); + SDA_HIGH(twi_sda); + if (!SDA_READ(twi_sda)) { return false; } busywait(twi_dcount); - SDA_LOW(); + SDA_LOW(twi_sda); busywait(twi_dcount); return true; } bool Twi::write_stop(void) { - SCL_LOW(); - SDA_LOW(); + SCL_LOW(twi_scl); + SDA_LOW(twi_sda); busywait(twi_dcount); - SCL_HIGH(); + SCL_HIGH(twi_scl); WAIT_CLOCK_STRETCH(); busywait(twi_dcount); - SDA_HIGH(); + SDA_HIGH(twi_sda); busywait(twi_dcount); return true; } bool Twi::write_bit(bool bit) { - SCL_LOW(); + SCL_LOW(twi_scl); if (bit) { - SDA_HIGH(); + SDA_HIGH(twi_sda); } else { - SDA_LOW(); + SDA_LOW(twi_sda); } busywait(twi_dcount + 1); - SCL_HIGH(); + SCL_HIGH(twi_scl); WAIT_CLOCK_STRETCH(); busywait(twi_dcount); return true; @@ -325,12 +277,12 @@ bool Twi::write_bit(bool bit) bool Twi::read_bit(void) { - SCL_LOW(); - SDA_HIGH(); + SCL_LOW(twi_scl); + SDA_HIGH(twi_sda); busywait(twi_dcount + 2); - SCL_HIGH(); + SCL_HIGH(twi_scl); WAIT_CLOCK_STRETCH(); - bool bit = SDA_READ(); + bool bit = SDA_READ(twi_sda); busywait(twi_dcount); return bit; } @@ -395,7 +347,7 @@ unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned // busywait(twi_dcount); } i = 0; - while (!SDA_READ() && (i++) < 10) + while (!SDA_READ(twi_sda) && (i++) < 10) { twi_scl_valley(); busywait(twi_dcount); @@ -434,7 +386,7 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned // busywait(twi_dcount); } i = 0; - while (!SDA_READ() && (i++) < 10) + while (!SDA_READ(twi_sda) && (i++) < 10) { twi_scl_valley(); busywait(twi_dcount); @@ -442,32 +394,36 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned return 0; } +void Twi::twi_scl_valley(void) +{ + SCL_LOW(twi_scl); + busywait(twi_dcount); + SCL_HIGH(twi_scl); + WAIT_CLOCK_STRETCH(); +} + uint8_t Twi::status() { - if (!SCL_READ()) + WAIT_CLOCK_STRETCH(); // wait for a slow slave to finish + if (!SCL_READ(twi_scl)) { return I2C_SCL_HELD_LOW; // SCL held low by another device, no procedure available to recover } int clockCount = 20; - while (!SDA_READ() && clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max + while (!SDA_READ(twi_sda) && clockCount-- > 0) // if SDA low, read the bits slaves have to sent to a max { read_bit(); - if (!SCL_READ()) + if (!SCL_READ(twi_scl)) { return I2C_SCL_HELD_LOW_AFTER_READ; // I2C bus error. SCL held low beyond slave clock stretch time } } - if (!SDA_READ()) + if (!SDA_READ(twi_sda)) { return I2C_SDA_HELD_LOW; // I2C bus error. SDA line held low by slave/another_master after n bits. } - if (!write_start()) - { - return I2C_SDA_HELD_LOW_AFTER_INIT; // line busy. SDA again held low by another device. 2nd master? - } - return I2C_OK; } @@ -507,42 +463,34 @@ void Twi::attachSlaveTxEvent(void (*function)(void)) twi_onSlaveTransmit = function; } -inline void ICACHE_RAM_ATTR Twi::reply(uint8_t ack) +// DO NOT INLINE, inlining reply() in combination with compiler optimizations causes function breakup into +// parts and the ICACHE_RAM_ATTR isn't propagated correctly to all parts, which of course causes crashes. +// TODO: test with gcc 9.x and if it still fails, disable optimization with -fdisable-ipa-fnsplit +void ICACHE_RAM_ATTR Twi::reply(uint8_t ack) { // transmit master read ready signal, with or without ack if (ack) { //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); - SCL_HIGH(); // _BV(TWINT) - twi_ack = 1; // _BV(TWEA) + SCL_HIGH(twi.twi_scl); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) } else { //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); - SCL_HIGH(); // _BV(TWINT) - twi_ack = 0; // ~_BV(TWEA) + SCL_HIGH(twi.twi_scl); // _BV(TWINT) + twi_ack = 0; // ~_BV(TWEA) } } -inline void ICACHE_RAM_ATTR Twi::stop(void) -{ - // send stop condition - //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); - SCL_HIGH(); // _BV(TWINT) - twi_ack = 1; // _BV(TWEA) - busywait(5); // Maybe this should be here - SDA_HIGH(); // _BV(TWSTO) - // update twi state - twi_state = TWI_READY; -} -inline void ICACHE_RAM_ATTR Twi::releaseBus(void) +void ICACHE_RAM_ATTR Twi::releaseBus(void) { // release bus //TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); - SCL_HIGH(); // _BV(TWINT) - twi_ack = 1; // _BV(TWEA) - SDA_HIGH(); + SCL_HIGH(twi.twi_scl); // _BV(TWINT) + twi_ack = 1; // _BV(TWEA) + SDA_HIGH(twi.twi_sda); // update twi state twi_state = TWI_READY; @@ -623,11 +571,11 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status) bitCount--; if (twi_data & 0x80) { - SDA_HIGH(); + SDA_HIGH(twi.twi_sda); } else { - SDA_LOW(); + SDA_LOW(twi.twi_sda); } twi_data <<= 1; @@ -652,19 +600,10 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status) break; case TW_BUS_ERROR: // bus error, illegal stop/start twi_error = TW_BUS_ERROR; - stop(); break; } } -void Twi::twi_scl_valley(void) -{ - SCL_LOW(); - busywait(twi_dcount); - SCL_HIGH(); - WAIT_CLOCK_STRETCH(); -} - void ICACHE_RAM_ATTR Twi::onTimer(void *unused) { (void)unused; @@ -721,10 +660,11 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) unsigned int scl; // Store bool return in int to reduce final code size. - sda = twi.SDA_READ(); - scl = twi.SCL_READ(); + + sda = SDA_READ(twi.twi_sda); + scl = SCL_READ(twi.twi_scl); - twi.twip_status = 0xF8; // reset TWI status + twi.twip_status = 0xF8; // reset TWI status int twip_state_mask = S2M(twi.twip_state); IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SLA_W) | S2M(TWIP_READ)) @@ -765,7 +705,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - twi.SDA_LOW(); + SDA_LOW(twi.twi_sda); } } else @@ -776,7 +716,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - twi.SDA_LOW(); + SDA_LOW(twi.twi_sda); } } twi.twip_state = TWIP_WAIT_ACK; @@ -794,13 +734,13 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) { if ((twi.twi_data & 0xFE) != twi.twi_addr) { - twi.SDA_HIGH(); + SDA_HIGH(twi.twi_sda); twi.twip_state = TWIP_WAIT_STOP; } else { - twi.SCL_LOW(); // clock stretching - twi.SDA_HIGH(); + SCL_LOW(twi.twi_scl); // clock stretching + SDA_HIGH(twi.twi_sda); twi.twip_mode = TWIPM_ADDRESSED; if (!(twi.twi_data & 0x01)) { @@ -817,8 +757,8 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - twi.SCL_LOW(); // clock stretching - twi.SDA_HIGH(); + SCL_LOW(twi.twi_scl); // clock stretching + SDA_HIGH(twi.twi_sda); if (!twi.twi_ack) { twi.onTwipEvent(TW_SR_DATA_NACK); @@ -845,11 +785,11 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) twi.bitCount--; if (twi.twi_data & 0x80) { - twi.SDA_HIGH(); + SDA_HIGH(twi.twi_sda); } else { - twi.SDA_LOW(); + SDA_LOW(twi.twi_sda); } twi.twi_data <<= 1; @@ -871,7 +811,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - twi.SDA_HIGH(); + SDA_HIGH(twi.twi_sda); twi.twip_state = TWIP_READ_ACK; } } @@ -895,7 +835,7 @@ void ICACHE_RAM_ATTR Twi::onSclChange(void) } else { - twi.SCL_LOW(); // clock stretching + SCL_LOW(twi.twi_scl); // clock stretching if (twi.twi_ack && twi.twi_ack_rec) { twi.onTwipEvent(TW_ST_DATA_ACK); @@ -918,8 +858,8 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void) unsigned int scl; // Store bool return in int to reduce final code size. - sda = twi.SDA_READ(); - scl = twi.SCL_READ(); + sda = SDA_READ(twi.twi_sda); + scl = SCL_READ(twi.twi_scl); int twip_state_mask = S2M(twi.twip_state); if (scl) /* !DATA */ @@ -941,7 +881,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void) else IFSTATE(S2M(TWIP_START) | S2M(TWIP_REP_START) | S2M(TWIP_SEND_ACK) | S2M(TWIP_WAIT_ACK) | S2M(TWIP_SLA_R) | S2M(TWIP_REC_ACK) | S2M(TWIP_READ_ACK) | S2M(TWIP_RWAIT_ACK) | S2M(TWIP_WRITE)) { // START or STOP - twi.SDA_HIGH(); // Should not be necessary + SDA_HIGH(twi.twi_sda); // Should not be necessary twi.onTwipEvent(TW_BUS_ERROR); twi.twip_mode = TWIPM_WAIT; twi.twip_state = TWIP_BUS_ERR; @@ -951,11 +891,11 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void) if (sda) { // STOP - twi.SCL_LOW(); // clock stretching + SCL_LOW(twi.twi_scl); // generates a low SCL pulse after STOP ets_timer_disarm(&twi.timer); twi.twip_state = TWIP_IDLE; twi.twip_mode = TWIPM_IDLE; - twi.SCL_HIGH(); + SCL_HIGH(twi.twi_scl); } else { @@ -985,7 +925,7 @@ void ICACHE_RAM_ATTR Twi::onSdaChange(void) else { // during first bit in byte transfer - ok - twi.SCL_LOW(); // clock stretching + SCL_LOW(twi.twi_scl); // clock stretching twi.onTwipEvent(TW_SR_STOP); if (sda) { @@ -1020,11 +960,6 @@ extern "C" { return twi.setAddress(a); } - void twi_stop(void) - { - twi.stop(); - } - void twi_setClock(unsigned int freq) { twi.setClock(freq); diff --git a/cores/esp8266/core_esp8266_spi_utils.cpp b/cores/esp8266/core_esp8266_spi_utils.cpp new file mode 100644 index 000000000..110b13968 --- /dev/null +++ b/cores/esp8266/core_esp8266_spi_utils.cpp @@ -0,0 +1,191 @@ +/* + core_esp8266_spi_utils.cpp + + Copyright (c) 2019 Mike Nix. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +// register names +#include "esp8266_peri.h" + +// for flashchip +#include "spi_flash.h" + +// for PRECACHE_* +#include "core_esp8266_features.h" + +#include "spi_utils.h" + +extern "C" uint32_t Wait_SPI_Idle(SpiFlashChip *fc); + +namespace experimental { + +/* + * critical part of SPICommand. + * Kept in a separate function to aid with precaching + * PRECACHE_* saves having to make the function IRAM_ATTR. + * + * spiIfNum needs to be volatile to keep the optimiser from + * deciding it can be treated as a constant (due to this being a + * static function only called with spiIfNum set to 0) + * + * Note: if porting to ESP32 mosi/miso bits are set in 2 registers, not 1. + */ +static SpiOpResult PRECACHE_ATTR +_SPICommand(volatile uint32_t spiIfNum, + uint32_t spic,uint32_t spiu,uint32_t spiu1,uint32_t spiu2, + uint32_t *data,uint32_t writeWords,uint32_t readWords) +{ + if (spiIfNum>1) + return SPI_RESULT_ERR; + + // force SPI register access via base+offest. + // Prevents loading individual address constants from flash. + uint32_t *spibase = (uint32_t*)(spiIfNum ? &(SPI1CMD) : &(SPI0CMD)); + #define SPIREG(reg) (*((volatile uint32_t *)(spibase+(&(reg) - &(SPI0CMD))))) + + // preload any constants and functions we need into variables + // Everything defined here must be volatile or the optimizer can + // treat them as constants, resulting in the flash reads we're + // trying to avoid + uint32_t (* volatile Wait_SPI_Idlep)(SpiFlashChip *) = Wait_SPI_Idle; + volatile SpiFlashChip *fchip=flashchip; + volatile uint32_t spicmdusr=SPICMDUSR; + + if (!spiIfNum) { + // Only need to precache when using SPI0 + PRECACHE_START(); + Wait_SPI_Idlep((SpiFlashChip *)fchip); + } + + // preserve essential controller state such as incoming/outgoing + // data lengths and IO mode. + uint32_t oldSPI0U = SPIREG(SPI0U); + uint32_t oldSPI0U2= SPIREG(SPI0U2); + uint32_t oldSPI0C = SPIREG(SPI0C); + + //SPI0S &= ~(SPISE|SPISBE|SPISSE|SPISCD); + SPIREG(SPI0C) = spic; + SPIREG(SPI0U) = spiu; + SPIREG(SPI0U1)= spiu1; + SPIREG(SPI0U2)= spiu2; + + if (writeWords>0) { + // copy the outgoing data to the SPI hardware + uint32_t *src=data; + volatile uint32_t *dst=&SPIREG(SPI0W0); + for (uint32_t i=0; i0) && (timeout>0)) { + // copy the response back to the buffer + uint32_t *dst=data; + volatile uint32_t *src=&SPIREG(SPI0W0); + for (uint32_t i=0; i0 ? SPI_RESULT_OK : SPI_RESULT_TIMEOUT); +} + + +/* SPI0Command: send a custom SPI command. + * This part calculates register values and passes them to _SPI0Command(). + * Parameters: + * cmd The command byte (first 8 bits) to send to the SPI device + * *data The buffer containing the outgoing data for the SPI bus. + * The data is expected to be mosi_bits long, and the buffer + * is overwritten by the incoming bus data, which will be + * miso_bits long. + * mosi_bits + * Number of bits to be sent after the command byte. + * miso_bits + * Number of bits to read from the SPI bus after the outgoing + * data has been sent. + * + * Note: This code has only been tested with SPI bus 0, but should work + * equally well with other busses. The ESP8266 has bus 0 and 1, + * newer chips may have more one day. + */ +SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits) { + if (mosi_bits>(64*8)) + return SPI_RESULT_ERR; + if (miso_bits>(64*8)) + return SPI_RESULT_ERR; + + // Calculate the number of data words (aka registers) that need to be copied + // to/from the SPI controller. + uint32_t mosi_words=mosi_bits/32; + uint32_t miso_words=miso_bits/32; + if (mosi_bits % 32 != 0) + mosi_words++; + if (miso_bits % 32 != 0) + miso_words++; + + // Select user defined command mode in the controller + uint32_t spiu=SPIUCOMMAND; //SPI_USR_COMMAND + + // Set the command byte to send + uint32_t spiu2 = ((7 & SPIMCOMMAND)<0) { + // set the number of outgoing data bits to send + spiu1 |= ((mosi_bits-1) & SPIMMOSI) << SPILMOSI; + spiu |= SPIUMOSI; // SPI_USR_MOSI + } + if (miso_bits>0) { + // set the number of incoming bits to read + spiu1 |= ((miso_bits-1) & SPIMMISO) << SPILMISO; + spiu |= SPIUMISO; // SPI_USR_MISO + } + + uint32_t spic = SPI0C; + // Select the most basic IO mode for maximum compatibility + // Some flash commands are only available in this mode. + spic &= ~(SPICQIO | SPICDIO | SPICQOUT | SPICDOUT | SPICAHB | SPICFASTRD); + spic |= (SPICRESANDRES | SPICSHARE | SPICWPR | SPIC2BSE); + + SpiOpResult rc =_SPICommand(0,spic,spiu,spiu1,spiu2,data,mosi_words,miso_words); + + if (rc==SPI_RESULT_OK) { + // clear any bits we did not read in the last word. + if (miso_bits % 32) { + data[miso_bits/32] &= ~(0xFFFFFFFF << (miso_bits % 32)); + } + } + return rc; +} + +} // namespace experimental diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index 5ed0a40ab..47eeebf86 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -30,7 +30,7 @@ extern "C" { -uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x04, 0x08, 0x0C, 0x10}; +volatile uint32_t* const esp8266_gpioToFn[16] PROGMEM = { &GPF0, &GPF1, &GPF2, &GPF3, &GPF4, &GPF5, &GPF6, &GPF7, &GPF8, &GPF9, &GPF10, &GPF11, &GPF12, &GPF13, &GPF14, &GPF15 }; extern void __pinMode(uint8_t pin, uint8_t mode) { if(pin < 16){ diff --git a/cores/esp8266/coredecls.h b/cores/esp8266/coredecls.h index 2496995b0..86ba43711 100644 --- a/cores/esp8266/coredecls.h +++ b/cores/esp8266/coredecls.h @@ -13,11 +13,14 @@ extern "C" { #include // g_pcont declaration extern bool timeshift64_is_set; +extern uint32_t sntp_real_timestamp; +bool can_yield(); void esp_yield(); void esp_schedule(); void tune_timeshift64 (uint64_t now_us); void disable_extra4k_at_link_time (void) __attribute__((noinline)); +bool sntp_set_timezone_in_seconds(int32_t timezone); uint32_t sqrt32 (uint32_t n); uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff); diff --git a/cores/esp8266/crc32.cpp b/cores/esp8266/crc32.cpp index cc2a2ee64..c2fdf928e 100644 --- a/cores/esp8266/crc32.cpp +++ b/cores/esp8266/crc32.cpp @@ -20,6 +20,7 @@ */ #include "coredecls.h" +#include "pgmspace.h" // moved from core_esp8266_eboot_command.cpp uint32_t crc32 (const void* data, size_t length, uint32_t crc /*= 0xffffffff*/) @@ -27,7 +28,7 @@ uint32_t crc32 (const void* data, size_t length, uint32_t crc /*= 0xffffffff*/) const uint8_t* ldata = (const uint8_t*)data; while (length--) { - uint8_t c = *ldata++; + uint8_t c = pgm_read_byte(ldata++); for (uint32_t i = 0x80; i > 0; i >>= 1) { bool bit = crc & 0x80000000; diff --git a/cores/esp8266/esp8266_peri.h b/cores/esp8266/esp8266_peri.h index 15a596aa6..4d9b8406f 100644 --- a/cores/esp8266/esp8266_peri.h +++ b/cores/esp8266/esp8266_peri.h @@ -102,8 +102,8 @@ #define GPF14 ESP8266_REG(0x80C) #define GPF15 ESP8266_REG(0x810) -extern uint8_t esp8266_gpioToFn[16]; -#define GPF(p) ESP8266_REG(0x800 + esp8266_gpioToFn[(p & 0xF)]) +extern volatile uint32_t* const esp8266_gpioToFn[16]; +#define GPF(p) (*esp8266_gpioToFn[(p & 0xF)]) //GPIO (0-15) PIN Function Bits #define GPFSOE 0 //Sleep OE diff --git a/cores/esp8266/libb64/cencode.cpp b/cores/esp8266/libb64/cencode.cpp index ae8f90a83..d86df31af 100755 --- a/cores/esp8266/libb64/cencode.cpp +++ b/cores/esp8266/libb64/cencode.cpp @@ -5,7 +5,6 @@ This is part of the libb64 project, and has been placed in the public domain. For details, see http://sourceforge.net/projects/libb64 */ -#include #include "cencode.h" extern "C" { @@ -23,10 +22,20 @@ void base64_init_encodestate_nonewlines(base64_encodestate* state_in){ state_in->stepsnewline = -1; } -char base64_encode_value(char value_in){ - static const char encoding[] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - if (value_in > 63) return '='; - return pgm_read_byte( &encoding[(int)value_in] ); +char base64_encode_value(const char n) { + char r; + + if (n < 26) + r = n + 'A'; + else if (n < 26 + 26) + r = n - 26 + 'a'; + else if (n < 26 + 26 + 10 ) + r = n - 26 - 26 + '0'; + else if (n == 62 ) + r = '+'; + else + r = '/'; + return r; } int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in){ diff --git a/cores/esp8266/libc_replacements.cpp b/cores/esp8266/libc_replacements.cpp index b3beb07dd..0ccf5e04b 100644 --- a/cores/esp8266/libc_replacements.cpp +++ b/cores/esp8266/libc_replacements.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include <../include/time.h> // See issue #6714 #include #include #include diff --git a/cores/esp8266/sntp-lwip2.cpp b/cores/esp8266/sntp-lwip2.cpp index 063cc5be2..cc3d8e853 100644 --- a/cores/esp8266/sntp-lwip2.cpp +++ b/cores/esp8266/sntp-lwip2.cpp @@ -1,7 +1,7 @@ /* * sntp-lwip2.c - ESP8266-specific functions for SNTP and lwIP-v2 * Copyright (c) 2015 Espressif (license is tools/sdk/lwip/src/core/sntp.c's) - * Redistribution and use in source and binary forms, with or without modification, + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, @@ -10,17 +10,17 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * @@ -38,7 +38,9 @@ */ #include +#include #include +#include #include #include #include "coredecls.h" @@ -64,11 +66,11 @@ extern "C" { static const char stod14[] PROGMEM = "settimeofday() can't set time!\n"; bool sntp_set_timezone(sint8 timezone); -bool sntp_set_timezone_in_seconds(sint32 timezone) +bool sntp_set_timezone_in_seconds(int32_t timezone) { - return sntp_set_timezone((sint8)(timezone/(60*60))); //TODO: move this to the same file as sntp_set_timezone() in lwip1.4, and implement correctly over there. + return sntp_set_timezone((sint8)(timezone/(60*60))); //TODO: move this to the same file as sntp_set_timezone() in lwip1.4, and implement correctly over there. } - + void sntp_set_daylight(int daylight); int settimeofday(const struct timeval* tv, const struct timezone* tz) @@ -86,7 +88,7 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz) // reset time subsystem timeshift64_is_set = false; - + return -1; } return 0; @@ -98,394 +100,31 @@ int settimeofday(const struct timeval* tv, const struct timezone* tz) #include -static uint32 realtime_stamp = 0; -static uint16 dst = 0; -static sint32 time_zone = 8 * (60 * 60); // espressif HQ's default timezone +uint32_t sntp_real_timestamp = 0; LOCAL os_timer_t sntp_timer; -/*****************************************/ -#define SECSPERMIN 60L -#define MINSPERHOUR 60L -#define HOURSPERDAY 24L -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) -#define DAYSPERWEEK 7 -#define MONSPERYEAR 12 - -#define YEAR_BASE 1900 -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY 4 -#define EPOCH_YEARS_SINCE_LEAP 2 -#define EPOCH_YEARS_SINCE_CENTURY 70 -#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370 - -#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) - -int __tznorth; -int __tzyear; -char reult[100]; -static const int mon_lengths[2][12] = { - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -} ; - -static const int year_lengths[2] = { - 365, - 366 -} ; -struct tm -{ - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -struct tm res_buf; -typedef struct __tzrule_struct -{ - char ch; - int m; - int n; - int d; - int s; - time_t change; - int offset; -} __tzrule_type; - -__tzrule_type sntp__tzrule[2]; -struct tm * -sntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime) -{ - long days, rem; - time_t lcltime; - int y; - int yleap; - const int *ip; - - /* base decision about std/dst time on current time */ - lcltime = *tim_p; - - days = ((long)lcltime) / SECSPERDAY; - rem = ((long)lcltime) % SECSPERDAY; - while (rem < 0) - { - rem += SECSPERDAY; - --days; - } - while (rem >= SECSPERDAY) - { - rem -= SECSPERDAY; - ++days; - } - - /* compute hour, min, and sec */ - res->tm_hour = (int) (rem / SECSPERHOUR); - rem %= SECSPERHOUR; - res->tm_min = (int) (rem / SECSPERMIN); - res->tm_sec = (int) (rem % SECSPERMIN); - - /* compute day of week */ - if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) - res->tm_wday += DAYSPERWEEK; - - /* compute year & day of year */ - y = EPOCH_YEAR; - if (days >= 0) - { - for (;;) - { - yleap = isleap(y); - if (days < year_lengths[yleap]) - break; - y++; - days -= year_lengths[yleap]; - } - } - else - { - do - { - --y; - yleap = isleap(y); - days += year_lengths[yleap]; - } while (days < 0); - } - - res->tm_year = y - YEAR_BASE; - res->tm_yday = days; - ip = mon_lengths[yleap]; - for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) - days -= ip[res->tm_mon]; - res->tm_mday = days + 1; - - if (!is_gmtime) - { - int offset; - int hours, mins, secs; - -// TZ_LOCK; -// if (_daylight) -// { -// if (y == __tzyear || __tzcalc_limits (y)) -// res->tm_isdst = (__tznorth -// ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change) -// : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change)); -// else -// res->tm_isdst = -1; -// } -// else - res->tm_isdst = -1; - - offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset); - - hours = offset / SECSPERHOUR; - offset = offset % SECSPERHOUR; - - mins = offset / SECSPERMIN; - secs = offset % SECSPERMIN; - - res->tm_sec -= secs; - res->tm_min -= mins; - res->tm_hour -= hours; - - if (res->tm_sec >= SECSPERMIN) - { - res->tm_min += 1; - res->tm_sec -= SECSPERMIN; - } - else if (res->tm_sec < 0) - { - res->tm_min -= 1; - res->tm_sec += SECSPERMIN; - } - if (res->tm_min >= MINSPERHOUR) - { - res->tm_hour += 1; - res->tm_min -= MINSPERHOUR; - } - else if (res->tm_min < 0) - { - res->tm_hour -= 1; - res->tm_min += MINSPERHOUR; - } - if (res->tm_hour >= HOURSPERDAY) - { - ++res->tm_yday; - ++res->tm_wday; - if (res->tm_wday > 6) - res->tm_wday = 0; - ++res->tm_mday; - res->tm_hour -= HOURSPERDAY; - if (res->tm_mday > ip[res->tm_mon]) - { - res->tm_mday -= ip[res->tm_mon]; - res->tm_mon += 1; - if (res->tm_mon == 12) - { - res->tm_mon = 0; - res->tm_year += 1; - res->tm_yday = 0; - } - } - } - else if (res->tm_hour < 0) - { - res->tm_yday -= 1; - res->tm_wday -= 1; - if (res->tm_wday < 0) - res->tm_wday = 6; - res->tm_mday -= 1; - res->tm_hour += 24; - if (res->tm_mday == 0) - { - res->tm_mon -= 1; - if (res->tm_mon < 0) - { - res->tm_mon = 11; - res->tm_year -= 1; - res->tm_yday = 365 + isleap(res->tm_year); - } - res->tm_mday = ip[res->tm_mon]; - } - } -// TZ_UNLOCK; - } - else - res->tm_isdst = 0; -// os_printf("res %d %d %d %d %d\n",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour); - return (res); -} -struct tm * -sntp_localtime_r(const time_t * tim_p , - struct tm *res) -{ - return sntp_mktm_r (tim_p, res, 0); -} - -struct tm * -sntp_localtime(const time_t * tim_p) -{ - return sntp_localtime_r (tim_p, &res_buf); -} - -int sntp__tzcalc_limits(int year) -{ - int days, year_days, years; - int i, j; - - if (year < EPOCH_YEAR) - return 0; - - __tzyear = year; - - years = (year - EPOCH_YEAR); - - year_days = years * 365 + - (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + - (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; - - for (i = 0; i < 2; ++i) - { - if (sntp__tzrule[i].ch == 'J') - days = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60); - else if (sntp__tzrule[i].ch == 'D') - days = year_days + sntp__tzrule[i].d; - else - { - int yleap = isleap(year); - int m_day, m_wday, wday_diff; - const int *ip = mon_lengths[yleap]; - - days = year_days; - - for (j = 1; j < sntp__tzrule[i].m; ++j) - days += ip[j-1]; - - m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; - - wday_diff = sntp__tzrule[i].d - m_wday; - if (wday_diff < 0) - wday_diff += DAYSPERWEEK; - m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; - - while (m_day >= ip[j-1]) - m_day -= DAYSPERWEEK; - - days += m_day; - } - - /* store the change-over time in GMT form by adding offset */ - sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset; - } - - __tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change); - - return 1; -} - -char* sntp_asctime_r(struct tm *tim_p ,char *result) -{ - static const char day_name[7][4] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const char mon_name[12][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - os_sprintf (result, "%s %s %02d %02d:%02d:%02d %02d\n", - day_name[tim_p->tm_wday], - mon_name[tim_p->tm_mon], - tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, - tim_p->tm_sec, 1900 + tim_p->tm_year); - return result; -} - -char* sntp_asctime(struct tm *tim_p) -{ - return sntp_asctime_r (tim_p, reult); -} - -uint32 ICACHE_RAM_ATTR sntp_get_current_timestamp(void) -{ - return realtime_stamp; -} - -char* sntp_get_real_time(time_t t) -{ - return sntp_asctime(sntp_localtime (&t)); -} - -/* Returns the set timezone in seconds. If the timezone was set as seconds, the fractional part is floored. */ -sint32 sntp_get_timezone_in_seconds(void) -{ - return time_zone; -} - -/* Returns the set timezone in hours. If the timezone was set as seconds, the fractional part is floored. */ -sint8 sntp_get_timezone(void) -{ - return (sint8)(time_zone / (60 * 60)); -} - -/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */ -bool sntp_set_timezone_in_seconds(sint32 timezone) -{ - if(timezone >= (-11 * (60 * 60)) || timezone <= (13 * (60 * 60))) { - time_zone = timezone; - return true; - } - return false; -} - -/* Sets the timezone in hours. Internally, the timezone is converted to seconds. */ -bool sntp_set_timezone(sint8 timezone) -{ - return sntp_set_timezone_in_seconds((sint32)timezone * 60 * 60); -} - - -void sntp_set_daylight(int daylight) -{ - dst = daylight; -} - void ICACHE_RAM_ATTR sntp_time_inc (void) { - realtime_stamp++; -} - -static void sntp_set_system_time (uint32_t t) -{ - realtime_stamp = t + time_zone + dst; - os_timer_disarm(&sntp_timer); - os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); - os_timer_arm(&sntp_timer, 1000, 1); + sntp_real_timestamp++; } int settimeofday(const struct timeval* tv, const struct timezone* tz) { - if (tz) /*before*/ - { - sntp_set_timezone_in_seconds(tz->tz_minuteswest * 60); - // apparently tz->tz_dsttime is a bitfield and should not be further used (cf man) - sntp_set_daylight(0); - } - if (tv) /* after*/ - { - // reset time subsystem - tune_timeshift64(tv->tv_sec * 1000000ULL + tv->tv_usec); + if (tz || !tv) + // tz is obsolete (cf. man settimeofday) + return EINVAL; - sntp_set_system_time(tv->tv_sec); + // reset time subsystem + tune_timeshift64(tv->tv_sec * 1000000ULL + tv->tv_usec); + + sntp_real_timestamp = tv->tv_sec; + os_timer_disarm(&sntp_timer); + os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL); + os_timer_arm(&sntp_timer, 1000, 1); + + if (_settimeofday_cb) + schedule_recurrent_function_us([](){ _settimeofday_cb(); return false; }, 0); - if (_settimeofday_cb) - schedule_function(_settimeofday_cb); - } return 0; } diff --git a/cores/esp8266/sntp-lwip2.h b/cores/esp8266/sntp-lwip2.h index 5ae697754..bcda54f9a 100644 --- a/cores/esp8266/sntp-lwip2.h +++ b/cores/esp8266/sntp-lwip2.h @@ -1,10 +1,6 @@ #ifndef __sntp_lwip2_h__ #define __sntp_lwip2_h__ -extern "C" { - -bool sntp_set_timezone_in_seconds(sint32 timezone); - -} +#include #endif diff --git a/cores/esp8266/spi_utils.h b/cores/esp8266/spi_utils.h new file mode 100644 index 000000000..bf0928f28 --- /dev/null +++ b/cores/esp8266/spi_utils.h @@ -0,0 +1,46 @@ +/* + spi_utils.h - SPI utility function + Copyright (c) 2015 Ivan Grokhotkov. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef SPI_UTILS_H +#define SPI_UTILS_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +namespace experimental { +typedef enum { + SPI_RESULT_OK, + SPI_RESULT_ERR, + SPI_RESULT_TIMEOUT +} SpiOpResult; + +SpiOpResult SPI0Command(uint8_t cmd, uint32_t *data, uint32_t mosi_bits, uint32_t miso_bits); +} + +#ifdef __cplusplus +} +#endif + + +#endif //SPI_UTILS_H diff --git a/cores/esp8266/spiffs_api.cpp b/cores/esp8266/spiffs_api.cpp index 04fc461d1..1f0278bfc 100644 --- a/cores/esp8266/spiffs_api.cpp +++ b/cores/esp8266/spiffs_api.cpp @@ -141,6 +141,14 @@ FS SPIFFS = FS(FSImplPtr(new spiffs_impl::SPIFFSImpl( FS_PHYS_PAGE, FS_PHYS_BLOCK, SPIFFS_MAX_OPEN_FILES))); + +extern "C" void spiffs_request_end(void) +{ + // override default weak function + //ets_printf("debug: not weak spiffs end\n"); + SPIFFS.end(); +} + #endif // ARDUINO #endif // !CORE_MOCK diff --git a/cores/esp8266/spiffs_api.h b/cores/esp8266/spiffs_api.h index c19dbc2c4..a40d59b0a 100644 --- a/cores/esp8266/spiffs_api.h +++ b/cores/esp8266/spiffs_api.h @@ -80,6 +80,11 @@ public: memset(&_fs, 0, sizeof(_fs)); } + ~SPIFFSImpl() + { + end(); + } + FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) override; bool exists(const char* path) override; DirImplPtr openDir(const char* path) override; @@ -162,7 +167,7 @@ public: bool setConfig(const FSConfig &cfg) override { - if ((cfg._type != SPIFFSConfig::fsid::FSId) || (SPIFFS_mounted(&_fs) != 0)) { + if ((cfg._type != SPIFFSConfig::FSId) || (SPIFFS_mounted(&_fs) != 0)) { return false; } _cfg = *static_cast(&cfg); diff --git a/cores/esp8266/time.cpp b/cores/esp8266/time.cpp index 3a3e3f755..45481d91b 100644 --- a/cores/esp8266/time.cpp +++ b/cores/esp8266/time.cpp @@ -17,12 +17,14 @@ */ #include -#include +#include <../include/time.h> // See issue #6714 #include #include #include "sntp.h" #include "coredecls.h" +#include // configTime() + #include "sntp-lwip2.h" extern "C" { @@ -71,14 +73,45 @@ int clock_gettime(clockid_t unused, struct timespec *tp) return 0; } +#if LWIP_VERSION_MAJOR == 1 +// hack for espressif time management included in patched lwIP-1.4 +#define sntp_real_timestamp sntp_get_current_timestamp() +#endif + +#if LWIP_VERSION_MAJOR != 1 + +// backport Espressif api + +bool sntp_set_timezone_in_seconds (int32_t timezone_sec) +{ + configTime(timezone_sec, 0, sntp_getservername(0), sntp_getservername(1), sntp_getservername(2)); + return true; +} + +bool sntp_set_timezone(sint8 timezone_in_hours) +{ + return sntp_set_timezone_in_seconds(3600 * ((int)timezone_in_hours)); +} + +char* sntp_get_real_time(time_t t) +{ + return ctime(&t); +} + +uint32 sntp_get_current_timestamp() +{ + return sntp_real_timestamp; +} + +#endif + time_t time(time_t * t) { - time_t seconds = sntp_get_current_timestamp(); if (t) { - *t = seconds; + *t = sntp_real_timestamp; } - return seconds; + return sntp_real_timestamp; } int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) @@ -88,7 +121,7 @@ int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) if (tp) { if (!timeshift64_is_set) - tune_timeshift64(sntp_get_current_timestamp() * 1000000ULL); + tune_timeshift64(sntp_real_timestamp * 1000000ULL); uint64_t currentTime_us = timeshift64 + micros64(); tp->tv_sec = currentTime_us / 1000000ULL; tp->tv_usec = currentTime_us % 1000000ULL; @@ -100,15 +133,57 @@ int _gettimeofday_r(struct _reent* unused, struct timeval *tp, void *tzp) void configTime(int timezone_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3) { - sntp_stop(); + // There is no way to tell when DST starts or stop with this API + // So DST is always integrated in TZ + // The other API should be preferred + /*** portable version using posix API + (calls sprintf here, then sscanf internally) + + int tzs = daylightOffset_sec + timezone_sec; + int tzh = tzs / 3600; + tzs -= tzh * 3600; + int tzm = tzs / 60; + tzs -= tzm * 60; + + // man tzset: + char tzstr [64]; + snprintf(tzstr, sizeof tzstr, "ESPUSER<%+d:%02d:%02d>", tzh, tzm, tzs); + return configTime(tzstr, server1, server2, server3); + + Replaced by light code found from + newlib inspection and internal structure hacking + (no sprintf, no sscanf, -7584 flash bytes): + + ***/ + + static char gmt[] = "GMT"; + + _timezone = timezone_sec + daylightOffset_sec; + _daylight = 0; + _tzname[0] = gmt; + _tzname[1] = gmt; + auto tz = __gettzinfo(); + tz->__tznorth = 1; + tz->__tzyear = 0; + for (int i = 0; i < 2; i++) + { + auto tzr = &tz->__tzrule[i]; + tzr->ch = 74; + tzr->m = 0; + tzr->n = 0; + tzr->d = 0; + tzr->s = 0; + tzr->change = 0; + tzr->offset = _timezone; + } + + // sntp servers setServer(0, server1); setServer(1, server2); setServer(2, server3); - sntp_set_timezone_in_seconds(timezone_sec); - sntp_set_daylight(daylightOffset_sec); - sntp_init(); + /*** end of posix replacement ***/ } void configTime(const char* tz, const char* server1, const char* server2, const char* server3) @@ -118,7 +193,6 @@ void configTime(const char* tz, const char* server1, const char* server2, const setServer(0, server1); setServer(1, server2); setServer(2, server3); - char tzram[strlen_P(tz) + 1]; memcpy_P(tzram, tz, sizeof(tzram)); setenv("TZ", tzram, 1/*overwrite*/); diff --git a/cores/esp8266/uart.cpp b/cores/esp8266/uart.cpp index 05a425c9c..fd8170b58 100644 --- a/cores/esp8266/uart.cpp +++ b/cores/esp8266/uart.cpp @@ -577,7 +577,7 @@ uart_get_baudrate(uart_t* uart) } uart_t* -uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size) +uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size, bool invert) { uart_t* uart = (uart_t*) malloc(sizeof(uart_t)); if(uart == NULL) @@ -657,6 +657,10 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx } uart_set_baudrate(uart, baudrate); + if(uart->uart_nr == UART0 && invert) + { + config |= BIT(UCDTRI) | BIT(UCRTSI) | BIT(UCTXI) | BIT(UCDSRI) | BIT(UCCTSI) | BIT(UCRXI); + } USC0(uart->uart_nr) = config; if(!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0) { diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h index fd6158568..4871b5e93 100644 --- a/cores/esp8266/uart.h +++ b/cores/esp8266/uart.h @@ -113,7 +113,7 @@ extern "C" { struct uart_; typedef struct uart_ uart_t; -uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size); +uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size, bool invert); void uart_uninit(uart_t* uart); void uart_swap(uart_t* uart, int tx_pin); diff --git a/cores/esp8266/umm_malloc/umm_local.c b/cores/esp8266/umm_malloc/umm_local.c index b984e86b8..1b20bcf7d 100644 --- a/cores/esp8266/umm_malloc/umm_local.c +++ b/cores/esp8266/umm_malloc/umm_local.c @@ -162,6 +162,10 @@ UMM_STATISTICS ummStats; // Keep complete call path in IRAM size_t umm_free_heap_size_lw( void ) { + if (umm_heap == NULL) { + umm_init(); + } + return (size_t)ummStats.free_blocks * sizeof(umm_block); } #endif @@ -211,5 +215,3 @@ int ICACHE_FLASH_ATTR umm_info_safe_printf_P(const char *fmt, ...) { } #endif // BUILD_UMM_MALLOC_C - - diff --git a/doc/PROGMEM.rst b/doc/PROGMEM.rst index eb4402806..e455df639 100644 --- a/doc/PROGMEM.rst +++ b/doc/PROGMEM.rst @@ -145,7 +145,7 @@ constructor: .. code:: cpp - String(const char *cstr = ""); // constructor from const char * + String(const char *cstr = nullptr); // constructor from const char * String(const String &str); // copy constructor String(const __FlashStringHelper *str); // constructor for flash strings @@ -237,6 +237,42 @@ the value back. } } +How do I declare Arrays of strings in PROGMEM and retrieve an element from it. +------------------------------------------------------------------------------ + +It is often convenient when working with large amounts of text, such as a project with an LCD display, to setup an array of strings. Because strings themselves are arrays, this is actually an example of a two-dimensional array. + +These tend to be large structures so putting them into program memory is often desirable. The code below illustrates the idea. + +.. code:: cpp + + // Define Strings + const char string_0[] PROGMEM = "String 0"; + const char string_1[] PROGMEM = "String 1"; + const char string_2[] PROGMEM = "String 2"; + const char string_3[] PROGMEM = "String 3"; + const char string_4[] PROGMEM = "String 4"; + const char string_5[] PROGMEM = "String 5"; + + // Initialize Table of Strings + const char* const string_table[] PROGMEM = { string_0, string_1, string_2, string_3, string_4, string_5 }; + + char buffer[30]; // buffer for reading the string to (needs to be large enough to take the longest string + + void setup() { + Serial.begin(9600); + Serial.println("OK"); + } + + void loop() { + for (int i = 0; i < 6; i++) { + strcpy_P(buffer, (char*)pgm_read_dword(&(string_table[i]))); + Serial.println(buffer); + delay(500); + } + } + + In summary ---------- diff --git a/doc/boards.rst b/doc/boards.rst index ae476989e..a27c1d5cf 100644 --- a/doc/boards.rst +++ b/doc/boards.rst @@ -317,6 +317,11 @@ SparkFun ESP8266 Thing Dev Product page: https://www.sparkfun.com/products/13711 +SparkFun Blynk Board +-------------------- + +Product page: https://www.sparkfun.com/products/13794 + SweetPea ESP-210 ---------------- @@ -447,3 +452,30 @@ Initially designed for kids in mind, everybody should be able to use it. Yet it' More details at https://shop.makestro.com/product/espectrocore/ +Schirmilabs Eduino WiFi +----------------------- + +Eduino WiFi is an Arduino-compatible DIY WiFi development board using an ESP-12 module + +Product page: https://schirmilabs.de/?page_id=165 + +ITEAD Sonoff +------------ + +ESP8266 based devices from ITEAD: Sonoff SV, Sonoff TH, Sonoff Basic, and Sonoff S20 + +These are not development boards. The development process is inconvenient with these devices. When flashing firmware you will need a Serial Adapter to connect it to your computer. + + | Most of these devices, during normal operation, are connected to *wall power (AKA Mains Electricity)*. **NEVER** try to flash these devices when connected to *wall power*. **ALWAYS** have them disconnected from *wall power* when connecting them to your computer. Your life may depend on it! + +When flashing you will need to hold down the push button connected to the GPIO0 pin, while powering up with a safe 3.3 Volt source. Some USB Serial Adapters may supply enough power to handle flashing; however, it many may not supply enough power to handle the activities when the device reboots. + +More product details at the bottom of https://www.itead.cc/wiki/Product/ + +DOIT ESP-Mx DevKit (ESP8285) +---------------------------- + +DOIT ESP-Mx DevKit - This is a development board by DOIT, with a DOIT ESP-Mx module (`datasheet `__) using a ESP8285 Chip. With the DOIT ESP-Mx module, GPIO pins 9 and 10 are not available. The DOIT ESP-Mx DevKit board has a red power LED and a blue LED connected to GPIO16 and is active low to turn on. It uses a CH340C, USB to Serial converter chip. +ESP8285 (`datasheet `__) is a multi-chip package which contains ESP8266 and 1MB flash. + + diff --git a/doc/esp8266wifi/bearssl-server-secure-class.rst b/doc/esp8266wifi/bearssl-server-secure-class.rst index fac5b95c6..dffefc0de 100644 --- a/doc/esp8266wifi/bearssl-server-secure-class.rst +++ b/doc/esp8266wifi/bearssl-server-secure-class.rst @@ -3,7 +3,7 @@ BearSSL Secure Server Class --------------------------- -Implements a TLS encrypted server with optional client certificate validation. See `Server Class `__ for general information and `BearSSL Secure Client Class `__ for basic server and BearSSL concepts. +Implements a TLS encrypted server with optional client certificate validation. See `Server Class `__ for general information and `BearSSL Secure Client Class `__ for basic server and BearSSL concepts. setBufferSizes(int recv, int xmit) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/faq/a05-board-generator.rst b/doc/faq/a05-board-generator.rst index b57397e27..56adf273a 100644 --- a/doc/faq/a05-board-generator.rst +++ b/doc/faq/a05-board-generator.rst @@ -54,6 +54,8 @@ As of today you can: * change the default lwIP version (1.4 or 2) +* create an abridged boards.txt file + When do I need to mess with it ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -78,4 +80,61 @@ After a modification in the generator, it is **mandatory** to regenerate all files (option ``--allgen``) and add them in the pull-request. +How to create an abridged boards.txt file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The list of boards presented by the IDE has gotten quite long. You can reduce +the ESP8266 boards shown by the IDE to a favorites list. This can +be done by generating a new boards.txt file using the ``--filter `` +option. + +Start by getting a current list of boards supported by boards.txt.py. +This command will write a list of supported board names to favorites.txt. + +:: + + ./tools/boards.txt.py --boardnames >favorites.txt + +Edit favorites.txt, keeping the name of the boards you want generated in +boards.txt. + +to generate a new abridged boards.txt run: + +:: + + ./tools/boards.txt.py --boardsgen --filter favorites.txt + + +You can turn the process around by creating a list of boards, you do not want +to be generated. To do this we use the ``--xfilter `` option. + +to generate this abridged boards.txt run: + +:: + + ./tools/boards.txt.py --boardsgen --xfilter favorites.txt + + +Yet another option, you can split the boards between boards.txt and +boards.local.txt. + +The commands below will generate a boards.txt file that omits the boards named +in favorites.txt, and generates a boards.local.txt ( via option ``--boardslocalgen`` ) that only contains boards +named in favorites.txt. + +:: + + ./tools/boards.txt.py --boardsgen --xfilter favorites.txt + ./tools/boards.txt.py --boardslocalgen --filter favorites.txt + +Additional Notes: + +1. The boards.txt file will always contain the generic and esp8285 boards. + +2. If boards.txt file exist and no backup copy named boards.txt.orig exist, the current boards.txt will be renamed to boards.txt.orig. Otherwise, the existing boards.txt is over-writen when you generate a new boards.txt file. Similar behavior for when generating a new boards.local.txt. + +3. The boards in the boards.txt file will be in the order they were listed in your favorites file, specified by option ``--filter ``. + +4. It is outside the scope of this document, but you could manually edit any boards.txt file to have fewer boards. One last observation, the Arduino IDE appears to need at least one board in a board.txt file. + `FAQ list :back: `__ diff --git a/doc/filesystem.rst b/doc/filesystem.rst index d70655f2f..abf47a7ea 100644 --- a/doc/filesystem.rst +++ b/doc/filesystem.rst @@ -92,6 +92,27 @@ and ``SPIFFS.open()`` to ``LittleFS.open()`` with the rest of the code remaining untouched. +SDFS and SD +----------- +FAT filesystems are supported on the ESP8266 using the old Arduino wrapper +"SD.h" which wraps the "SDFS.h" filesystem transparently. + +Any commands discussed below pertaining to SPIFFS or LittleFS are +applicable to SD/SDFS. + +For legacy applications, the classic SD filesystem may continue to be used, +but for new applications, directly accessing the SDFS filesystem is +recommended as it may expose additional functionality that the old Arduino +SD filesystem didn't have. + +Note that in earlier releases of the core, using SD and SPIFFS in the same +sketch was complicated and required the use of ``NO_FS_GLOBALS``. The +current design makes SD, SDFS, SPIFFS, and LittleFS fully source compatible +and so please remove any ``NO_FS_GLOBALS`` definitions in your projects +when updgrading core versions. + + + SPIFFS file system limitations ------------------------------ @@ -169,11 +190,11 @@ directory into ESP8266 flash file system. **Warning**: Due to the move from the obsolete esptool-ck.exe to the supported esptool.py upload tool, upgraders from pre 2.5.1 will need to -update the ESP8266FS tool referenced below to 0.4.0 or later. Prior versions +update the ESP8266FS tool referenced below to 0.5.0 or later. Prior versions will fail with a "esptool not found" error because they don't know how to use esptool.py. -- Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.4.0/ESP8266FS-0.4.0.zip +- Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.5.0/ESP8266FS-0.5.0.zip - In your Arduino sketchbook directory, create ``tools`` directory if it doesn't exist yet. - Unpack the tool into ``tools`` directory (the path will look like @@ -193,13 +214,13 @@ use esptool.py. *ESP8266LittleFS* is the equivalent tool for LittleFS. -- Download the tool: https://github.com/earlephilhower/arduino-esp8266littlefs-plugin/releases +- Download the 2.6.0 or later version of the tool: https://github.com/earlephilhower/arduino-esp8266littlefs-plugin/releases - Install as above - To upload a LittleFS filesystem use Tools > ESP8266 LittleFS Data Upload -File system object (SPIFFS/LittleFS) ------------------------------------- +File system object (SPIFFS/LittleFS/SD/SDFS) +-------------------------------------------- setConfig ~~~~~~~~~ @@ -369,41 +390,6 @@ rename Renames file from ``pathFrom`` to ``pathTo``. Paths must be absolute. Returns *true* if file was renamed successfully. -info -~~~~ - -.. code:: cpp - - FSInfo fs_info; - SPIFFS.info(fs_info); - or LittleFS.info(fs_info); - -Fills `FSInfo structure <#filesystem-information-structure>`__ with -information about the file system. Returns ``true`` is successful, -``false`` otherwise. - -Filesystem information structure --------------------------------- - -.. code:: cpp - - struct FSInfo { - size_t totalBytes; - size_t usedBytes; - size_t blockSize; - size_t pageSize; - size_t maxOpenFiles; - size_t maxPathLength; - }; - -This is the structure which may be filled using FS::info method. - -``totalBytes`` — total size of useful data on the file system - -``usedBytes`` — number of bytes used by files - ``blockSize`` — filesystem -block size - ``pageSize`` — filesystem logical page size - ``maxOpenFiles`` -— max number of files which may be open simultaneously - -``maxPathLength`` — max file name length (including one byte for zero -termination) - gc ~~ @@ -429,6 +415,81 @@ Only implemented in SPIFFS. Performs an in-depth check of the filesystem metada correct what is repairable. Not normally needed, and not guaranteed to actually fix anything should there be corruption. +info +~~~~ + +.. code:: cpp + + FSInfo fs_info; + SPIFFS.info(fs_info); + or LittleFS.info(fs_info); + +Fills `FSInfo structure <#filesystem-information-structure>`__ with +information about the file system. Returns ``true`` if successful, +``false`` otherwise. + +Filesystem information structure +-------------------------------- + +.. code:: cpp + + struct FSInfo { + size_t totalBytes; + size_t usedBytes; + size_t blockSize; + size_t pageSize; + size_t maxOpenFiles; + size_t maxPathLength; + }; + +This is the structure which may be filled using FS::info method. - +``totalBytes`` — total size of useful data on the file system - +``usedBytes`` — number of bytes used by files - ``blockSize`` — filesystem +block size - ``pageSize`` — filesystem logical page size - ``maxOpenFiles`` +— max number of files which may be open simultaneously - +``maxPathLength`` — max file name length (including one byte for zero +termination) + +info64 +~~~~~~ + +.. code:: cpp + + FSInfo64 fsinfo; + SD.info(fsinfo); + or LittleFS(fsinfo); + +Performs the same operation as ``info`` but allows for reporting greater than +4GB for filesystem size/used/etc. Should be used with the SD and SDFS +filesystems since most SD cards today are greater than 4GB in size. + +setTimeCallback(time_t (*cb)(void)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: cpp + + time_t myTimeCallback() { + return 1455451200; // UNIX timestamp + } + void setup () { + LittleFS.setTimeCallback(myTimeCallback); + ... + // Any files will now be made with Pris' incept date + } + + +The SD, SDFS, and LittleFS filesystems support a file timestamp, updated when the file is +opened for writing. By default, the ESP8266 will use the internal time returned from +``time(NULL)`` (i.e. local time, not UTC, to conform to the existing FAT filesystem), but this +can be overridden to GMT or any other standard you'd like by using ``setTimeCallback()``. +If your app sets the system time using NTP before file operations, then +you should not need to use this function. However, if you need to set a specific time +for a file, or the system clock isn't correct and you need to read the time from an external +RTC or use a fixed time, this call allows you do to so. + +In general use, with a functioning ``time()`` call, user applications should not need +to use this function. + Directory object (Dir) ---------------------- @@ -468,6 +529,17 @@ fileSize Returns the size of the current file pointed to by the internal iterator. +fileTime +~~~~~~~~ + +Returns the time_t write time of the current file pointed +to by the internal iterator. + +fileCreationTime +~~~~~~~~~~~~~~~~ +Returns the time_t creation time of the current file +pointed to by the internal iterator. + isFile ~~~~~~ @@ -491,6 +563,13 @@ rewind Resets the internal pointer to the start of the directory. +setTimeCallback(time_t (*cb)(void)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sets the time callback for any files accessed from this Dir object via openNextFile. +Note that the SD and SDFS filesystems only support a filesystem-wide callback and +calls to ``Dir::setTimeCallback`` may produce unexpected behavior. + File object ----------- @@ -562,6 +641,17 @@ fullName Returns the full path file name as a ``const char*``. +getLastWrite +~~~~~~~~~~~~ + +Returns the file last write time, and only valid for files opened in read-only +mode. If a file is opened for writing, the returned time may be indeterminate. + +getCreationTime +~~~~~~~~~~~~~~~ + +Returns the file creation time, if available. + isFile ~~~~~~ @@ -616,3 +706,10 @@ rewindDirectory (compatibiity method, not recommended for new code) Resets the ``openNextFile`` pointer to the top of the directory. Only valid when ``File.isDirectory() == true``. + +setTimeCallback(time_t (*cb)(void)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sets the time callback for this specific file. Note that the SD and +SDFS filesystems only support a filesystem-wide callback and calls to +``Dir::setTimeCallback`` may produce unexpected behavior. diff --git a/doc/installing.rst b/doc/installing.rst index a83d4161f..ca9e3f449 100644 --- a/doc/installing.rst +++ b/doc/installing.rst @@ -53,7 +53,8 @@ Instructions - Windows 10 ~~~~~~~~~~~~~~~~~~~~~~~~~ - First, make sure you don't already have an ESP8266 core version installed using the Board Manager (see above). If you do, uninstall it from the - Board Manager before proceeding. + Board Manager before proceeding. It is also advisable to erase the Arduino15 + contents. - Install git for Windows (if not already; see https://git-scm.com/download/win) @@ -136,7 +137,8 @@ Instructions - Other OS - First, make sure you don't already have an ESP8266 core version installed using the Board Manager (see above). If you do, uninstall it from the - Board Manager before proceeding. + Board Manager before proceeding. It is also advisable to erase the .arduino15 (Linux) + or Arduino15 (MacOS) contents. - Open the console and go to Arduino directory. This can be either your *sketchbook* directory (usually ``/Arduino``), or the diff --git a/doc/libraries.rst b/doc/libraries.rst index c902dc196..d99dfe71f 100644 --- a/doc/libraries.rst +++ b/doc/libraries.rst @@ -113,6 +113,8 @@ Some ESP-specific APIs related to deep sleep, RTC and flash memories are availab ``ESP.getCycleCount()`` returns the cpu instruction cycle count since start as an unsigned 32-bit. This is useful for accurate timing of very short actions like bit banging. +``ESP.checkFlashCRC()`` calculates the CRC of the program memory (not including any filesystems) and compares it to the one embedded in the image. If this call returns ``false`` then the flash has been corrupted. At that point, you may want to consider trying to send a MQTT message, to start a re-download of the application, blink a LED in an `SOS` pattern, etc. However, since the flash is known corrupted at this point there is no guarantee the app will be able to perform any of these operations, so in safety critical deployments an immediate shutdown to a fail-safe mode may be indicated. + ``ESP.getVcc()`` may be used to measure supply voltage. ESP needs to reconfigure the ADC at startup in order for this feature to be available. Add the following line to the top of your sketch to use ``getVcc``: .. code:: cpp diff --git a/doc/ota_updates/readme.rst b/doc/ota_updates/readme.rst old mode 100644 new mode 100755 index f5c76f0d2..a783bc782 --- a/doc/ota_updates/readme.rst +++ b/doc/ota_updates/readme.rst @@ -61,7 +61,7 @@ As shown below, the signed hash is appended to the unsigned binary, followed by .. code:: bash - NORMAL-BINARY + NORMAL-BINARY Signed Binary Prerequisites ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -123,7 +123,7 @@ Compile the sketch normally and, once a `.bin` file is available, sign it using .. code:: bash - /tools/signing.py --mode sign --privatekey --bin --out + /tools/signing.py --mode sign --privatekey --bin --out Old And New Signature Formats ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,34 @@ To create a legacy signature, call the signing script with --legacy: .. code:: bash - /tools/signing.py --mode sign --privatekey --bin --out --legacy + /tools/signing.py --mode sign --privatekey --bin --out --legacy + + +Compression +----------- + +The eboot bootloader incorporates a GZIP decompressor, built for very low code requirements. For applications, this optional decompression is completely transparent. For uploading compressed filesystems, the application must be built with `ATOMIC_FS_UPDATE` defined because, otherwise, eboot will not be involved in writing the filesystem. + +No changes to the application are required. The `Updater` class and `eboot` bootloader (which performs actual application overwriting on update) automatically search for the `gzip` header in the uploaded binary, and if found, handle it. + +Compress an application `.bin` file or filesystem package using any `gzip` available, at any desired compression level (`gzip -9` is recommended because it provides the maximum compression and uncompresses as fast as any other compressino level). For example: + +.. code:: bash + + gzip -9 sketch.bin # Maximum compression, output sketch.bin.gz + + +If signing is desired, sign the gzip compressed file *after* compression. + +.. code:: bash + + gzip -9 sketch.bin + /tools/signing.py --mode sign --privatekey --bin sketch.bin.gz --out sketch.bin.gz.signed + +Updating apps in the field to support compression +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you have applications deployed in the field and wish to update them to support compressed OTA uploads, you will need to first recompile the application, then _upload the uncompressed `.bin` file once_. Attempting to upload a `gzip` compressed binary to a legacy app will result in the Updater rejecting the upload as it does not understand the `gzip` format. After this initial upload, which will include the new bootloader and `Updater` class with compression support, compressed updates can then be used. Safety @@ -173,11 +200,11 @@ The following chapters provide more details and specific methods for OTA updates Arduino IDE ----------- -Uploading modules wirelessly from Arduino IDE is intended for the following typical scenarios: +Uploading modules wirelessly from Arduino IDE is intended for the following typical scenarios: -- during firmware development as a quicker alternative to loading over a serial port, +- during firmware development as a quicker alternative to loading over a serial port, -- for updating a small number of modules, +- for updating a small number of modules, - only if modules are accessible on the same network as the computer with the Arduino IDE. @@ -483,6 +510,11 @@ HTTP Server ``ESPhttpUpdate`` class can check for updates and download a binary file from HTTP web server. It is possible to download updates from every IP or domain address on the network or Internet. +Note that by default this class closes all other connections except the one used by the update, this is because the update method blocks. This means that if there's another application receiving data then TCP packets will build up in the buffer leading to out of memory errors causing the OTA update to fail. There's also a limited number of receive buffers available and all may be used up by other applications. + +There are some cases where you know that you won't be receiving any data but would still like to send progress updates. +It's possible to disable the default behaviour (and keep connections open) by calling closeConnectionsOnUpdate(false). + Requirements ~~~~~~~~~~~~ @@ -646,7 +678,7 @@ Update process - memory view - the new sketch is now copied "over" the old one. - the new sketch is started. -By default, filesystem updates are overriding the target flash directly. In order to use the same two step process set the `ATOMIC_FS_UPDATE` flag. +By default, OTA filesystem updates overwrite the target flash directly. This can lead to the file system being corrupted if there is a power outage during the update process. In order to use the same two step process that is used for OTA application firmware updates, set the `ATOMIC_FS_UPDATE` flag. Note that you will need to have enough unused space for the new filesystem image to be stored, hence is why this is not the default behaviour. .. figure:: update_memory_copy.png :alt: Memory layout for OTA updates diff --git a/doc/requirements.txt b/doc/requirements.txt index 4bed15c4d..0db3ae5ba 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,6 +1,6 @@ # Requirements file for pip # list of Python packages used in documentation build -sphinx==1.7.9 +sphinx sphinx-rtd-theme breathe nbsphinx diff --git a/libraries/ArduinoOTA/ArduinoOTA.cpp b/libraries/ArduinoOTA/ArduinoOTA.cpp index 53d5272d8..0b0789474 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/ArduinoOTA.cpp @@ -168,7 +168,7 @@ int ArduinoOTAClass::parseInt(){ } String ArduinoOTAClass::readStringUntil(char end){ - String res = ""; + String res; int value; while(true){ value = _udp_ota->read(); @@ -231,7 +231,7 @@ void ArduinoOTAClass::_onRx(){ return; } - String challenge = _password + ":" + String(_nonce) + ":" + cnonce; + String challenge = _password + ':' + String(_nonce) + ':' + cnonce; MD5Builder _challengemd5; _challengemd5.begin(); _challengemd5.add(challenge); @@ -303,7 +303,7 @@ void ArduinoOTAClass::_runUpdate() { client.setNoDelay(true); uint32_t written, total = 0; - while (!Update.isFinished() && client.connected()) { + while (!Update.isFinished() && (client.connected() || client.available())) { int waited = 1000; while (!client.available() && waited--) delay(1); diff --git a/libraries/DNSServer/src/DNSServer.cpp b/libraries/DNSServer/src/DNSServer.cpp index 31d2c9079..2113ae0f5 100644 --- a/libraries/DNSServer/src/DNSServer.cpp +++ b/libraries/DNSServer/src/DNSServer.cpp @@ -119,7 +119,7 @@ void DNSServer::respondToRequest(uint8_t *buffer, size_t length) query, queryLength); // If we have no domain name configured, just return an error - if (_domainName == "") + if (_domainName.isEmpty()) return replyWithError(dnsHeader, _errorReplyCode, query, queryLength); diff --git a/libraries/ESP8266HTTPClient/examples/PostHttpClient/PostHttpClient.ino b/libraries/ESP8266HTTPClient/examples/PostHttpClient/PostHttpClient.ino new file mode 100644 index 000000000..94d57bdbf --- /dev/null +++ b/libraries/ESP8266HTTPClient/examples/PostHttpClient/PostHttpClient.ino @@ -0,0 +1,84 @@ +/** + PostHTTPClient.ino + + Created on: 21.11.2016 + +*/ + +#include +#include + +#define USE_SERIAL Serial + +/* this can be run with an emulated server on host: + cd esp8266-core-root-dir + cd tests/host + make ../../libraries/ESP8266WebServer/examples/PostServer/PostServer + bin/PostServer/PostServer + then put your PC's IP address in SERVER_IP below, port 9080 (instead of default 80): +*/ +//#define SERVER_IP "10.0.1.7:9080" // PC address with emulation on host +#define SERVER_IP "192.168.1.42" + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +void setup() { + + USE_SERIAL.begin(115200); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + WiFi.begin(STASSID, STAPSK); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + USE_SERIAL.print("."); + } + USE_SERIAL.println(""); + USE_SERIAL.print("Connected! IP address: "); + USE_SERIAL.println(WiFi.localIP()); + +} + +void loop() { + // wait for WiFi connection + if ((WiFi.status() == WL_CONNECTED)) { + + WiFiClient client; + HTTPClient http; + + USE_SERIAL.print("[HTTP] begin...\n"); + // configure traged server and url + http.begin(client, "http://" SERVER_IP "/postplain/"); //HTTP + http.addHeader("Content-Type", "application/json"); + + USE_SERIAL.print("[HTTP] POST...\n"); + // start connection and send HTTP header and body + int httpCode = http.POST("{\"hello\":\"world\"}"); + + // httpCode will be negative on error + if (httpCode > 0) { + // HTTP header has been send and Server response header has been handled + USE_SERIAL.printf("[HTTP] POST... code: %d\n", httpCode); + + // file found at server + if (httpCode == HTTP_CODE_OK) { + const String& payload = http.getString(); + USE_SERIAL.println("received payload:\n<<"); + USE_SERIAL.println(payload); + USE_SERIAL.println(">>"); + } + } else { + USE_SERIAL.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } + + delay(10000); +} diff --git a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp index a05b9dd6f..ff46822c3 100644 --- a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp +++ b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp @@ -137,9 +137,9 @@ void HTTPClient::clear() { _returnCode = 0; _size = -1; - _headers = ""; + _headers.clear(); + _location.clear(); _payload.reset(); - _location = ""; } @@ -150,7 +150,7 @@ void HTTPClient::clear() * @param https bool * @return success bool */ -bool HTTPClient::begin(WiFiClient &client, String url) { +bool HTTPClient::begin(WiFiClient &client, const String& url) { #if HTTPCLIENT_1_1_COMPATIBLE if(_tcpDeprecated) { DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n"); @@ -188,7 +188,7 @@ bool HTTPClient::begin(WiFiClient &client, String url) { * @param https bool * @return success bool */ -bool HTTPClient::begin(WiFiClient &client, String host, uint16_t port, String uri, bool https) +bool HTTPClient::begin(WiFiClient &client, const String& host, uint16_t port, const String& uri, bool https) { #if HTTPCLIENT_1_1_COMPATIBLE if(_tcpDeprecated) { @@ -281,8 +281,10 @@ bool HTTPClient::begin(String url) } #endif // HTTPCLIENT_1_1_COMPATIBLE -bool HTTPClient::beginInternal(String url, const char* expectedProtocol) +bool HTTPClient::beginInternal(const String& __url, const char* expectedProtocol) { + String url(__url); + DEBUG_HTTPCLIENT("[HTTP-Client][begin] url: %s\n", url.c_str()); clear(); @@ -317,7 +319,7 @@ bool HTTPClient::beginInternal(String url, const char* expectedProtocol) // auth info String auth = host.substring(0, index); host.remove(0, index + 1); // remove auth part including @ - _base64Authorization = base64::encode(auth); + _base64Authorization = base64::encode(auth, false /* doNewLines */); } // get port @@ -500,9 +502,9 @@ void HTTPClient::setAuthorization(const char * user, const char * password) { if(user && password) { String auth = user; - auth += ":"; + auth += ':'; auth += password; - _base64Authorization = base64::encode(auth); + _base64Authorization = base64::encode(auth, false /* doNewLines */); } } @@ -514,6 +516,7 @@ void HTTPClient::setAuthorization(const char * auth) { if(auth) { _base64Authorization = auth; + _base64Authorization.replace(String('\n'), emptyString); } } @@ -533,7 +536,7 @@ void HTTPClient::setTimeout(uint16_t timeout) * set the URL to a new value. Handy for following redirects. * @param url */ -bool HTTPClient::setURL(String url) +bool HTTPClient::setURL(const String& url) { // if the new location is only a path then only update the URI if (url && url[0] == '/') { @@ -542,13 +545,13 @@ bool HTTPClient::setURL(String url) return true; } - if (!url.startsWith(_protocol + ":")) { + if (!url.startsWith(_protocol + ':')) { DEBUG_HTTPCLIENT("[HTTP-Client][setURL] new URL not the same protocol, expected '%s', URL: '%s'\n", _protocol.c_str(), url.c_str()); return false; } - // disconnect but preserve _client + // disconnect but preserve _client (clear _canReuse so disconnect will close the connection) + _canReuse = false; disconnect(true); - clear(); return beginInternal(url, nullptr); } @@ -587,16 +590,16 @@ int HTTPClient::GET() /** * sends a post request to the server - * @param payload uint8_t * + * @param payload const uint8_t * * @param size size_t * @return http code */ -int HTTPClient::POST(uint8_t * payload, size_t size) +int HTTPClient::POST(const uint8_t* payload, size_t size) { return sendRequest("POST", payload, size); } -int HTTPClient::POST(String payload) +int HTTPClient::POST(const String& payload) { return POST((uint8_t *) payload.c_str(), payload.length()); } @@ -607,26 +610,26 @@ int HTTPClient::POST(String payload) * @param size size_t * @return http code */ -int HTTPClient::PUT(uint8_t * payload, size_t size) { +int HTTPClient::PUT(const uint8_t* payload, size_t size) { return sendRequest("PUT", payload, size); } -int HTTPClient::PUT(String payload) { - return PUT((uint8_t *) payload.c_str(), payload.length()); +int HTTPClient::PUT(const String& payload) { + return PUT((const uint8_t *) payload.c_str(), payload.length()); } /** * sends a patch request to the server - * @param payload uint8_t * + * @param payload const uint8_t * * @param size size_t * @return http code */ -int HTTPClient::PATCH(uint8_t * payload, size_t size) { +int HTTPClient::PATCH(const uint8_t * payload, size_t size) { return sendRequest("PATCH", payload, size); } -int HTTPClient::PATCH(String payload) { - return PATCH((uint8_t *) payload.c_str(), payload.length()); +int HTTPClient::PATCH(const String& payload) { + return PATCH((const uint8_t *) payload.c_str(), payload.length()); } /** @@ -635,19 +638,19 @@ int HTTPClient::PATCH(String payload) { * @param payload String data for the message body * @return */ -int HTTPClient::sendRequest(const char * type, String payload) +int HTTPClient::sendRequest(const char * type, const String& payload) { - return sendRequest(type, (uint8_t *) payload.c_str(), payload.length()); + return sendRequest(type, (const uint8_t *) payload.c_str(), payload.length()); } /** * sendRequest - * @param type const char * "GET", "POST", .... - * @param payload uint8_t * data for the message body if null not send - * @param size size_t size for the message body if 0 not send + * @param type const char * "GET", "POST", .... + * @param payload const uint8_t * data for the message body if null not send + * @param size size_t size for the message body if 0 not send * @return -1 if no info or > 0 when Content-Length is set by server */ -int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) +int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t size) { bool redirect = false; int code = 0; @@ -655,7 +658,7 @@ int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) // wipe out any existing headers from previous request for(size_t i = 0; i < _headerKeysCount; i++) { if (_currentHeaders[i].value.length() > 0) { - _currentHeaders[i].value = ""; + _currentHeaders[i].value.clear(); } } @@ -675,9 +678,21 @@ int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) } // send Payload if needed - if(payload && size > 0) { - if(_client->write(&payload[0], size) != size) { - return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + if (payload && size > 0) { + size_t bytesWritten = 0; + const uint8_t *p = payload; + size_t originalSize = size; + while (bytesWritten < originalSize) { + int written; + int towrite = std::min((int)size, (int)HTTP_TCP_BUFFER_SIZE); + written = _client->write(p + bytesWritten, towrite); + if (written < 0) { + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } else if (written == 0) { + return returnError(HTTPC_ERROR_CONNECTION_LOST); + } + bytesWritten += written; + size -= written; } } @@ -745,7 +760,7 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) } if(size > 0) { - addHeader("Content-Length", String(size)); + addHeader(F("Content-Length"), String(size)); } // send Header @@ -1063,12 +1078,14 @@ String HTTPClient::errorToString(int error) void HTTPClient::addHeader(const String& name, const String& value, bool first, bool replace) { // not allow set of Header handled by code - if(!name.equalsIgnoreCase(F("Connection")) && - !name.equalsIgnoreCase(F("User-Agent")) && - !name.equalsIgnoreCase(F("Host")) && - !(name.equalsIgnoreCase(F("Authorization")) && _base64Authorization.length())){ + if (!name.equalsIgnoreCase(F("Connection")) && + !name.equalsIgnoreCase(F("User-Agent")) && + !name.equalsIgnoreCase(F("Host")) && + !(name.equalsIgnoreCase(F("Authorization")) && _base64Authorization.length())) { - String headerLine = name; + String headerLine; + headerLine.reserve(name.length() + value.length() + 4); + headerLine += name; headerLine += ": "; if (replace) { @@ -1081,13 +1098,12 @@ void HTTPClient::addHeader(const String& name, const String& value, bool first, headerLine += value; headerLine += "\r\n"; - if(first) { + if (first) { _headers = headerLine + _headers; } else { _headers += headerLine; } } - } void HTTPClient::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) @@ -1212,42 +1228,50 @@ bool HTTPClient::sendHeader(const char * type) return false; } - String header = String(type) + " " + (_uri.length() ? _uri : F("/")) + F(" HTTP/1."); + String header; + // 128: Arbitrarily chosen to have enough buffer space for avoiding internal reallocations + header.reserve(_headers.length() + _uri.length() + + _base64Authorization.length() + _host.length() + _userAgent.length() + 128); + header += type; + header += ' '; + if (_uri.length()) { + header += _uri; + } else { + header += '/'; + } + header += F(" HTTP/1."); if(_useHTTP10) { - header += "0"; + header += '0'; } else { - header += "1"; + header += '1'; } - header += String(F("\r\nHost: ")) + _host; + header += F("\r\nHost: "); + header += _host; if (_port != 80 && _port != 443) { header += ':'; header += String(_port); } - header += String(F("\r\nUser-Agent: ")) + _userAgent + - F("\r\nConnection: "); + header += F("\r\nUser-Agent: "); + header += _userAgent; - if(_reuse) { - header += F("keep-alive"); - } else { - header += F("close"); + if (!_useHTTP10) { + header += F("\r\nAccept-Encoding: identity;q=1,chunked;q=0.1,*;q=0"); } + + if (_base64Authorization.length()) { + header += F("\r\nAuthorization: Basic "); + header += _base64Authorization; + } + + header += F("\r\nConnection: "); + header += _reuse ? F("keep-alive") : F("close"); header += "\r\n"; - if(!_useHTTP10) { - header += F("Accept-Encoding: identity;q=1,chunked;q=0.1,*;q=0\r\n"); - } - - if(_base64Authorization.length()) { - _base64Authorization.replace("\n", ""); - header += F("Authorization: Basic "); - header += _base64Authorization; - header += "\r\n"; - } - - header += _headers + "\r\n"; + header += _headers; + header += "\r\n"; DEBUG_HTTPCLIENT("[HTTP-Client] sending request header\n-----\n%s-----\n", header.c_str()); @@ -1278,20 +1302,23 @@ int HTTPClient::handleHeaderResponse() size_t len = _client->available(); if(len > 0) { String headerLine = _client->readStringUntil('\n'); - headerLine.trim(); // remove \r lastDataTime = millis(); DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] RX: '%s'\n", headerLine.c_str()); - if(headerLine.startsWith("HTTP/1.")) { - if(_canReuse) { + if (headerLine.startsWith(F("HTTP/1."))) { + if (_canReuse) { _canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0'); } _returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt(); - } else if(headerLine.indexOf(':')) { - String headerName = headerLine.substring(0, headerLine.indexOf(':')); - String headerValue = headerLine.substring(headerLine.indexOf(':') + 1); + continue; + } + + int headerSeparator = headerLine.indexOf(':'); + if (headerSeparator > 0) { + String headerName = headerLine.substring(0, headerSeparator); + String headerValue = headerLine.substring(headerSeparator + 1); headerValue.trim(); if(headerName.equalsIgnoreCase(F("Content-Length"))) { @@ -1299,7 +1326,8 @@ int HTTPClient::handleHeaderResponse() } if(_canReuse && headerName.equalsIgnoreCase(F("Connection"))) { - if(headerValue.indexOf("close") >= 0 && headerValue.indexOf("keep-alive") < 0) { + if (headerValue.indexOf(F("close")) >= 0 && + headerValue.indexOf(F("keep-alive")) < 0) { _canReuse = false; } } @@ -1312,20 +1340,24 @@ int HTTPClient::handleHeaderResponse() _location = headerValue; } - for(size_t i = 0; i < _headerKeysCount; i++) { - if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) { - if (_currentHeaders[i].value != "") { + for (size_t i = 0; i < _headerKeysCount; i++) { + if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) { + if (!_currentHeaders[i].value.isEmpty()) { // Existing value, append this one with a comma - _currentHeaders[i].value += "," + headerValue; + _currentHeaders[i].value += ','; + _currentHeaders[i].value += headerValue; } else { _currentHeaders[i].value = headerValue; } break; // We found a match, stop looking } } + continue; } - if(headerLine == "") { + headerLine.trim(); // remove \r + + if (headerLine.isEmpty()) { DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: %d\n", _returnCode); if(_size > 0) { diff --git a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h index d6e4f88c0..1d7548f0f 100644 --- a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h +++ b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.h @@ -147,8 +147,8 @@ public: * Since both begin() functions take a reference to client as a parameter, you need to * ensure the client object lives the entire time of the HTTPClient */ - bool begin(WiFiClient &client, String url); - bool begin(WiFiClient &client, String host, uint16_t port, String uri = "/", bool https = false); + bool begin(WiFiClient &client, const String& url); + bool begin(WiFiClient &client, const String& host, uint16_t port, const String& uri = "/", bool https = false); #if HTTPCLIENT_1_1_COMPATIBLE // Plain HTTP connection, unencrypted @@ -175,20 +175,20 @@ public: void setTimeout(uint16_t timeout); void setFollowRedirects(bool follow); void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request - bool setURL(String url); // handy for handling redirects + bool setURL(const String& url); // handy for handling redirects void useHTTP10(bool usehttp10 = true); /// request handling int GET(); - int POST(uint8_t * payload, size_t size); - int POST(String payload); - int PUT(uint8_t * payload, size_t size); - int PUT(String payload); - int PATCH(uint8_t * payload, size_t size); - int PATCH(String payload); - int sendRequest(const char * type, String payload); - int sendRequest(const char * type, uint8_t * payload = NULL, size_t size = 0); - int sendRequest(const char * type, Stream * stream, size_t size = 0); + int POST(const uint8_t* payload, size_t size); + int POST(const String& payload); + int PUT(const uint8_t* payload, size_t size); + int PUT(const String& payload); + int PATCH(const uint8_t* payload, size_t size); + int PATCH(const String& payload); + int sendRequest(const char* type, const String& payload); + int sendRequest(const char* type, const uint8_t* payload = NULL, size_t size = 0); + int sendRequest(const char* type, Stream * stream, size_t size = 0); void addHeader(const String& name, const String& value, bool first = false, bool replace = true); @@ -216,7 +216,7 @@ protected: String value; }; - bool beginInternal(String url, const char* expectedProtocol); + bool beginInternal(const String& url, const char* expectedProtocol); void disconnect(bool preserveClient = false); void clear(); int returnError(int error); diff --git a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h index 6761177a0..966a73eef 100644 --- a/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h +++ b/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer-impl.h @@ -5,7 +5,6 @@ #include #include #include -#include #include "StreamString.h" #include "ESP8266HTTPUpdateServer.h" @@ -22,12 +21,12 @@ static const char serverIndex[] PROGMEM =
Firmware:
- +
FileSystem:
- +
@@ -78,7 +77,7 @@ void ESP8266HTTPUpdateServerTemplate::setup(ESP8266WebServerTemplate HTTPUpload& upload = _server->upload(); if(upload.status == UPLOAD_FILE_START){ - _updaterError = String(); + _updaterError.clear(); if (_serial_output) Serial.setDebugOutput(true); @@ -94,8 +93,7 @@ void ESP8266HTTPUpdateServerTemplate::setup(ESP8266WebServerTemplate Serial.printf("Update: %s\n", upload.filename.c_str()); if (upload.name == "filesystem") { size_t fsSize = ((size_t) &_FS_end - (size_t) &_FS_start); - SPIFFS.end(); - LittleFS.end(); + close_all_fs(); if (!Update.begin(fsSize, U_FS)){//start with max available size if (_serial_output) Update.printError(Serial); } diff --git a/libraries/ESP8266SSDP/ESP8266SSDP.cpp b/libraries/ESP8266SSDP/ESP8266SSDP.cpp index 900c2059f..93121ffc8 100644 --- a/libraries/ESP8266SSDP/ESP8266SSDP.cpp +++ b/libraries/ESP8266SSDP/ESP8266SSDP.cpp @@ -69,11 +69,11 @@ static const char _ssdp_notify_template[] PROGMEM = static const char _ssdp_packet_template[] PROGMEM = "%s" // _ssdp_response_template / _ssdp_notify_template - "CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL + "CACHE-CONTROL: max-age=%u\r\n" // _interval "SERVER: Arduino/1.0 UPNP/1.1 %s/%s\r\n" // _modelName, _modelNumber "USN: %s\r\n" // _uuid "%s: %s\r\n" // "NT" or "ST", _deviceType - "LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL + "LOCATION: http://%s:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL "\r\n"; static const char _ssdp_schema_template[] PROGMEM = @@ -88,7 +88,7 @@ static const char _ssdp_schema_template[] PROGMEM = "1" "0" "" - "http://%u.%u.%u.%u:%u/" // WiFi.localIP(), _port + "http://%s:%u/" // WiFi.localIP(), _port "" "%s" "%s" @@ -130,6 +130,7 @@ SSDPClass::SSDPClass() : _timer(0), _port(80), _ttl(SSDP_MULTICAST_TTL), + _interval(SSDP_INTERVAL), _respondToAddr(0,0,0,0), _respondToPort(0), _pending(false), @@ -241,13 +242,13 @@ void SSDPClass::_send(ssdp_method_t method) { int len = snprintf_P(buffer, sizeof(buffer), _ssdp_packet_template, valueBuffer, - SSDP_INTERVAL, + _interval, _modelName, _modelNumber, _uuid, (method == NONE) ? "ST" : "NT", (_st_is_uuid) ? _uuid : _deviceType, - ip[0], ip[1], ip[2], ip[3], _port, _schemaURL + ip.toString().c_str(), _port, _schemaURL ); _server->append(buffer, len); @@ -276,12 +277,12 @@ void SSDPClass::_send(ssdp_method_t method) { _server->send(remoteAddr, remotePort); } -void SSDPClass::schema(WiFiClient client) { +void SSDPClass::schema(Print &client) const { IPAddress ip = WiFi.localIP(); char buffer[strlen_P(_ssdp_schema_template) + 1]; strcpy_P(buffer, _ssdp_schema_template); client.printf(buffer, - ip[0], ip[1], ip[2], ip[3], _port, + ip.toString().c_str(), _port, _deviceType, _friendlyName, _presentationURL, @@ -428,7 +429,7 @@ void SSDPClass::_update() { if (_pending && (millis() - _process_time) > _delay) { _pending = false; _delay = 0; _send(NONE); - } else if(_notify_time == 0 || (millis() - _notify_time) > (SSDP_INTERVAL * 1000L)){ + } else if(_notify_time == 0 || (millis() - _notify_time) > (_interval * 1000L)){ _notify_time = millis(); _st_is_uuid = false; _send(NOTIFY); @@ -493,11 +494,14 @@ void SSDPClass::setManufacturerURL(const char *url) { strlcpy(_manufacturerURL, url, sizeof(_manufacturerURL)); } - void SSDPClass::setTTL(const uint8_t ttl) { _ttl = ttl; } +void SSDPClass::setInterval(uint32_t interval) { + _interval = interval; +} + void SSDPClass::_onTimerStatic(SSDPClass* self) { self->_update(); } diff --git a/libraries/ESP8266SSDP/ESP8266SSDP.h b/libraries/ESP8266SSDP/ESP8266SSDP.h index 5fbbf5936..527822f6d 100644 --- a/libraries/ESP8266SSDP/ESP8266SSDP.h +++ b/libraries/ESP8266SSDP/ESP8266SSDP.h @@ -62,7 +62,8 @@ class SSDPClass{ ~SSDPClass(); bool begin(); void end(); - void schema(WiFiClient client); + void schema(WiFiClient client) const { schema((Print&)std::ref(client)); } + void schema(Print &print) const; void setDeviceType(const String& deviceType) { setDeviceType(deviceType.c_str()); } void setDeviceType(const char *deviceType); @@ -70,13 +71,13 @@ class SSDPClass{ void setUUID(const String& uuid) { setUUID(uuid.c_str()); } void setUUID(const char *uuid); - void setName(const String& name) { setName(name.c_str()); } + void setName(const String& name) { setName(name.c_str()); } void setName(const char *name); void setURL(const String& url) { setURL(url.c_str()); } void setURL(const char *url); void setSchemaURL(const String& url) { setSchemaURL(url.c_str()); } void setSchemaURL(const char *url); - void setSerialNumber(const String& serialNumber) { setSerialNumber(serialNumber.c_str()); } + void setSerialNumber(const String& serialNumber) { setSerialNumber(serialNumber.c_str()); } void setSerialNumber(const char *serialNumber); void setSerialNumber(const uint32_t serialNumber); void setModelName(const String& name) { setModelName(name.c_str()); } @@ -91,6 +92,7 @@ class SSDPClass{ void setManufacturerURL(const char *url); void setHTTPPort(uint16_t port); void setTTL(uint8_t ttl); + void setInterval(uint32_t interval); protected: void _send(ssdp_method_t method); @@ -103,6 +105,7 @@ class SSDPClass{ SSDPTimer* _timer; uint16_t _port; uint8_t _ttl; + uint32_t _interval; IPAddress _respondToAddr; uint16_t _respondToPort; diff --git a/libraries/ESP8266SdFat b/libraries/ESP8266SdFat index af4ed0c5e..b240d2231 160000 --- a/libraries/ESP8266SdFat +++ b/libraries/ESP8266SdFat @@ -1 +1 @@ -Subproject commit af4ed0c5ec3084cb3883df51ec2052791ca2bff2 +Subproject commit b240d2231a117bbd89b79902eb54cae948ee2f42 diff --git a/libraries/ESP8266WebServer/README.rst b/libraries/ESP8266WebServer/README.rst index 00a3813a8..0dcf68b51 100644 --- a/libraries/ESP8266WebServer/README.rst +++ b/libraries/ESP8266WebServer/README.rst @@ -96,7 +96,7 @@ Getting information about request arguments int args(); bool hasArg(); -``arg`` - get request argument value +``arg`` - get request argument value, use ``arg("plain")`` to get POST body ``argName`` - get request argument name diff --git a/libraries/ESP8266WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino b/libraries/ESP8266WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino index fb02d0f98..2fc8508ca 100644 --- a/libraries/ESP8266WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino +++ b/libraries/ESP8266WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino @@ -94,6 +94,25 @@ void handleNotFound() { digitalWrite(led, 0); } +void drawGraph() { + String out; + out.reserve(2600); + char temp[70]; + out += "\n"; + out += "\n"; + out += "\n"; + int y = rand() % 130; + for (int x = 10; x < 390; x += 10) { + int y2 = rand() % 130; + sprintf(temp, "\n", x, 140 - y, x + 10, 140 - y2); + out += temp; + y = y2; + } + out += "\n\n"; + + server.send(200, "image/svg+xml", out); +} + void setup(void) { pinMode(led, OUTPUT); digitalWrite(led, 0); @@ -133,20 +152,3 @@ void loop(void) { MDNS.update(); } -void drawGraph() { - String out = ""; - char temp[100]; - out += "\n"; - out += "\n"; - out += "\n"; - int y = rand() % 130; - for (int x = 10; x < 390; x += 10) { - int y2 = rand() % 130; - sprintf(temp, "\n", x, 140 - y, x + 10, 140 - y2); - out += temp; - y = y2; - } - out += "\n\n"; - - server.send(200, "image/svg+xml", out); -} diff --git a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino index 69065c43d..fb5847d4b 100644 --- a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino +++ b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino @@ -122,7 +122,7 @@ void handleFileUpload() { } DBG_OUTPUT_PORT.print("handleFileUpload Name: "); DBG_OUTPUT_PORT.println(filename); fsUploadFile = filesystem->open(filename, "w"); - filename = String(); + filename.clear(); } else if (upload.status == UPLOAD_FILE_WRITE) { //DBG_OUTPUT_PORT.print("handleFileUpload Data: "); DBG_OUTPUT_PORT.println(upload.currentSize); if (fsUploadFile) { @@ -150,7 +150,7 @@ void handleFileDelete() { } filesystem->remove(path); server.send(200, "text/plain", ""); - path = String(); + path.clear(); } void handleFileCreate() { @@ -172,7 +172,7 @@ void handleFileCreate() { return server.send(500, "text/plain", "CREATE FAILED"); } server.send(200, "text/plain", ""); - path = String(); + path.clear(); } void handleFileList() { @@ -184,7 +184,7 @@ void handleFileList() { String path = server.arg("dir"); DBG_OUTPUT_PORT.println("handleFileList: " + path); Dir dir = filesystem->openDir(path); - path = String(); + path.clear(); String output = "["; while (dir.next()) { @@ -275,13 +275,13 @@ void setup(void) { //get heap status, analog input value and all GPIO statuses in one json call server.on("/all", HTTP_GET, []() { - String json = "{"; + String json('{'); json += "\"heap\":" + String(ESP.getFreeHeap()); json += ", \"analog\":" + String(analogRead(A0)); json += ", \"gpio\":" + String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16))); json += "}"; server.send(200, "text/json", json); - json = String(); + json.clear(); }); server.begin(); DBG_OUTPUT_PORT.println("HTTP server started"); diff --git a/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino b/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino index 40bb9ea29..1335c347a 100644 --- a/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino +++ b/libraries/ESP8266WebServer/examples/HelloServer/HelloServer.ino @@ -67,6 +67,23 @@ void setup(void) { server.send(200, "text/plain", "this works as well"); }); + server.on("/gif", []() { + static const uint8_t gif[] PROGMEM = { + 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x19, 0x8c, 0x8f, 0xa9, 0xcb, 0x9d, + 0x00, 0x5f, 0x74, 0xb4, 0x56, 0xb0, 0xb0, 0xd2, 0xf2, 0x35, 0x1e, 0x4c, + 0x0c, 0x24, 0x5a, 0xe6, 0x89, 0xa6, 0x4d, 0x01, 0x00, 0x3b + }; + char gif_colored[sizeof(gif)]; + memcpy_P(gif_colored, gif, sizeof(gif)); + // Set the background to a random set of colors + gif_colored[16] = millis() % 256; + gif_colored[17] = millis() % 256; + gif_colored[18] = millis() % 256; + server.send(200, "image/gif", gif_colored, sizeof(gif_colored)); + }); + server.onNotFound(handleNotFound); server.begin(); diff --git a/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino b/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino new file mode 100644 index 000000000..dc998986e --- /dev/null +++ b/libraries/ESP8266WebServer/examples/PathArgServer/PathArgServer.ino @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char *ssid = STASSID; +const char *password = STAPSK; + +ESP8266WebServer server(80); + +void setup(void) { + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (MDNS.begin("esp8266")) { + Serial.println("MDNS responder started"); + } + + server.on(F("/"), []() { + server.send(200, "text/plain", "hello from esp8266!"); + }); + + server.on(UriBraces("/users/{}"), []() { + String user = server.pathArg(0); + server.send(200, "text/plain", "User: '" + user + "'"); + }); + + server.on(UriRegex("^\\/users\\/([0-9]+)\\/devices\\/([0-9]+)$"), []() { + String user = server.pathArg(0); + String device = server.pathArg(1); + server.send(200, "text/plain", "User: '" + user + "' and Device: '" + device + "'"); + }); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} diff --git a/libraries/ESP8266WebServer/examples/PostServer/PostServer.ino b/libraries/ESP8266WebServer/examples/PostServer/PostServer.ino new file mode 100644 index 000000000..da1703807 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/PostServer/PostServer.ino @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +ESP8266WebServer server(80); + +const int led = LED_BUILTIN; + +const String postForms = "\ + \ + ESP8266 Web Server POST handling\ + \ + \ + \ +

POST plain text to /postplain/


\ +
\ +
\ + \ +
\ +

POST form data to /postform/


\ +
\ +
\ + \ +
\ + \ +"; + +void handleRoot() { + digitalWrite(led, 1); + server.send(200, "text/html", postForms); + digitalWrite(led, 0); +} + +void handlePlain() { + if (server.method() != HTTP_POST) { + digitalWrite(led, 1); + server.send(405, "text/plain", "Method Not Allowed"); + digitalWrite(led, 0); + } else { + digitalWrite(led, 1); + server.send(200, "text/plain", "POST body was:\n" + server.arg("plain")); + digitalWrite(led, 0); + } +} + +void handleForm() { + if (server.method() != HTTP_POST) { + digitalWrite(led, 1); + server.send(405, "text/plain", "Method Not Allowed"); + digitalWrite(led, 0); + } else { + digitalWrite(led, 1); + String message = "POST form was:\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(200, "text/plain", message); + digitalWrite(led, 0); + } +} + +void handleNotFound() { + digitalWrite(led, 1); + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); + digitalWrite(led, 0); +} + +void setup(void) { + pinMode(led, OUTPUT); + digitalWrite(led, 0); + Serial.begin(115200); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (MDNS.begin("esp8266")) { + Serial.println("MDNS responder started"); + } + + server.on("/", handleRoot); + + server.on("/postplain/", handlePlain); + + server.on("/postform/", handleForm); + + server.onNotFound(handleNotFound); + + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + server.handleClient(); +} diff --git a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino index 59432cf90..1679b5806 100644 --- a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino +++ b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino @@ -209,7 +209,7 @@ void printDirectory() { return returnFail("BAD PATH"); } File dir = SD.open((char *)path.c_str()); - path = String(); + path.clear(); if (!dir.isDirectory()) { dir.close(); return returnFail("NOT DIR"); @@ -241,6 +241,7 @@ void printDirectory() { entry.close(); } server.sendContent("]"); + server.sendContent(""); // Terminate the HTTP chunked transmission with a 0-length chunk dir.close(); } diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h index 3af7ca394..f085a8afe 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h @@ -252,28 +252,28 @@ void ESP8266WebServerTemplate::requestAuthentication(HTTPAuthMethod _srealm = String(realm); } if(mode == BASIC_AUTH) { - sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String(F("\""))); + sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String('\"')); } else { _snonce=_getRandomHexString(); _sopaque=_getRandomHexString(); - sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Digest realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String(F("\""))); + sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Digest realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String('\"')); } using namespace mime; send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg); } template -void ESP8266WebServerTemplate::on(const String &uri, ESP8266WebServerTemplate::THandlerFunction handler) { +void ESP8266WebServerTemplate::on(const Uri &uri, ESP8266WebServerTemplate::THandlerFunction handler) { on(uri, HTTP_ANY, handler); } template -void ESP8266WebServerTemplate::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate::THandlerFunction fn) { +void ESP8266WebServerTemplate::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate::THandlerFunction fn) { on(uri, method, fn, _fileUploadHandler); } template -void ESP8266WebServerTemplate::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate::THandlerFunction fn, ESP8266WebServerTemplate::THandlerFunction ufn) { +void ESP8266WebServerTemplate::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate::THandlerFunction fn, ESP8266WebServerTemplate::THandlerFunction ufn) { _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method)); } @@ -319,7 +319,7 @@ void ESP8266WebServerTemplate::handleClient() { bool keepCurrentClient = false; bool callYield = false; - if (_currentClient.connected()) { + if (_currentClient.connected() || _currentClient.available()) { switch (_currentStatus) { case HC_NONE: // No-op to avoid C++ compiler warning @@ -464,8 +464,10 @@ void ESP8266WebServerTemplate::send_P(int code, PGM_P content_type, char type[64]; memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type)); _prepareHeader(header, code, (const char* )type, contentLength); - sendContent(header); - sendContent_P(content, contentLength); + _currentClient.write((const uint8_t *)header.c_str(), header.length()); + if (contentLength) { + sendContent_P(content, contentLength); + } } template @@ -524,13 +526,13 @@ String ESP8266WebServerTemplate::credentialHash(const String& userna { MD5Builder md5; md5.begin(); - md5.add(username + ":" + realm + ":" + password); // md5 of the user:realm:password + md5.add(username + ':' + realm + ':' + password); // md5 of the user:realm:password md5.calculate(); return md5.toString(); } template -void ESP8266WebServerTemplate::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType) +void ESP8266WebServerTemplate::_streamFileCore(const size_t fileSize, const String &fileName, const String &contentType) { using namespace mime; setContentLength(fileSize); @@ -542,9 +544,15 @@ void ESP8266WebServerTemplate::_streamFileCore(const size_t fileSize send(200, contentType, emptyString); } +template +const String& ESP8266WebServerTemplate::pathArg(unsigned int i) const { + if (_currentHandler != nullptr) + return _currentHandler->pathArg(i); + return emptyString; +} template -const String& ESP8266WebServerTemplate::arg(String name) const { +const String& ESP8266WebServerTemplate::arg(const String& name) const { for (int j = 0; j < _postArgsLen; ++j) { if ( _postArgs[j].key == name ) return _postArgs[j].value; @@ -590,7 +598,7 @@ bool ESP8266WebServerTemplate::hasArg(const String& name) const { template -const String& ESP8266WebServerTemplate::header(String name) const { +const String& ESP8266WebServerTemplate::header(const String& name) const { for (int i = 0; i < _headerKeysCount; ++i) { if (_currentHeaders[i].key.equalsIgnoreCase(name)) return _currentHeaders[i].value; @@ -630,7 +638,7 @@ int ESP8266WebServerTemplate::headers() const { } template -bool ESP8266WebServerTemplate::hasHeader(String name) const { +bool ESP8266WebServerTemplate::hasHeader(const String& name) const { for (int i = 0; i < _headerKeysCount; ++i) { if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0)) return true; @@ -693,49 +701,136 @@ void ESP8266WebServerTemplate::_finalizeResponse() { } template -const String ESP8266WebServerTemplate::responseCodeToString(const int code) { - switch (code) { - case 100: return F("Continue"); - case 101: return F("Switching Protocols"); - case 200: return F("OK"); - case 201: return F("Created"); - case 202: return F("Accepted"); - case 203: return F("Non-Authoritative Information"); - case 204: return F("No Content"); - case 205: return F("Reset Content"); - case 206: return F("Partial Content"); - case 300: return F("Multiple Choices"); - case 301: return F("Moved Permanently"); - case 302: return F("Found"); - case 303: return F("See Other"); - case 304: return F("Not Modified"); - case 305: return F("Use Proxy"); - case 307: return F("Temporary Redirect"); - case 400: return F("Bad Request"); - case 401: return F("Unauthorized"); - case 402: return F("Payment Required"); - case 403: return F("Forbidden"); - case 404: return F("Not Found"); - case 405: return F("Method Not Allowed"); - case 406: return F("Not Acceptable"); - case 407: return F("Proxy Authentication Required"); - case 408: return F("Request Time-out"); - case 409: return F("Conflict"); - case 410: return F("Gone"); - case 411: return F("Length Required"); - case 412: return F("Precondition Failed"); - case 413: return F("Request Entity Too Large"); - case 414: return F("Request-URI Too Large"); - case 415: return F("Unsupported Media Type"); - case 416: return F("Requested range not satisfiable"); - case 417: return F("Expectation Failed"); - case 418: return F("I'm a teapot"); - case 500: return F("Internal Server Error"); - case 501: return F("Not Implemented"); - case 502: return F("Bad Gateway"); - case 503: return F("Service Unavailable"); - case 504: return F("Gateway Time-out"); - case 505: return F("HTTP Version not supported"); - default: return F(""); - } +String ESP8266WebServerTemplate::responseCodeToString(const int code) { + // By first determining the pointer to the flash stored string in the switch + // statement and then doing String(FlashStringHelper) return reduces the total code + // size of this function by over 50%. + const __FlashStringHelper *r; + switch (code) + { + case 100: + r = F("Continue"); + break; + case 101: + r = F("Switching Protocols"); + break; + case 200: + r = F("OK"); + break; + case 201: + r = F("Created"); + break; + case 202: + r = F("Accepted"); + break; + case 203: + r = F("Non-Authoritative Information"); + break; + case 204: + r = F("No Content"); + break; + case 205: + r = F("Reset Content"); + break; + case 206: + r = F("Partial Content"); + break; + case 300: + r = F("Multiple Choices"); + break; + case 301: + r = F("Moved Permanently"); + break; + case 302: + r = F("Found"); + break; + case 303: + r = F("See Other"); + break; + case 304: + r = F("Not Modified"); + break; + case 305: + r = F("Use Proxy"); + break; + case 307: + r = F("Temporary Redirect"); + break; + case 400: + r = F("Bad Request"); + break; + case 401: + r = F("Unauthorized"); + break; + case 402: + r = F("Payment Required"); + break; + case 403: + r = F("Forbidden"); + break; + case 404: + r = F("Not Found"); + break; + case 405: + r = F("Method Not Allowed"); + break; + case 406: + r = F("Not Acceptable"); + break; + case 407: + r = F("Proxy Authentication Required"); + break; + case 408: + r = F("Request Timeout"); + break; + case 409: + r = F("Conflict"); + break; + case 410: + r = F("Gone"); + break; + case 411: + r = F("Length Required"); + break; + case 412: + r = F("Precondition Failed"); + break; + case 413: + r = F("Request Entity Too Large"); + break; + case 414: + r = F("URI Too Long"); + break; + case 415: + r = F("Unsupported Media Type"); + break; + case 416: + r = F("Range not satisfiable"); + break; + case 417: + r = F("Expectation Failed"); + break; + case 500: + r = F("Internal Server Error"); + break; + case 501: + r = F("Not Implemented"); + break; + case 502: + r = F("Bad Gateway"); + break; + case 503: + r = F("Service Unavailable"); + break; + case 504: + r = F("Gateway Timeout"); + break; + case 505: + r = F("HTTP Version not supported"); + break; + default: + r = F(""); + break; + } + return String(r); } diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 9b7c2bbb3..eefcba2ba 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -29,6 +29,7 @@ #include #include #include "detail/mimetable.h" +#include "Uri.h" enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS }; enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END, @@ -91,9 +92,9 @@ public: void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") ); typedef std::function THandlerFunction; - void on(const String &uri, THandlerFunction handler); - void on(const String &uri, HTTPMethod method, THandlerFunction fn); - void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); + void on(const Uri &uri, THandlerFunction handler); + void on(const Uri &uri, HTTPMethod method, THandlerFunction fn); + void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); void addHandler(RequestHandlerType* handler); void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); void onNotFound(THandlerFunction fn); //called when handler is not assigned @@ -107,17 +108,18 @@ public: // Allows setting server options (i.e. SSL keys) by the instantiator ServerType &getServer() { return _server; } - const String& arg(String name) const; // get request argument value by name + const String& pathArg(unsigned int i) const; // get request path argument by number + const String& arg(const String& name) const; // get request argument value by name const String& arg(int i) const; // get request argument value by number const String& argName(int i) const; // get request argument name by number int args() const; // get arguments count bool hasArg(const String& name) const; // check if argument exists void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect - const String& header(String name) const; // get request header value by name + const String& header(const String& name) const; // get request header value by name const String& header(int i) const; // get request header value by number const String& headerName(int i) const; // get request header name by number int headers() const; // get header count - bool hasHeader(String name) const; // check if header exists + bool hasHeader(const String& name) const; // check if header exists const String& hostHeader() const; // get request host header if available or empty String if not // send response to the client @@ -127,6 +129,15 @@ public: void send(int code, const char* content_type = NULL, const String& content = String("")); void send(int code, char* content_type, const String& content); void send(int code, const String& content_type, const String& content); + void send(int code, const char *content_type, const char *content) { + send_P(code, content_type, content); + } + void send(int code, const char *content_type, const char *content, size_t content_length) { + send_P(code, content_type, content, content_length); + } + void send(int code, const char *content_type, const uint8_t *content, size_t content_length) { + send_P(code, content_type, (const char *)content, content_length); + } void send_P(int code, PGM_P content_type, PGM_P content); void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength); @@ -142,13 +153,25 @@ public: static String urlDecode(const String& text); + // Handle a GET request by sending a response header and stream file content to response body template size_t streamFile(T &file, const String& contentType) { - _streamFileCore(file.size(), file.name(), contentType); - return _currentClient.write(file); + return streamFile(file, contentType, HTTP_GET); } - static const String responseCodeToString(const int code); + // Implement GET and HEAD requests for files. + // Stream body on HTTP_GET but not on HTTP_HEAD requests. + template + size_t streamFile(T &file, const String& contentType, HTTPMethod requestMethod) { + size_t contentLength = 0; + _streamFileCore(file.size(), file.name(), contentType); + if (requestMethod == HTTP_GET) { + contentLength = _currentClient.write(file); + } + return contentLength; + } + + static String responseCodeToString(const int code); protected: void _addRequestHandler(RequestHandlerType* handler); diff --git a/libraries/ESP8266WebServer/src/Parsing-impl.h b/libraries/ESP8266WebServer/src/Parsing-impl.h index decc9c8e0..54bcd6c28 100644 --- a/libraries/ESP8266WebServer/src/Parsing-impl.h +++ b/libraries/ESP8266WebServer/src/Parsing-impl.h @@ -89,7 +89,7 @@ bool ESP8266WebServerTemplate::_parseRequest(ClientType& client) { String url = req.substring(addr_start + 1, addr_end); String versionEnd = req.substring(addr_end + 8); _currentVersion = atoi(versionEnd.c_str()); - String searchStr = ""; + String searchStr; int hasSearch = url.indexOf('?'); if (hasSearch != -1){ searchStr = url.substring(hasSearch + 1); @@ -144,7 +144,7 @@ bool ESP8266WebServerTemplate::_parseRequest(ClientType& client) { while(1){ req = client.readStringUntil('\r'); client.readStringUntil('\n'); - if (req == "") break;//no moar headers + if (req.isEmpty()) break;//no moar headers int headerDiv = req.indexOf(':'); if (headerDiv == -1){ break; @@ -222,7 +222,7 @@ bool ESP8266WebServerTemplate::_parseRequest(ClientType& client) { while(1){ req = client.readStringUntil('\r'); client.readStringUntil('\n'); - if (req == "") break;//no moar headers + if (req.isEmpty()) break;//no moar headers int headerDiv = req.indexOf(':'); if (headerDiv == -1){ break; @@ -452,7 +452,7 @@ bool ESP8266WebServerTemplate::_parseForm(ClientType& client, const line = client.readStringUntil('\r'); client.readStringUntil('\n'); if (line.startsWith("--"+boundary)) break; - if (argValue.length() > 0) argValue += "\n"; + if (argValue.length() > 0) argValue += '\n'; argValue += line; } #ifdef DEBUG_ESP_HTTP_SERVER @@ -600,7 +600,7 @@ readfile: template String ESP8266WebServerTemplate::urlDecode(const String& text) { - String decoded = ""; + String decoded; char temp[] = "0x00"; unsigned int len = text.length(); unsigned int i = 0; diff --git a/libraries/ESP8266WebServer/src/Uri.h b/libraries/ESP8266WebServer/src/Uri.h new file mode 100644 index 000000000..95f5c8936 --- /dev/null +++ b/libraries/ESP8266WebServer/src/Uri.h @@ -0,0 +1,27 @@ +#ifndef URI_H +#define URI_H + +#include +#include + +class Uri { + + protected: + const String _uri; + + public: + Uri(const char *uri) : _uri(uri) {} + Uri(const String &uri) : _uri(uri) {} + Uri(const __FlashStringHelper *uri) : _uri(String(uri)) {} + virtual ~Uri() {} + + virtual Uri* clone() const { + return new Uri(_uri); + }; + + virtual bool canHandle(const String &requestUri, __attribute__((unused)) std::vector &pathArgs) { + return _uri == requestUri; + } +}; + +#endif diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandler.h b/libraries/ESP8266WebServer/src/detail/RequestHandler.h index db840af2a..9202f623b 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandler.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandler.h @@ -2,6 +2,8 @@ #define REQUESTHANDLER_H #include +#include +#include template class RequestHandler { @@ -18,6 +20,15 @@ public: private: RequestHandler* _next = nullptr; + +protected: + std::vector pathArgs; + +public: + const String& pathArg(unsigned int i) { + assert(i < pathArgs.size()); + return pathArgs[i]; + } }; #endif //REQUESTHANDLER_H diff --git a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h index 1c930aed7..9388d4ac4 100644 --- a/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h +++ b/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h @@ -5,6 +5,7 @@ #include "RequestHandler.h" #include "mimetable.h" #include "WString.h" +#include "Uri.h" using namespace mime; @@ -12,22 +13,23 @@ template class FunctionRequestHandler : public RequestHandler { using WebServerType = ESP8266WebServerTemplate; public: - FunctionRequestHandler(typename WebServerType::THandlerFunction fn, typename WebServerType::THandlerFunction ufn, const String &uri, HTTPMethod method) + FunctionRequestHandler(typename WebServerType::THandlerFunction fn, typename WebServerType::THandlerFunction ufn, const Uri &uri, HTTPMethod method) : _fn(fn) , _ufn(ufn) - , _uri(uri) + , _uri(uri.clone()) , _method(method) { } + ~FunctionRequestHandler() { + delete _uri; + } + bool canHandle(HTTPMethod requestMethod, String requestUri) override { if (_method != HTTP_ANY && _method != requestMethod) return false; - if (requestUri != _uri) - return false; - - return true; + return _uri->canHandle(requestUri, RequestHandler::pathArgs); } bool canUpload(String requestUri) override { @@ -56,7 +58,7 @@ public: protected: typename WebServerType::THandlerFunction _fn; typename WebServerType::THandlerFunction _ufn; - String _uri; + Uri *_uri; HTTPMethod _method; }; @@ -70,13 +72,21 @@ public: , _path(path) , _cache_header(cache_header) { - _isFile = fs.exists(path); + if (fs.exists(path)) { + File file = fs.open(path, "r"); + _isFile = file && file.isFile(); + file.close(); + } + else { + _isFile = false; + } + DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header); _baseUriLength = _uri.length(); } bool canHandle(HTTPMethod requestMethod, String requestUri) override { - if (requestMethod != HTTP_GET) + if ((requestMethod != HTTP_GET) && (requestMethod != HTTP_HEAD)) return false; if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri)) @@ -96,11 +106,17 @@ public: if (!_isFile) { // Base URI doesn't point to a file. // If a directory is requested, look for index file. - if (requestUri.endsWith("/")) + if (requestUri.endsWith("/")) requestUri += "index.htm"; // Append whatever follows this URI in request to get the file path. path += requestUri.substring(_baseUriLength); + + // If neither nor .gz exist, and is a file.htm, try it with file.html instead + // For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz + if (!_fs.exists(path) && !_fs.exists(path + ".gz") && path.endsWith(".htm")) { + path += "l"; + } } DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile); @@ -118,10 +134,15 @@ public: if (!f) return false; + if (!f.isFile()) { + f.close(); + return false; + } + if (_cache_header.length() != 0) server.sendHeader("Cache-Control", _cache_header); - server.streamFile(f, contentType); + server.streamFile(f, contentType, requestMethod); return true; } diff --git a/libraries/ESP8266WebServer/src/uri/UriBraces.h b/libraries/ESP8266WebServer/src/uri/UriBraces.h new file mode 100644 index 000000000..29652efc7 --- /dev/null +++ b/libraries/ESP8266WebServer/src/uri/UriBraces.h @@ -0,0 +1,54 @@ +#ifndef URI_BRACES_H +#define URI_BRACES_H + +#include "Uri.h" + +class UriBraces : public Uri { + + public: + explicit UriBraces(const char *uri) : Uri(uri) {}; + explicit UriBraces(const String &uri) : Uri(uri) {}; + + Uri* clone() const override final { + return new UriBraces(_uri); + }; + + bool canHandle(const String &requestUri, std::vector &pathArgs) override final { + if (Uri::canHandle(requestUri, pathArgs)) + return true; + + pathArgs.clear(); + + size_t uriLength = _uri.length(); + unsigned int requestUriIndex = 0; + for (unsigned int i = 0; i < uriLength; i++, requestUriIndex++) { + char uriChar = _uri[i]; + char requestUriChar = requestUri[requestUriIndex]; + + if (uriChar == requestUriChar) + continue; + if (uriChar != '{') + return false; + + i += 2; // index of char after '}' + if (i >= uriLength) { + // there is no char after '}' + pathArgs.push_back(requestUri.substring(requestUriIndex)); + return pathArgs.back().indexOf("/") == -1; // path argument may not contain a '/' + } + else + { + char charEnd = _uri[i]; + int uriIndex = requestUri.indexOf(charEnd, requestUriIndex); + if (uriIndex < 0) + return false; + pathArgs.push_back(requestUri.substring(requestUriIndex, uriIndex)); + requestUriIndex = (unsigned int) uriIndex; + } + } + + return requestUriIndex >= requestUri.length(); + } +}; + +#endif diff --git a/libraries/ESP8266WebServer/src/uri/UriGlob.h b/libraries/ESP8266WebServer/src/uri/UriGlob.h new file mode 100644 index 000000000..1e222cbab --- /dev/null +++ b/libraries/ESP8266WebServer/src/uri/UriGlob.h @@ -0,0 +1,22 @@ +#ifndef URI_GLOB_H +#define URI_GLOB_H + +#include "Uri.h" +#include + +class UriGlob : public Uri { + + public: + explicit UriGlob(const char *uri) : Uri(uri) {}; + explicit UriGlob(const String &uri) : Uri(uri) {}; + + Uri* clone() const override final { + return new UriGlob(_uri); + }; + + bool canHandle(const String &requestUri, __attribute__((unused)) std::vector &pathArgs) override final { + return fnmatch(_uri.c_str(), requestUri.c_str(), 0) == 0; + } +}; + +#endif diff --git a/libraries/ESP8266WebServer/src/uri/UriRegex.h b/libraries/ESP8266WebServer/src/uri/UriRegex.h new file mode 100644 index 000000000..eef1b516d --- /dev/null +++ b/libraries/ESP8266WebServer/src/uri/UriRegex.h @@ -0,0 +1,54 @@ +#ifndef URI_REGEX_H +#define URI_REGEX_H + +#include "Uri.h" +#include +#include + +#ifndef REGEX_MAX_GROUPS +#define REGEX_MAX_GROUPS 10 +#endif + +class UriRegex : public Uri { + + private: + regex_t _regexCompiled; + + public: + explicit UriRegex(const char *uri) : Uri(uri) { + assert(regcomp(&_regexCompiled, uri, REG_EXTENDED) == 0); + }; + explicit UriRegex(const String &uri) : UriRegex(uri.c_str()) {}; + + ~UriRegex() { + regfree(&_regexCompiled); + } + + Uri* clone() const override final { + return new UriRegex(_uri); + }; + + bool canHandle(const String &requestUri, std::vector &pathArgs) override final { + if (Uri::canHandle(requestUri, pathArgs)) + return true; + + regmatch_t groupArray[REGEX_MAX_GROUPS]; + if (regexec(&_regexCompiled, requestUri.c_str(), REGEX_MAX_GROUPS, groupArray, 0) == 0) { + // matches + pathArgs.clear(); + + unsigned int g = 1; + for (; g < REGEX_MAX_GROUPS; g++) { + if (groupArray[g].rm_so == (long int)-1) + break; // No more groups + + pathArgs.push_back(requestUri.substring(groupArray[g].rm_so, groupArray[g].rm_eo)); + } + + return true; + } + return false; + } +}; + +#endif diff --git a/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino b/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino index a01ffcb5d..f64c7347d 100644 --- a/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino +++ b/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino @@ -6,6 +6,7 @@ #include #include +#include #include #ifndef STASSID @@ -81,7 +82,8 @@ void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_ } client->stop(); uint32_t freeStackEnd = ESP.getFreeContStack(); - Serial.printf("\nCONT stack used: %d\n-------\n\n", freeStackStart - freeStackEnd); + Serial.printf("\nCONT stack used: %d\n", freeStackStart - freeStackEnd); + Serial.printf("BSSL stack used: %d\n-------\n\n", stack_thunk_get_max_usage()); } void fetchNoConfig() { diff --git a/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino b/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino index 5ba217b23..9102af12d 100644 --- a/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino +++ b/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino @@ -85,8 +85,8 @@ void setup() { Serial.swap(); // Hardware serial is now on RX:GPIO13 TX:GPIO15 // use SoftwareSerial on regular RX(3)/TX(1) for logging - logger = new SoftwareSerial(); - logger->begin(BAUD_LOGGER, 3, 1); + logger = new SoftwareSerial(3, 1); + logger->begin(BAUD_LOGGER); logger->enableIntTx(false); logger->println("\n\nUsing SoftwareSerial for logging"); #else diff --git a/libraries/ESP8266WiFi/src/CertStoreBearSSL.cpp b/libraries/ESP8266WiFi/src/CertStoreBearSSL.cpp index 8affc7e01..905efde2b 100644 --- a/libraries/ESP8266WiFi/src/CertStoreBearSSL.cpp +++ b/libraries/ESP8266WiFi/src/CertStoreBearSSL.cpp @@ -82,6 +82,10 @@ int CertStore::initCertStore(FS &fs, const char *indexFileName, const char *data _fs = &fs; + // In case initCertStore called multiple times, don't leak old filenames + free(_indexName); + free(_dataName); + // No strdup_P, so manually do it _indexName = (char *)malloc(strlen_P(indexFileName) + 1); _dataName = (char *)malloc(strlen_P(dataFileName) + 1); diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index ed49ca9d6..4b2eb54ce 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -1,796 +1,817 @@ -/* - ESP8266WiFiGeneric.cpp - WiFi library for esp8266 - - Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Reworked on 28 Dec 2015 by Markus Sattler - - */ - -#include -#include -#include -#include "ESP8266WiFi.h" -#include "ESP8266WiFiGeneric.h" - -extern "C" { -#include "c_types.h" -#include "ets_sys.h" -#include "os_type.h" -#include "osapi.h" -#include "mem.h" -#include "user_interface.h" - -#include "lwip/opt.h" -#include "lwip/err.h" -#include "lwip/dns.h" -#include "lwip/dhcp.h" -#include "lwip/init.h" // LWIP_VERSION_ -#if LWIP_VERSION_MAJOR == 1 -#include "lwip/sntp.h" -#else -#include "lwip/apps/sntp.h" -#endif -} - -#include "WiFiClient.h" -#include "WiFiUdp.h" -#include "debug.h" -#include "include/WiFiState.h" - -extern "C" void esp_schedule(); -extern "C" void esp_yield(); - - -// ----------------------------------------------------------------------------------------------------------------------- -// ------------------------------------------------- Generic WiFi function ----------------------------------------------- -// ----------------------------------------------------------------------------------------------------------------------- - -struct WiFiEventHandlerOpaque -{ - WiFiEventHandlerOpaque(WiFiEvent_t event, std::function handler) - : mEvent(event), mHandler(handler) - { - } - - void operator()(System_Event_t* e) - { - if (static_cast(e->event) == mEvent || mEvent == WIFI_EVENT_ANY) { - mHandler(e); - } - } - - bool canExpire() - { - return mCanExpire; - } - - WiFiEvent_t mEvent; - std::function mHandler; - bool mCanExpire = true; /* stopgap solution to handle deprecated void onEvent(cb, evt) case */ -}; - -static std::list sCbEventList; - -bool ESP8266WiFiGenericClass::_persistent = true; -WiFiMode_t ESP8266WiFiGenericClass::_forceSleepLastMode = WIFI_OFF; - -ESP8266WiFiGenericClass::ESP8266WiFiGenericClass() -{ - wifi_set_event_handler_cb((wifi_event_handler_cb_t) &ESP8266WiFiGenericClass::_eventCallback); -} - -void ESP8266WiFiGenericClass::onEvent(WiFiEventCb f, WiFiEvent_t event) -{ - WiFiEventHandler handler = std::make_shared(event, [f](System_Event_t* e) { - (*f)(static_cast(e->event)); - }); - handler->mCanExpire = false; - sCbEventList.push_back(handler); -} - -WiFiEventHandler ESP8266WiFiGenericClass::onStationModeConnected(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_CONNECTED, [f](System_Event_t* e) { - auto& src = e->event_info.connected; - WiFiEventStationModeConnected dst; - dst.ssid = String(reinterpret_cast(src.ssid)); - memcpy(dst.bssid, src.bssid, 6); - dst.channel = src.channel; - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onStationModeDisconnected(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_DISCONNECTED, [f](System_Event_t* e){ - auto& src = e->event_info.disconnected; - WiFiEventStationModeDisconnected dst; - dst.ssid = String(reinterpret_cast(src.ssid)); - memcpy(dst.bssid, src.bssid, 6); - dst.reason = static_cast(src.reason); - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onStationModeAuthModeChanged(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_AUTHMODE_CHANGE, [f](System_Event_t* e){ - auto& src = e->event_info.auth_change; - WiFiEventStationModeAuthModeChanged dst; - dst.oldMode = src.old_mode; - dst.newMode = src.new_mode; - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onStationModeGotIP(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_GOT_IP, [f](System_Event_t* e){ - auto& src = e->event_info.got_ip; - WiFiEventStationModeGotIP dst; - dst.ip = src.ip.addr; - dst.mask = src.mask.addr; - dst.gw = src.gw.addr; - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onStationModeDHCPTimeout(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_DHCP_TIMEOUT, [f](System_Event_t* e){ - (void) e; - f(); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeStationConnected(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_STACONNECTED, [f](System_Event_t* e){ - auto& src = e->event_info.sta_connected; - WiFiEventSoftAPModeStationConnected dst; - memcpy(dst.mac, src.mac, 6); - dst.aid = src.aid; - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeStationDisconnected(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_STADISCONNECTED, [f](System_Event_t* e){ - auto& src = e->event_info.sta_disconnected; - WiFiEventSoftAPModeStationDisconnected dst; - memcpy(dst.mac, src.mac, 6); - dst.aid = src.aid; - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeProbeRequestReceived(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED, [f](System_Event_t* e){ - auto& src = e->event_info.ap_probereqrecved; - WiFiEventSoftAPModeProbeRequestReceived dst; - memcpy(dst.mac, src.mac, 6); - dst.rssi = src.rssi; - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function f) -{ - WiFiEventHandler handler = std::make_shared(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){ - WiFiEventModeChange& dst = *reinterpret_cast(&e->event_info); - f(dst); - }); - sCbEventList.push_back(handler); - return handler; -} - -/** - * callback for WiFi events - * @param arg - */ -void ESP8266WiFiGenericClass::_eventCallback(void* arg) -{ - System_Event_t* event = reinterpret_cast(arg); - DEBUG_WIFI("wifi evt: %d\n", event->event); - - if(event->event == EVENT_STAMODE_DISCONNECTED) { - DEBUG_WIFI("STA disconnect: %d\n", event->event_info.disconnected.reason); - WiFiClient::stopAll(); - } - - for(auto it = std::begin(sCbEventList); it != std::end(sCbEventList); ) { - WiFiEventHandler &handler = *it; - if (handler->canExpire() && handler.unique()) { - it = sCbEventList.erase(it); - } - else { - (*handler)(event); - ++it; - } - } -} - -/** - * Return the current channel associated with the network - * @return channel (1-13) - */ -int32_t ESP8266WiFiGenericClass::channel(void) { - return wifi_get_channel(); -} - -/** - * set Sleep mode - * @param type sleep_type_t - * @return bool - */ -bool ESP8266WiFiGenericClass::setSleepMode(WiFiSleepType_t type, uint8_t listenInterval) { - - /** - * datasheet: - * - wifi_set_sleep_level(): - Set sleep level of modem sleep and light sleep - This configuration should be called before calling wifi_set_sleep_type - Modem-sleep and light sleep mode have minimum and maximum sleep levels. - - In minimum sleep level, station wakes up at every DTIM to receive - beacon. Broadcast data will not be lost because it is transmitted after - DTIM. However, it can not save much more power if DTIM period is short, - as specified in AP. - - In maximum sleep level, station wakes up at every listen interval to - receive beacon. Broadcast data may be lost because station may be in sleep - state at DTIM time. If listen interval is longer, more power will be saved, but - it’s very likely to lose more broadcast data. - - Default setting is minimum sleep level. - Further reading: https://routerguide.net/dtim-interval-period-best-setting/ - - wifi_set_listen_interval(): - Set listen interval of maximum sleep level for modem sleep and light sleep - It only works when sleep level is set as MAX_SLEEP_T - forum: https://github.com/espressif/ESP8266_NONOS_SDK/issues/165#issuecomment-416121920 - default value seems to be 3 (as recommended by https://routerguide.net/dtim-interval-period-best-setting/) - - call order: - wifi_set_sleep_level(MAX_SLEEP_T) (SDK3) - wifi_set_listen_interval (SDK3) - wifi_set_sleep_type (all SDKs) - - */ - -#ifdef NONOSDK3V0 - -#ifdef DEBUG_ESP_WIFI - if (listenInterval && type == WIFI_NONE_SLEEP) - DEBUG_WIFI_GENERIC("listenInterval not usable with WIFI_NONE_SLEEP\n"); -#endif - - if (type == WIFI_LIGHT_SLEEP || type == WIFI_MODEM_SLEEP) { - if (listenInterval) { - if (!wifi_set_sleep_level(MAX_SLEEP_T)) { - DEBUG_WIFI_GENERIC("wifi_set_sleep_level(MAX_SLEEP_T): error\n"); - return false; - } - if (listenInterval > 10) { - DEBUG_WIFI_GENERIC("listenInterval must be in [1..10]\n"); -#ifndef DEBUG_ESP_WIFI - // stay within datasheet range when not in debug mode - listenInterval = 10; -#endif - } - if (!wifi_set_listen_interval(listenInterval)) { - DEBUG_WIFI_GENERIC("wifi_set_listen_interval(%d): error\n", listenInterval); - return false; - } - } else { - if (!wifi_set_sleep_level(MIN_SLEEP_T)) { - DEBUG_WIFI_GENERIC("wifi_set_sleep_level(MIN_SLEEP_T): error\n"); - return false; - } - } - } -#else // !defined(NONOSDK3V0) - (void)listenInterval; -#endif // !defined(NONOSDK3V0) - - bool ret = wifi_set_sleep_type((sleep_type_t) type); - if (!ret) { - DEBUG_WIFI_GENERIC("wifi_set_sleep_type(%d): error\n", (int)type); - } - return ret; -} - -/** - * get Sleep mode - * @return sleep_type_t - */ -WiFiSleepType_t ESP8266WiFiGenericClass::getSleepMode() { - return (WiFiSleepType_t) wifi_get_sleep_type(); -} - -/** - * set phy Mode - * @param mode phy_mode_t - * @return bool - */ -bool ESP8266WiFiGenericClass::setPhyMode(WiFiPhyMode_t mode) { - return wifi_set_phy_mode((phy_mode_t) mode); -} - -/** - * get phy Mode - * @return phy_mode_t - */ -WiFiPhyMode_t ESP8266WiFiGenericClass::getPhyMode() { - return (WiFiPhyMode_t) wifi_get_phy_mode(); -} - -/** - * set the output power of WiFi - * @param dBm max: +20.5dBm min: 0dBm - */ -void ESP8266WiFiGenericClass::setOutputPower(float dBm) { - - if(dBm > 20.5) { - dBm = 20.5; - } else if(dBm < 0) { - dBm = 0; - } - - uint8_t val = (dBm*4.0f); - system_phy_set_max_tpw(val); -} - - -/** - * store WiFi config in SDK flash area - * @param persistent - */ -void ESP8266WiFiGenericClass::persistent(bool persistent) { - _persistent = persistent; -} - -/** - * gets the persistent state - * @return bool - */ -bool ESP8266WiFiGenericClass::getPersistent(){ - return _persistent; -} - -/** - * set new mode - * @param m WiFiMode_t - */ -bool ESP8266WiFiGenericClass::mode(WiFiMode_t m, WiFiState* state) { - if (m == WIFI_SHUTDOWN) { - return shutdown(0, state); - } - else if (m == WIFI_RESUME) { - return resumeFromShutdown(state); - } - else if (m & ~(WIFI_STA | WIFI_AP)) - // any other bits than legacy disallowed - return false; - - // m is now WIFI_STA, WIFI_AP or WIFI_AP_STA - if (state) - { - DEBUG_WIFI("core: state is useless without SHUTDOWN or RESUME\n"); - } - - if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { - // wifi may have been put asleep by ESP8266WiFiGenericClass::preinitWiFiOff - wifi_fpm_do_wakeup(); - wifi_fpm_close(); - } - - if(_persistent){ - if(wifi_get_opmode() == (uint8) m && wifi_get_opmode_default() == (uint8) m){ - return true; - } - } else if(wifi_get_opmode() == (uint8) m){ - return true; - } - - bool ret = false; - ETS_UART_INTR_DISABLE(); - if(_persistent) { - ret = wifi_set_opmode(m); - } else { - ret = wifi_set_opmode_current(m); - } - ETS_UART_INTR_ENABLE(); - - return ret; -} - -/** - * get WiFi mode - * @return WiFiMode - */ -WiFiMode_t ESP8266WiFiGenericClass::getMode() { - return (WiFiMode_t) wifi_get_opmode(); -} - -/** - * control STA mode - * @param enable bool - * @return ok - */ -bool ESP8266WiFiGenericClass::enableSTA(bool enable) { - - WiFiMode_t currentMode = getMode(); - bool isEnabled = ((currentMode & WIFI_STA) != 0); - - if (isEnabled == enable) - return true; - - if (enable) - return mode((WiFiMode_t)(currentMode | WIFI_STA)); - - return mode((WiFiMode_t)(currentMode & (~WIFI_STA))); -} - -/** - * control AP mode - * @param enable bool - * @return ok - */ -bool ESP8266WiFiGenericClass::enableAP(bool enable){ - - WiFiMode_t currentMode = getMode(); - bool isEnabled = ((currentMode & WIFI_AP) != 0); - - if(isEnabled != enable) { - if(enable) { - return mode((WiFiMode_t)(currentMode | WIFI_AP)); - } else { - return mode((WiFiMode_t)(currentMode & (~WIFI_AP))); - } - } else { - return true; - } -} - - -/** - * Disable WiFi for x us when value is not 0 - * @param sleep_time_in_us - * @return ok - */ -bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) { - _forceSleepLastMode = getMode(); - if(!mode(WIFI_OFF)) { - DEBUG_WIFI("core: error with mode(WIFI_OFF)\n"); - return false; - } - - if(sleepUs == 0 || sleepUs > 0xFFFFFFF) { - sleepUs = 0xFFFFFFF; - } - - wifi_fpm_set_sleep_type(MODEM_SLEEP_T); - delay(0); - wifi_fpm_open(); - delay(0); - auto ret = wifi_fpm_do_sleep(sleepUs); - if (ret != 0) - { - DEBUG_WIFI("core: error %d with wifi_fpm_do_sleep: (-1=sleep status error, -2=force sleep not enabled)\n", ret); - return false; - } - // fpm_is_open() is always 1 here, with or without delay - // wifi_fpm_set_wakeup_cb(cb): callback is never called - // no power reduction without this delay - delay(10); - return true; -} - -/** - * wake up WiFi Modem - * @return ok - */ -bool ESP8266WiFiGenericClass::forceSleepWake() { - if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { - wifi_fpm_do_wakeup(); - wifi_fpm_close(); - } - - // restore last mode - if(mode(_forceSleepLastMode)) { - if((_forceSleepLastMode & WIFI_STA) != 0){ - wifi_station_connect(); - } - return true; - } - return false; -} - -/** - * Get listen interval of maximum sleep level for modem sleep and light sleep. - * @return interval - */ -uint8_t ESP8266WiFiGenericClass::getListenInterval () { -#ifndef NONOSDK3V0 - return 0; -#else - return wifi_get_listen_interval(); -#endif -} - -/** - * Get sleep level of modem sleep and light sleep - * @return true if max level - */ -bool ESP8266WiFiGenericClass::isSleepLevelMax () { -#ifndef NONOSDK3V0 - return false; -#else - return wifi_get_sleep_level() == MAX_SLEEP_T; -#endif -} - - -// ----------------------------------------------------------------------------------------------------------------------- -// ------------------------------------------------ Generic Network function --------------------------------------------- -// ----------------------------------------------------------------------------------------------------------------------- - -void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *callback_arg); - -static bool _dns_lookup_pending = false; - -/** - * Resolve the given hostname to an IP address. - * @param aHostname Name to be resolved - * @param aResult IPAddress structure to store the returned IP address - * @return 1 if aIPAddrString was successfully converted to an IP address, - * else 0 - */ -int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult) -{ - return hostByName(aHostname, aResult, 10000); -} - - -int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms) -{ - ip_addr_t addr; - aResult = static_cast(0); - - if(aResult.fromString(aHostname)) { - // Host name is a IP address use it! - DEBUG_WIFI_GENERIC("[hostByName] Host: %s is a IP!\n", aHostname); - return 1; - } - - DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname); - err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult); - if(err == ERR_OK) { - aResult = IPAddress(&addr); - } else if(err == ERR_INPROGRESS) { - _dns_lookup_pending = true; - delay(timeout_ms); - _dns_lookup_pending = false; - // will return here when dns_found_callback fires - if(aResult.isSet()) { - err = ERR_OK; - } - } - - if(err != 0) { - DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err); - } else { - DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str()); - } - - return (err == ERR_OK) ? 1 : 0; -} - -/** - * DNS callback - * @param name - * @param ipaddr - * @param callback_arg - */ -void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *callback_arg) -{ - (void) name; - if (!_dns_lookup_pending) { - return; - } - if(ipaddr) { - (*reinterpret_cast(callback_arg)) = IPAddress(ipaddr); - } - esp_schedule(); // resume the hostByName function -} - -uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState* state) -{ - return state? crc32(&state->state, sizeof(state->state)): 0; -} - -bool ESP8266WiFiGenericClass::shutdownValidCRC (const WiFiState* state) -{ - return state && (crc32(&state->state, sizeof(state->state)) == state->crc); -} - -bool ESP8266WiFiGenericClass::shutdown (uint32 sleepUs, WiFiState* state) -{ - bool persistent = _persistent; - WiFiMode_t before_off_mode = getMode(); - - if ((before_off_mode & WIFI_STA) && state) - { - bool ret = wifi_get_ip_info(STATION_IF, &state->state.ip); - if (!ret) - { - DEBUG_WIFI("core: error with wifi_get_ip_info(STATION_IF)\n"); - return false; - } - memset(state->state.fwconfig.bssid, 0xff, 6); - ret = wifi_station_get_config(&state->state.fwconfig); - if (!ret) - { - DEBUG_WIFI("core: error with wifi_station_get_config\n"); - return false; - } - state->state.channel = wifi_get_channel(); - } - - // disable persistence in FW so in case of power failure - // it doesn't wake up in off mode. - // persistence state will be restored on WiFi resume. - WiFi.persistent(false); - if (!WiFi.forceSleepBegin(sleepUs)) - { - // WIFI_OFF mode set by forceSleepBegin() - DEBUG_WIFI("core: error with forceSleepBegin()\n"); - WiFi.mode(before_off_mode); - WiFi.persistent(persistent); - return false; - } - - // WiFi is now in force-sleep mode - - if (state) - { - // finish filling state and process crc - - state->state.persistent = persistent; - state->state.mode = before_off_mode; - uint8_t i = 0; - for (auto& ntp: state->state.ntp) - { -#if LWIP_VERSION_MAJOR == 1 - ntp = sntp_getserver(i++); -#else - ntp = *sntp_getserver(i++); -#endif - } - i = 0; - for (auto& dns: state->state.dns) - dns = WiFi.dnsIP(i++); - state->crc = shutdownCRC(state); - DEBUG_WIFI("core: state is saved\n"); - } - return true; -} - -bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state) -{ - if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { - wifi_fpm_do_wakeup(); - wifi_fpm_close(); - } - - if (!state || shutdownCRC(state) != state->crc) - { - DEBUG_WIFI("core: resume: no state or bad crc\n"); - return false; - } - - persistent(state->state.persistent); - - if (!mode(state->state.mode)) - { - DEBUG_WIFI("core: resume: can't set wifi mode to %d\n", state->state.mode); - return false; - } - - if (state->state.mode & WIFI_STA) - { - IPAddress local(state->state.ip.ip); - if (local) - { - DEBUG_WIFI("core: resume: static address '%s'\n", local.toString().c_str()); - WiFi.config(state->state.ip.ip, state->state.ip.gw, state->state.ip.netmask, state->state.dns[0], state->state.dns[1]); - uint8_t i = 0; - for (CONST auto& ntp: state->state.ntp) - { - IPAddress ip(ntp); - if (ip.isSet()) - { - DEBUG_WIFI("core: resume: start SNTP, server='%s'\n", ip.toString().c_str()); - sntp_setserver(i++, &ntp); - } - } - } - // state->state.fwconfig.bssid is not real bssid (it's what user may have provided when bssid_set==1) - if (WiFi.begin((const char*)state->state.fwconfig.ssid, - (const char*)state->state.fwconfig.password, - state->state.channel, - nullptr/*(const uint8_t*)state->state.fwconfig.bssid*/, // <- try with gw's mac address? - true) == WL_CONNECT_FAILED) - { - DEBUG_WIFI("core: resume: WiFi.begin failed\n"); - return false; - } - } - - if (state->state.mode & WIFI_AP) - { - DEBUG_WIFI("core: resume AP mode TODO\n"); - return false; - } - - // success, invalidate saved state - state->crc++; - - return true; -} - -//meant to be called from user-defined ::preinit() -void ESP8266WiFiGenericClass::preinitWiFiOff () { - // https://github.com/esp8266/Arduino/issues/2111#issuecomment-224251391 - // WiFi.persistent(false); - // WiFi.mode(WIFI_OFF); - // WiFi.forceSleepBegin(); - - //WiFi.mode(WIFI_OFF) equivalent: - // datasheet: - // Set Wi-Fi working mode to Station mode, SoftAP - // or Station + SoftAP, and do not update flash - // (not persistent) - wifi_set_opmode_current(WIFI_OFF); - - //WiFi.forceSleepBegin(/*default*/0) equivalent: - // sleep forever until wifi_fpm_do_wakeup() is called - wifi_fpm_set_sleep_type(MODEM_SLEEP_T); - wifi_fpm_open(); - wifi_fpm_do_sleep(0xFFFFFFF); - - // use WiFi.forceSleepWake() to wake WiFi up -} +/* + ESP8266WiFiGeneric.cpp - WiFi library for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Reworked on 28 Dec 2015 by Markus Sattler + + */ + +#include +#include +#include +#include +#include "ESP8266WiFi.h" +#include "ESP8266WiFiGeneric.h" + +extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "lwip/dhcp.h" +#include "lwip/init.h" // LWIP_VERSION_ +#if LWIP_VERSION_MAJOR == 1 +#include "lwip/sntp.h" +#else +#include "lwip/apps/sntp.h" +#endif +} + +#include "WiFiClient.h" +#include "WiFiUdp.h" +#include "debug.h" +#include "include/WiFiState.h" + +extern "C" void esp_schedule(); +extern "C" void esp_yield(); + + +// ----------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------- Generic WiFi function ----------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + +struct WiFiEventHandlerOpaque +{ + WiFiEventHandlerOpaque(WiFiEvent_t event, std::function handler) + : mEvent(event), mHandler(handler) + { + } + + void operator()(System_Event_t* e) + { + if (static_cast(e->event) == mEvent || mEvent == WIFI_EVENT_ANY) { + mHandler(e); + } + } + + bool canExpire() + { + return mCanExpire; + } + + WiFiEvent_t mEvent; + std::function mHandler; + bool mCanExpire = true; /* stopgap solution to handle deprecated void onEvent(cb, evt) case */ +}; + +static std::list sCbEventList; + +bool ESP8266WiFiGenericClass::_persistent = true; +WiFiMode_t ESP8266WiFiGenericClass::_forceSleepLastMode = WIFI_OFF; + +ESP8266WiFiGenericClass::ESP8266WiFiGenericClass() +{ + wifi_set_event_handler_cb((wifi_event_handler_cb_t) &ESP8266WiFiGenericClass::_eventCallback); +} + +void ESP8266WiFiGenericClass::onEvent(WiFiEventCb f, WiFiEvent_t event) +{ + WiFiEventHandler handler = std::make_shared(event, [f](System_Event_t* e) { + (*f)(static_cast(e->event)); + }); + handler->mCanExpire = false; + sCbEventList.push_back(handler); +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeConnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_CONNECTED, [f](System_Event_t* e) { + auto& src = e->event_info.connected; + WiFiEventStationModeConnected dst; + dst.ssid = String(reinterpret_cast(src.ssid)); + memcpy(dst.bssid, src.bssid, 6); + dst.channel = src.channel; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeDisconnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_DISCONNECTED, [f](System_Event_t* e){ + auto& src = e->event_info.disconnected; + WiFiEventStationModeDisconnected dst; + dst.ssid = String(reinterpret_cast(src.ssid)); + memcpy(dst.bssid, src.bssid, 6); + dst.reason = static_cast(src.reason); + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeAuthModeChanged(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_AUTHMODE_CHANGE, [f](System_Event_t* e){ + auto& src = e->event_info.auth_change; + WiFiEventStationModeAuthModeChanged dst; + dst.oldMode = src.old_mode; + dst.newMode = src.new_mode; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeGotIP(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_GOT_IP, [f](System_Event_t* e){ + auto& src = e->event_info.got_ip; + WiFiEventStationModeGotIP dst; + dst.ip = src.ip.addr; + dst.mask = src.mask.addr; + dst.gw = src.gw.addr; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeDHCPTimeout(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_DHCP_TIMEOUT, [f](System_Event_t* e){ + (void) e; + f(); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeStationConnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_STACONNECTED, [f](System_Event_t* e){ + auto& src = e->event_info.sta_connected; + WiFiEventSoftAPModeStationConnected dst; + memcpy(dst.mac, src.mac, 6); + dst.aid = src.aid; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeStationDisconnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_STADISCONNECTED, [f](System_Event_t* e){ + auto& src = e->event_info.sta_disconnected; + WiFiEventSoftAPModeStationDisconnected dst; + memcpy(dst.mac, src.mac, 6); + dst.aid = src.aid; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeProbeRequestReceived(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED, [f](System_Event_t* e){ + auto& src = e->event_info.ap_probereqrecved; + WiFiEventSoftAPModeProbeRequestReceived dst; + memcpy(dst.mac, src.mac, 6); + dst.rssi = src.rssi; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){ + WiFiEventModeChange& dst = *reinterpret_cast(&e->event_info); + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +/** + * callback for WiFi events + * @param arg + */ +void ESP8266WiFiGenericClass::_eventCallback(void* arg) +{ + System_Event_t* event = reinterpret_cast(arg); + DEBUG_WIFI("wifi evt: %d\n", event->event); + + if(event->event == EVENT_STAMODE_DISCONNECTED) { + DEBUG_WIFI("STA disconnect: %d\n", event->event_info.disconnected.reason); + WiFiClient::stopAll(); + } + + for(auto it = std::begin(sCbEventList); it != std::end(sCbEventList); ) { + WiFiEventHandler &handler = *it; + if (handler->canExpire() && handler.unique()) { + it = sCbEventList.erase(it); + } + else { + (*handler)(event); + ++it; + } + } +} + +/** + * Return the current channel associated with the network + * @return channel (1-13) + */ +int32_t ESP8266WiFiGenericClass::channel(void) { + return wifi_get_channel(); +} + +/** + * set Sleep mode + * @param type sleep_type_t + * @return bool + */ +bool ESP8266WiFiGenericClass::setSleepMode(WiFiSleepType_t type, uint8_t listenInterval) { + + /** + * datasheet: + * + wifi_set_sleep_level(): + Set sleep level of modem sleep and light sleep + This configuration should be called before calling wifi_set_sleep_type + Modem-sleep and light sleep mode have minimum and maximum sleep levels. + - In minimum sleep level, station wakes up at every DTIM to receive + beacon. Broadcast data will not be lost because it is transmitted after + DTIM. However, it can not save much more power if DTIM period is short, + as specified in AP. + - In maximum sleep level, station wakes up at every listen interval to + receive beacon. Broadcast data may be lost because station may be in sleep + state at DTIM time. If listen interval is longer, more power will be saved, but + it’s very likely to lose more broadcast data. + - Default setting is minimum sleep level. + Further reading: https://routerguide.net/dtim-interval-period-best-setting/ + + wifi_set_listen_interval(): + Set listen interval of maximum sleep level for modem sleep and light sleep + It only works when sleep level is set as MAX_SLEEP_T + forum: https://github.com/espressif/ESP8266_NONOS_SDK/issues/165#issuecomment-416121920 + default value seems to be 3 (as recommended by https://routerguide.net/dtim-interval-period-best-setting/) + + call order: + wifi_set_sleep_level(MAX_SLEEP_T) (SDK3) + wifi_set_listen_interval (SDK3) + wifi_set_sleep_type (all SDKs) + + */ + +#ifdef NONOSDK3V0 + +#ifdef DEBUG_ESP_WIFI + if (listenInterval && type == WIFI_NONE_SLEEP) + DEBUG_WIFI_GENERIC("listenInterval not usable with WIFI_NONE_SLEEP\n"); +#endif + + if (type == WIFI_LIGHT_SLEEP || type == WIFI_MODEM_SLEEP) { + if (listenInterval) { + if (!wifi_set_sleep_level(MAX_SLEEP_T)) { + DEBUG_WIFI_GENERIC("wifi_set_sleep_level(MAX_SLEEP_T): error\n"); + return false; + } + if (listenInterval > 10) { + DEBUG_WIFI_GENERIC("listenInterval must be in [1..10]\n"); +#ifndef DEBUG_ESP_WIFI + // stay within datasheet range when not in debug mode + listenInterval = 10; +#endif + } + if (!wifi_set_listen_interval(listenInterval)) { + DEBUG_WIFI_GENERIC("wifi_set_listen_interval(%d): error\n", listenInterval); + return false; + } + } else { + if (!wifi_set_sleep_level(MIN_SLEEP_T)) { + DEBUG_WIFI_GENERIC("wifi_set_sleep_level(MIN_SLEEP_T): error\n"); + return false; + } + } + } +#else // !defined(NONOSDK3V0) + (void)listenInterval; +#endif // !defined(NONOSDK3V0) + + bool ret = wifi_set_sleep_type((sleep_type_t) type); + if (!ret) { + DEBUG_WIFI_GENERIC("wifi_set_sleep_type(%d): error\n", (int)type); + } + return ret; +} + +/** + * get Sleep mode + * @return sleep_type_t + */ +WiFiSleepType_t ESP8266WiFiGenericClass::getSleepMode() { + return (WiFiSleepType_t) wifi_get_sleep_type(); +} + +/** + * set phy Mode + * @param mode phy_mode_t + * @return bool + */ +bool ESP8266WiFiGenericClass::setPhyMode(WiFiPhyMode_t mode) { + return wifi_set_phy_mode((phy_mode_t) mode); +} + +/** + * get phy Mode + * @return phy_mode_t + */ +WiFiPhyMode_t ESP8266WiFiGenericClass::getPhyMode() { + return (WiFiPhyMode_t) wifi_get_phy_mode(); +} + +/** + * set the output power of WiFi + * @param dBm max: +20.5dBm min: 0dBm + */ +void ESP8266WiFiGenericClass::setOutputPower(float dBm) { + + if(dBm > 20.5) { + dBm = 20.5; + } else if(dBm < 0) { + dBm = 0; + } + + uint8_t val = (dBm*4.0f); + system_phy_set_max_tpw(val); +} + + +/** + * store WiFi config in SDK flash area + * @param persistent + */ +void ESP8266WiFiGenericClass::persistent(bool persistent) { + _persistent = persistent; +} + +/** + * gets the persistent state + * @return bool + */ +bool ESP8266WiFiGenericClass::getPersistent(){ + return _persistent; +} + +/** + * set new mode + * @param m WiFiMode_t + */ +bool ESP8266WiFiGenericClass::mode(WiFiMode_t m, WiFiState* state) { + if (m == WIFI_SHUTDOWN) { + return shutdown(0, state); + } + else if (m == WIFI_RESUME) { + return resumeFromShutdown(state); + } + else if (m & ~(WIFI_STA | WIFI_AP)) + // any other bits than legacy disallowed + return false; + + // m is now WIFI_STA, WIFI_AP or WIFI_AP_STA + if (state) + { + DEBUG_WIFI("core: state is useless without SHUTDOWN or RESUME\n"); + } + + if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { + // wifi may have been put asleep by ESP8266WiFiGenericClass::preinitWiFiOff + wifi_fpm_do_wakeup(); + wifi_fpm_close(); + } + + if(_persistent){ + if(wifi_get_opmode() == (uint8) m && wifi_get_opmode_default() == (uint8) m){ + return true; + } + } else if(wifi_get_opmode() == (uint8) m){ + return true; + } + + bool ret = false; + ETS_UART_INTR_DISABLE(); + if(_persistent) { + ret = wifi_set_opmode(m); + } else { + ret = wifi_set_opmode_current(m); + } + ETS_UART_INTR_ENABLE(); + + if(!ret) + return false; //calling wifi_set_opmode failed + + //Wait for mode change, which is asynchronous. + //Only wait if in CONT context. If this were called from SYS, it's up to the user to serialize + //tasks to wait correctly. + constexpr unsigned int timeoutValue = 1000; //1 second + if(can_yield()) { + using oneShot = esp8266::polledTimeout::oneShotFastMs; + oneShot timeout(timeoutValue); + while(wifi_get_opmode() != (uint8) m && !timeout) + delay(5); + + //if at this point mode still hasn't been reached, give up + if(wifi_get_opmode() != (uint8) m) { + return false; //timeout + } + } + + return ret; +} + +/** + * get WiFi mode + * @return WiFiMode + */ +WiFiMode_t ESP8266WiFiGenericClass::getMode() { + return (WiFiMode_t) wifi_get_opmode(); +} + +/** + * control STA mode + * @param enable bool + * @return ok + */ +bool ESP8266WiFiGenericClass::enableSTA(bool enable) { + + WiFiMode_t currentMode = getMode(); + bool isEnabled = ((currentMode & WIFI_STA) != 0); + + if (isEnabled == enable) + return true; + + if (enable) + return mode((WiFiMode_t)(currentMode | WIFI_STA)); + + return mode((WiFiMode_t)(currentMode & (~WIFI_STA))); +} + +/** + * control AP mode + * @param enable bool + * @return ok + */ +bool ESP8266WiFiGenericClass::enableAP(bool enable){ + + WiFiMode_t currentMode = getMode(); + bool isEnabled = ((currentMode & WIFI_AP) != 0); + + if(isEnabled != enable) { + if(enable) { + return mode((WiFiMode_t)(currentMode | WIFI_AP)); + } else { + return mode((WiFiMode_t)(currentMode & (~WIFI_AP))); + } + } else { + return true; + } +} + + +/** + * Disable WiFi for x us when value is not 0 + * @param sleep_time_in_us + * @return ok + */ +bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) { + _forceSleepLastMode = getMode(); + if(!mode(WIFI_OFF)) { + DEBUG_WIFI("core: error with mode(WIFI_OFF)\n"); + return false; + } + + if(sleepUs == 0 || sleepUs > 0xFFFFFFF) { + sleepUs = 0xFFFFFFF; + } + + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + delay(0); + wifi_fpm_open(); + delay(0); + auto ret = wifi_fpm_do_sleep(sleepUs); + if (ret != 0) + { + DEBUG_WIFI("core: error %d with wifi_fpm_do_sleep: (-1=sleep status error, -2=force sleep not enabled)\n", ret); + return false; + } + // fpm_is_open() is always 1 here, with or without delay + // wifi_fpm_set_wakeup_cb(cb): callback is never called + // no power reduction without this delay + delay(10); + return true; +} + +/** + * wake up WiFi Modem + * @return ok + */ +bool ESP8266WiFiGenericClass::forceSleepWake() { + if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { + wifi_fpm_do_wakeup(); + wifi_fpm_close(); + } + + // restore last mode + if(mode(_forceSleepLastMode)) { + if((_forceSleepLastMode & WIFI_STA) != 0){ + wifi_station_connect(); + } + return true; + } + return false; +} + +/** + * Get listen interval of maximum sleep level for modem sleep and light sleep. + * @return interval + */ +uint8_t ESP8266WiFiGenericClass::getListenInterval () { +#ifndef NONOSDK3V0 + return 0; +#else + return wifi_get_listen_interval(); +#endif +} + +/** + * Get sleep level of modem sleep and light sleep + * @return true if max level + */ +bool ESP8266WiFiGenericClass::isSleepLevelMax () { +#ifndef NONOSDK3V0 + return false; +#else + return wifi_get_sleep_level() == MAX_SLEEP_T; +#endif +} + + +// ----------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------ Generic Network function --------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + +void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *callback_arg); + +static bool _dns_lookup_pending = false; + +/** + * Resolve the given hostname to an IP address. + * @param aHostname Name to be resolved + * @param aResult IPAddress structure to store the returned IP address + * @return 1 if aIPAddrString was successfully converted to an IP address, + * else 0 + */ +int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + return hostByName(aHostname, aResult, 10000); +} + + +int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms) +{ + ip_addr_t addr; + aResult = static_cast(0); + + if(aResult.fromString(aHostname)) { + // Host name is a IP address use it! + DEBUG_WIFI_GENERIC("[hostByName] Host: %s is a IP!\n", aHostname); + return 1; + } + + DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname); + err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult); + if(err == ERR_OK) { + aResult = IPAddress(&addr); + } else if(err == ERR_INPROGRESS) { + _dns_lookup_pending = true; + delay(timeout_ms); + // will resume on timeout or when wifi_dns_found_callback fires + _dns_lookup_pending = false; + // will return here when dns_found_callback fires + if(aResult.isSet()) { + err = ERR_OK; + } + } + + if(err != 0) { + DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err); + } else { + DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str()); + } + + return (err == ERR_OK) ? 1 : 0; +} + +/** + * DNS callback + * @param name + * @param ipaddr + * @param callback_arg + */ +void wifi_dns_found_callback(const char *name, CONST ip_addr_t *ipaddr, void *callback_arg) +{ + (void) name; + if (!_dns_lookup_pending) { + return; + } + if(ipaddr) { + (*reinterpret_cast(callback_arg)) = IPAddress(ipaddr); + } + esp_schedule(); // break delay in hostByName +} + +uint32_t ESP8266WiFiGenericClass::shutdownCRC (const WiFiState* state) +{ + return state? crc32(&state->state, sizeof(state->state)): 0; +} + +bool ESP8266WiFiGenericClass::shutdownValidCRC (const WiFiState* state) +{ + return state && (crc32(&state->state, sizeof(state->state)) == state->crc); +} + +bool ESP8266WiFiGenericClass::shutdown (uint32 sleepUs, WiFiState* state) +{ + bool persistent = _persistent; + WiFiMode_t before_off_mode = getMode(); + + if ((before_off_mode & WIFI_STA) && state) + { + bool ret = wifi_get_ip_info(STATION_IF, &state->state.ip); + if (!ret) + { + DEBUG_WIFI("core: error with wifi_get_ip_info(STATION_IF)\n"); + return false; + } + memset(state->state.fwconfig.bssid, 0xff, 6); + ret = wifi_station_get_config(&state->state.fwconfig); + if (!ret) + { + DEBUG_WIFI("core: error with wifi_station_get_config\n"); + return false; + } + state->state.channel = wifi_get_channel(); + } + + // disable persistence in FW so in case of power failure + // it doesn't wake up in off mode. + // persistence state will be restored on WiFi resume. + WiFi.persistent(false); + if (!WiFi.forceSleepBegin(sleepUs)) + { + // WIFI_OFF mode set by forceSleepBegin() + DEBUG_WIFI("core: error with forceSleepBegin()\n"); + WiFi.mode(before_off_mode); + WiFi.persistent(persistent); + return false; + } + + // WiFi is now in force-sleep mode + + if (state) + { + // finish filling state and process crc + + state->state.persistent = persistent; + state->state.mode = before_off_mode; + uint8_t i = 0; + for (auto& ntp: state->state.ntp) + { +#if LWIP_VERSION_MAJOR == 1 + ntp = sntp_getserver(i++); +#else + ntp = *sntp_getserver(i++); +#endif + } + i = 0; + for (auto& dns: state->state.dns) + dns = WiFi.dnsIP(i++); + state->crc = shutdownCRC(state); + DEBUG_WIFI("core: state is saved\n"); + } + return true; +} + +bool ESP8266WiFiGenericClass::resumeFromShutdown (WiFiState* state) +{ + if (wifi_fpm_get_sleep_type() != NONE_SLEEP_T) { + wifi_fpm_do_wakeup(); + wifi_fpm_close(); + } + + if (!state || shutdownCRC(state) != state->crc) + { + DEBUG_WIFI("core: resume: no state or bad crc\n"); + return false; + } + + persistent(state->state.persistent); + + if (!mode(state->state.mode)) + { + DEBUG_WIFI("core: resume: can't set wifi mode to %d\n", state->state.mode); + return false; + } + + if (state->state.mode & WIFI_STA) + { + IPAddress local(state->state.ip.ip); + if (local) + { + DEBUG_WIFI("core: resume: static address '%s'\n", local.toString().c_str()); + WiFi.config(state->state.ip.ip, state->state.ip.gw, state->state.ip.netmask, state->state.dns[0], state->state.dns[1]); + uint8_t i = 0; + for (CONST auto& ntp: state->state.ntp) + { + IPAddress ip(ntp); + if (ip.isSet()) + { + DEBUG_WIFI("core: resume: start SNTP, server='%s'\n", ip.toString().c_str()); + sntp_setserver(i++, &ntp); + } + } + } + // state->state.fwconfig.bssid is not real bssid (it's what user may have provided when bssid_set==1) + if (WiFi.begin((const char*)state->state.fwconfig.ssid, + (const char*)state->state.fwconfig.password, + state->state.channel, + nullptr/*(const uint8_t*)state->state.fwconfig.bssid*/, // <- try with gw's mac address? + true) == WL_CONNECT_FAILED) + { + DEBUG_WIFI("core: resume: WiFi.begin failed\n"); + return false; + } + } + + if (state->state.mode & WIFI_AP) + { + DEBUG_WIFI("core: resume AP mode TODO\n"); + return false; + } + + // success, invalidate saved state + state->crc++; + + return true; +} + +//meant to be called from user-defined ::preinit() +void ESP8266WiFiGenericClass::preinitWiFiOff () { + // https://github.com/esp8266/Arduino/issues/2111#issuecomment-224251391 + // WiFi.persistent(false); + // WiFi.mode(WIFI_OFF); + // WiFi.forceSleepBegin(); + + //WiFi.mode(WIFI_OFF) equivalent: + // datasheet: + // Set Wi-Fi working mode to Station mode, SoftAP + // or Station + SoftAP, and do not update flash + // (not persistent) + wifi_set_opmode_current(WIFI_OFF); + + //WiFi.forceSleepBegin(/*default*/0) equivalent: + // sleep forever until wifi_fpm_do_wakeup() is called + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); + + // use WiFi.forceSleepWake() to wake WiFi up +} diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp index 3a88c7e69..531e76239 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -38,6 +38,10 @@ bool ESP8266WiFiMulti::addAP(const char* ssid, const char *passphrase) { return APlistAdd(ssid, passphrase); } +void ESP8266WiFiMulti::cleanAPlist(void) { + APlistClean(); +} + bool ESP8266WiFiMulti::existsAP(const char* ssid, const char *passphrase) { return APlistExists(ssid, passphrase); } diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h index 9417e2ba4..de8703618 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h @@ -57,6 +57,8 @@ class ESP8266WiFiMulti { wl_status_t run(void); + void cleanAPlist(void); + private: WifiAPlist APlist; bool APlistAdd(const char* ssid, const char *passphrase = NULL); diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp index c7a92765b..99d27ba7a 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiSTA-WPS.cpp @@ -71,7 +71,7 @@ bool ESP8266WiFiSTAClass::beginWPSConfig(void) { } esp_yield(); - // will return here when wifi_wps_status_cb fires + // will resume when wifi_wps_status_cb fires return true; } @@ -107,5 +107,5 @@ void wifi_wps_status_cb(wps_cb_status status) { } // TODO user function to get status - esp_schedule(); // resume the beginWPSConfig function + esp_schedule(); // resume beginWPSConfig } diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp index 146469243..65878a3d5 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp @@ -98,7 +98,7 @@ int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 ch return WIFI_SCAN_RUNNING; } - esp_yield(); + esp_yield(); // will resume when _scanDone fires return ESP8266WiFiScanClass::_scanCount; } else { return WIFI_SCAN_FAILED; @@ -323,7 +323,7 @@ void ESP8266WiFiScanClass::_scanDone(void* result, int status) { ESP8266WiFiScanClass::_scanComplete = true; if(!ESP8266WiFiScanClass::_scanAsync) { - esp_schedule(); + esp_schedule(); // resume scanNetworks } else if (ESP8266WiFiScanClass::_onComplete) { ESP8266WiFiScanClass::_onComplete(ESP8266WiFiScanClass::_scanCount); ESP8266WiFiScanClass::_onComplete = nullptr; diff --git a/libraries/ESP8266WiFi/src/WiFiClient.cpp b/libraries/ESP8266WiFi/src/WiFiClient.cpp index 2d7b5ac46..059c6c663 100644 --- a/libraries/ESP8266WiFi/src/WiFiClient.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClient.cpp @@ -346,7 +346,7 @@ uint8_t WiFiClient::status() WiFiClient::operator bool() { - return connected(); + return available() || connected(); } IPAddress WiFiClient::remoteIP() diff --git a/libraries/ESP8266WiFi/src/WiFiServer.cpp b/libraries/ESP8266WiFi/src/WiFiServer.cpp index d9d47657d..0b0de5d42 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.cpp +++ b/libraries/ESP8266WiFi/src/WiFiServer.cpp @@ -35,12 +35,17 @@ extern "C" { #include "lwip/opt.h" #include "lwip/tcp.h" #include "lwip/inet.h" +#include "lwip/init.h" // LWIP_VERSION_ #include +#ifndef MAX_PENDING_CLIENTS_PER_PORT +#define MAX_PENDING_CLIENTS_PER_PORT 5 +#endif + WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port) : _port(port) , _addr(addr) -, _pcb(nullptr) +, _listen_pcb(nullptr) , _unclaimed(nullptr) , _discarded(nullptr) { @@ -49,7 +54,7 @@ WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port) WiFiServer::WiFiServer(uint16_t port) : _port(port) , _addr(IP_ANY_TYPE) -, _pcb(nullptr) +, _listen_pcb(nullptr) , _unclaimed(nullptr) , _discarded(nullptr) { @@ -60,9 +65,14 @@ void WiFiServer::begin() { } void WiFiServer::begin(uint16_t port) { + return begin(port, MAX_PENDING_CLIENTS_PER_PORT); +} + +void WiFiServer::begin(uint16_t port, uint8_t backlog) { close(); + if (!backlog) + return; _port = port; - err_t err; tcp_pcb* pcb = tcp_new(); if (!pcb) return; @@ -70,19 +80,23 @@ void WiFiServer::begin(uint16_t port) { pcb->so_options |= SOF_REUSEADDR; // (IPAddress _addr) operator-converted to (const ip_addr_t*) - err = tcp_bind(pcb, _addr, _port); - - if (err != ERR_OK) { + if (tcp_bind(pcb, _addr, _port) != ERR_OK) { tcp_close(pcb); return; } +#if LWIP_VERSION_MAJOR == 1 tcp_pcb* listen_pcb = tcp_listen(pcb); +#else + tcp_pcb* listen_pcb = tcp_listen_with_backlog(pcb, backlog); +#endif + if (!listen_pcb) { tcp_close(pcb); return; } - _pcb = listen_pcb; + _listen_pcb = listen_pcb; + _port = _listen_pcb->local_port; tcp_accept(listen_pcb, &WiFiServer::_s_accept); tcp_arg(listen_pcb, (void*) this); } @@ -110,9 +124,15 @@ WiFiClient WiFiServer::available(byte* status) { (void) status; if (_unclaimed) { WiFiClient result(_unclaimed); +#if LWIP_VERSION_MAJOR != 1 + // pcb can be null when peer has already closed the connection + if (_unclaimed->getPCB()) + // give permission to lwIP to accept one more peer + tcp_backlog_accepted(_unclaimed->getPCB()); +#endif _unclaimed = _unclaimed->next(); result.setNoDelay(getNoDelay()); - DEBUGV("WS:av\r\n"); + DEBUGV("WS:av status=%d WCav=%d\r\n", result.status(), result.available()); return result; } @@ -121,17 +141,21 @@ WiFiClient WiFiServer::available(byte* status) { } uint8_t WiFiServer::status() { - if (!_pcb) + if (!_listen_pcb) return CLOSED; - return _pcb->state; + return _listen_pcb->state; +} + +uint16_t WiFiServer::port() const { + return _port; } void WiFiServer::close() { - if (!_pcb) { + if (!_listen_pcb) { return; } - tcp_close(_pcb); - _pcb = nullptr; + tcp_close(_listen_pcb); + _listen_pcb = nullptr; } void WiFiServer::stop() { @@ -164,9 +188,28 @@ T* slist_append_tail(T* head, T* item) { long WiFiServer::_accept(tcp_pcb* apcb, long err) { (void) err; DEBUGV("WS:ac\r\n"); + + // always accept new PCB so incoming data can be stored in our buffers even before + // user calls ::available() ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this); + +#if LWIP_VERSION_MAJOR == 1 + + tcp_accepted(_listen_pcb); + +#else + + // backlog doc: + // http://lwip.100.n7.nabble.com/Problem-re-opening-listening-pbc-tt32484.html#a32494 + // https://www.nongnu.org/lwip/2_1_x/group__tcp__raw.html#gaeff14f321d1eecd0431611f382fcd338 + + // increase lwIP's backlog + tcp_backlog_delayed(apcb); + +#endif + _unclaimed = slist_append_tail(_unclaimed, client); - tcp_accepted(_pcb); + return ERR_OK; } diff --git a/libraries/ESP8266WiFi/src/WiFiServer.h b/libraries/ESP8266WiFi/src/WiFiServer.h index ec0cea17d..9df758bf0 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.h +++ b/libraries/ESP8266WiFi/src/WiFiServer.h @@ -31,6 +31,37 @@ extern "C" { #include "Server.h" #include "IPAddress.h" +// lwIP-v2 backlog facility allows to keep memory safe by limiting the +// maximum number of incoming *pending clients*. Default number of possibly +// simultaneously pending clients is defined in WiFiServer.cpp +// (MAX_PENDING_CLIENTS_PER_PORT=5). User can overide it at runtime from +// sketch: +// WiFiServer::begin(port, max-simultaneous-pending-clients); +// +// An "incoming pending" client is a new incoming TCP connection trying to +// reach the TCP server. It is "pending" until lwIP acknowledges it and +// "accepted / no more pending" when user calls WiFiServer::available(). +// +// Before the backlog feature or with lwIP-v1.4, there was no pending +// connections: They were immediately accepted and filling RAM. +// +// Several pending clients can appear during the time when one client is +// served by a long not-async service like ESP8266WebServer. During that +// time WiFiServer::available() cannot be called. +// +// Note: This *does not limit* the number of *simultaneously accepted +// clients*. Such limit management is left to the user. +// +// Thus, when the maximum number of pending connections is reached, new +// connections are delayed. +// By "delayed", it is meant that WiFiServer(lwIP) will not answer to the +// SYN packet until there is room for a new one: The TCP server on that port +// will be mute. The TCP client will regularly try to connect until success +// or a timeout occurs (72s on windows). +// +// When user calls WiFiServer::available(), the tcp server stops muting and +// answers to newcomers (until the "backlog" pending list is full again). + class ClientContext; class WiFiClient; @@ -39,7 +70,7 @@ class WiFiServer : public Server { protected: uint16_t _port; IPAddress _addr; - tcp_pcb* _pcb; + tcp_pcb* _listen_pcb; ClientContext* _unclaimed; ClientContext* _discarded; @@ -53,11 +84,13 @@ public: bool hasClient(); void begin(); void begin(uint16_t port); + void begin(uint16_t port, uint8_t backlog); void setNoDelay(bool nodelay); bool getNoDelay(); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buf, size_t size); uint8_t status(); + uint16_t port() const; void close(); void stop(); diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index abbb20e81..6ce97115f 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -40,17 +40,22 @@ public: _pcb(pcb), _rx_buf(0), _rx_buf_offset(0), _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0), _sync(::getDefaultPrivateGlobalSyncValue()) { - tcp_setprio(pcb, TCP_PRIO_MIN); - tcp_arg(pcb, this); - tcp_recv(pcb, &_s_recv); - tcp_sent(pcb, &_s_acked); - tcp_err(pcb, &_s_error); - tcp_poll(pcb, &_s_poll, 1); + tcp_setprio(_pcb, TCP_PRIO_MIN); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_s_recv); + tcp_sent(_pcb, &_s_acked); + tcp_err(_pcb, &_s_error); + tcp_poll(_pcb, &_s_poll, 1); // keep-alive not enabled by default //keepAlive(); } + tcp_pcb* getPCB () + { + return _pcb; + } + err_t abort() { if(_pcb) { @@ -130,10 +135,10 @@ public: } _connect_pending = true; _op_start_time = millis(); - // Following delay will be interrupted by connect callback for (decltype(_timeout_ms) i = 0; _connect_pending && i < _timeout_ms; i++) { // Give scheduled functions a chance to run (e.g. Ethernet uses recurrent) delay(1); + // will resume on timeout or when _connected or _notify_error fires } _connect_pending = false; if (!_pcb) { @@ -291,6 +296,7 @@ public: void discard_received() { + DEBUGV(":dsrcv %d\n", _rx_buf? _rx_buf->tot_len: 0); if(!_rx_buf) { return; } @@ -349,7 +355,8 @@ public: uint8_t state() const { - if(!_pcb) { + if(!_pcb || _pcb->state == CLOSE_WAIT || _pcb->state == CLOSING) { + // CLOSED for WiFIClient::status() means nothing more can be written return CLOSED; } @@ -435,7 +442,7 @@ protected: if (_connect_pending || _send_waiting) { _send_waiting = false; _connect_pending = false; - esp_schedule(); // break current delay() + esp_schedule(); // break delay in connect or _write_from_source } } @@ -461,10 +468,11 @@ protected: } _send_waiting = true; - // Following delay will be interrupted by on next received ack for (decltype(_timeout_ms) i = 0; _send_waiting && i < _timeout_ms; i++) { // Give scheduled functions a chance to run (e.g. Ethernet uses recurrent) delay(1); + // will resume on timeout or when _write_some_from_cb or _notify_error fires + } _send_waiting = false; } while(true); @@ -536,7 +544,7 @@ protected: { if (_send_waiting) { _send_waiting = false; - esp_schedule(); // break current delay() + esp_schedule(); // break delay in _write_from_source } } @@ -575,11 +583,23 @@ protected: { (void) pcb; (void) err; - if(pb == 0) { // connection closed - DEBUGV(":rcl\r\n"); + if(pb == 0) { + // connection closed by peer + DEBUGV(":rcl pb=%p sz=%d\r\n", _rx_buf, _rx_buf? _rx_buf->tot_len: -1); _notify_error(); - abort(); - return ERR_ABRT; + if (_rx_buf && _rx_buf->tot_len) + { + // there is still something to read + return ERR_OK; + } + else + { + // nothing in receive buffer, + // peer closed = nothing can be written: + // closing in the legacy way + abort(); + return ERR_ABRT; + } } if(_rx_buf) { @@ -612,7 +632,7 @@ protected: assert(pcb == _pcb); if (_connect_pending) { _connect_pending = false; - esp_schedule(); // break current delay() + esp_schedule(); // break delay in connect } return ERR_OK; } diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index 8ad074eee..8534c61f1 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -47,6 +47,7 @@ public: , _rx_buf(0) , _first_buf_taken(false) , _rx_buf_offset(0) + , _rx_buf_size(0) , _refcnt(0) , _tx_buf_head(0) , _tx_buf_cur(0) @@ -74,6 +75,7 @@ public: pbuf_free(_rx_buf); _rx_buf = 0; _rx_buf_offset = 0; + _rx_buf_size = 0; } } @@ -167,6 +169,26 @@ public: #endif // !LWIP_IPV6 + /* + * Add a netif (by its index) as the multicast interface + */ + void setMulticastInterface(netif* p_pNetIf) + { +#if LWIP_VERSION_MAJOR == 1 + udp_set_multicast_netif_addr(_pcb, (p_pNetIf ? p_pNetIf->ip_addr : ip_addr_any)); +#else + udp_set_multicast_netif_index(_pcb, (p_pNetIf ? netif_get_index(p_pNetIf) : NETIF_NO_INDEX)); +#endif + } + + /* + * Allow access to pcb to change eg. options + */ + udp_pcb* pcb(void) + { + return _pcb; + } + void setMulticastTTL(int ttl) { #ifdef LWIP_MAYBE_XCC @@ -182,12 +204,36 @@ public: _on_rx = handler; } +#ifdef DEBUG_ESP_CORE + // this helper is ready to be used when debugging UDP + void printChain (const pbuf* pb, const char* msg, size_t n) const + { + // printf the pb pbuf chain, bufferred and all at once + char buf[128]; + int l = snprintf(buf, sizeof(buf), "UDP: %s %u: ", msg, n); + while (pb) + { + l += snprintf(&buf[l], sizeof(buf) -l, "%p(H=%d,%d<=%d)-", + pb, pb->flags == PBUF_HELPER_FLAG, pb->len, pb->tot_len); + pb = pb->next; + } + l += snprintf(&buf[l], sizeof(buf) - l, "(end)"); + DEBUGV("%s\n", buf); + } +#else + void printChain (const pbuf* pb, const char* msg) const + { + (void)pb; + (void)msg; + } +#endif + size_t getSize() const { if (!_rx_buf) return 0; - return _rx_buf->len - _rx_buf_offset; + return _rx_buf_size - _rx_buf_offset; } size_t tell() const @@ -202,7 +248,12 @@ public: } bool isValidOffset(const size_t pos) const { - return (pos <= _rx_buf->len); + return (pos <= _rx_buf_size); + } + + netif* getInputNetif() const + { + return _currentAddr.input_netif; } CONST IPAddress& getRemoteAddress() CONST @@ -237,46 +288,57 @@ public: return true; } + // We have interleaved informations on addresses within received pbuf chain: + // (before ipv6 code we had: (data-pbuf) -> (data-pbuf) -> (data-pbuf) -> ... in the receiving order) + // Now: (address-info-pbuf -> chained-data-pbuf [-> chained-data-pbuf...]) -> + // (chained-address-info-pbuf -> chained-data-pbuf [-> chained...]) -> ... + // _rx_buf is currently adressing a data pbuf, + // in this function it is going to be discarded. + auto deleteme = _rx_buf; - _rx_buf = _rx_buf->next; + + // forward in the chain until next address-info pbuf or end of chain + while(_rx_buf && _rx_buf->flags != PBUF_HELPER_FLAG) + _rx_buf = _rx_buf->next; if (_rx_buf) { - if (_rx_buf->flags == PBUF_HELPER_FLAG) - { - // we have interleaved informations on addresses within reception pbuf chain: - // before: (data-pbuf) -> (data-pbuf) -> (data-pbuf) -> ... in the receiving order - // now: (address-info-pbuf -> data-pbuf) -> (address-info-pbuf -> data-pbuf) -> ... + assert(_rx_buf->flags == PBUF_HELPER_FLAG); - // so the first rx_buf contains an address helper, - // copy it to "current address" - auto helper = (AddrHelper*)PBUF_ALIGNER(_rx_buf->payload); - _currentAddr = *helper; + // copy address helper to "current address" + auto helper = (AddrHelper*)PBUF_ALIGNER(_rx_buf->payload); + _currentAddr = *helper; - // destroy the helper in the about-to-be-released pbuf - helper->~AddrHelper(); + // destroy the helper in the about-to-be-released pbuf + helper->~AddrHelper(); - // forward in rx_buf list, next one is effective data - // current (not ref'ed) one will be pbuf_free'd with deleteme - _rx_buf = _rx_buf->next; - } + // forward in rx_buf list, next one is effective data + // current (not ref'ed) one will be pbuf_free'd + // with the 'deleteme' pointer above + _rx_buf = _rx_buf->next; // this rx_buf is not nullptr by construction, + assert(_rx_buf); // ref'ing it to prevent release from the below pbuf_free(deleteme) + // (ref counter prevents release and will be decreased by pbuf_free) pbuf_ref(_rx_buf); } + + // release in chain previous data, and if any: + // current helper, but not start of current data pbuf_free(deleteme); _rx_buf_offset = 0; + _rx_buf_size = _processSize(_rx_buf); return _rx_buf != nullptr; } int read() { - if (!_rx_buf || _rx_buf_offset >= _rx_buf->len) + if (!_rx_buf || _rx_buf_offset >= _rx_buf_size) return -1; - char c = reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + char c = pbuf_get_at(_rx_buf, _rx_buf_offset); _consume(1); return c; } @@ -286,11 +348,17 @@ public: if (!_rx_buf) return 0; - size_t max_size = _rx_buf->len - _rx_buf_offset; + size_t max_size = _rx_buf_size - _rx_buf_offset; size = (size < max_size) ? size : max_size; - DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf_offset); + DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf_size, _rx_buf_offset); + + void* buf = pbuf_get_contiguous(_rx_buf, dst, size, size, _rx_buf_offset); + if(!buf) + return 0; + + if(buf != dst) + memcpy(dst, buf, size); - memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, size); _consume(size); return size; @@ -298,10 +366,10 @@ public: int peek() const { - if (!_rx_buf || _rx_buf_offset == _rx_buf->len) + if (!_rx_buf || _rx_buf_offset == _rx_buf_size) return -1; - return reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + return pbuf_get_at(_rx_buf, _rx_buf_offset); } void flush() @@ -310,7 +378,7 @@ public: if (!_rx_buf) return; - _consume(_rx_buf->len - _rx_buf_offset); + _consume(_rx_buf_size - _rx_buf_offset); } size_t append(const char* data, size_t size) @@ -394,6 +462,14 @@ public: private: + size_t _processSize (const pbuf* pb) + { + size_t ret = 0; + for (; pb && pb->flags != PBUF_HELPER_FLAG; pb = pb->next) + ret += pb->len; + return ret; + } + void _reserve(size_t size) { const size_t pbuf_unit_size = 128; @@ -431,8 +507,8 @@ private: void _consume(size_t size) { _rx_buf_offset += size; - if (_rx_buf_offset > _rx_buf->len) { - _rx_buf_offset = _rx_buf->len; + if (_rx_buf_offset > _rx_buf_size) { + _rx_buf_offset = _rx_buf_size; } } @@ -440,11 +516,27 @@ private: const ip_addr_t *srcaddr, u16_t srcport) { (void) upcb; + // check receive pbuf chain depth + // optimization path: cache the pbuf chain length + { + pbuf* p; + int count = 0; + for (p = _rx_buf; p && ++count < rxBufMaxDepth*2; p = p->next); + if (p) + { + // pbuf chain too deep, dropping + pbuf_free(pb); + DEBUGV(":udr\r\n"); + return; + } + } #if LWIP_VERSION_MAJOR == 1 #define TEMPDSTADDR (¤t_iphdr_dest) + #define TEMPINPUTNETIF (current_netif) #else #define TEMPDSTADDR (ip_current_dest_addr()) + #define TEMPINPUTNETIF (ip_current_input_netif()) #endif // chain this helper pbuf first @@ -472,7 +564,7 @@ private: return; } // construct in place - new(PBUF_ALIGNER(pb_helper->payload)) AddrHelper(srcaddr, TEMPDSTADDR, srcport); + new(PBUF_ALIGNER(pb_helper->payload)) AddrHelper(srcaddr, TEMPDSTADDR, srcport, TEMPINPUTNETIF); pb_helper->flags = PBUF_HELPER_FLAG; // mark helper pbuf // chain it pbuf_cat(_rx_buf, pb_helper); @@ -486,11 +578,13 @@ private: _currentAddr.srcaddr = srcaddr; _currentAddr.dstaddr = TEMPDSTADDR; _currentAddr.srcport = srcport; + _currentAddr.input_netif = TEMPINPUTNETIF; DEBUGV(":urn %d\r\n", pb->tot_len); _first_buf_taken = false; _rx_buf = pb; _rx_buf_offset = 0; + _rx_buf_size = pb->tot_len; } if (_on_rx) { @@ -498,6 +592,7 @@ private: } #undef TEMPDSTADDR + #undef TEMPINPUTNETIF } @@ -508,11 +603,96 @@ private: reinterpret_cast(arg)->_recv(upcb, p, srcaddr, srcport); } +#if LWIP_VERSION_MAJOR == 1 + /* + * Code in this conditional block is copied/backported verbatim from + * LwIP 2.1.2 to provide pbuf_get_contiguous. + */ + + static const struct pbuf * + pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset) + { + u16_t offset_left = in_offset; + const struct pbuf *pbuf_it = in; + + /* get the correct pbuf */ + while ((pbuf_it != NULL) && (pbuf_it->len <= offset_left)) { + offset_left = (u16_t)(offset_left - pbuf_it->len); + pbuf_it = pbuf_it->next; + } + if (out_offset != NULL) { + *out_offset = offset_left; + } + return pbuf_it; + } + + u16_t + pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) + { + const struct pbuf *p; + u16_t left = 0; + u16_t buf_copy_len; + u16_t copied_total = 0; + + LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); + LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); + + /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ + for (p = buf; len != 0 && p != NULL; p = p->next) { + if ((offset != 0) && (offset >= p->len)) { + /* don't copy from this buffer -> on to the next */ + offset = (u16_t)(offset - p->len); + } else { + /* copy from this buffer. maybe only partially. */ + buf_copy_len = (u16_t)(p->len - offset); + if (buf_copy_len > len) { + buf_copy_len = len; + } + /* copy the necessary parts of the buffer */ + MEMCPY(&((char *)dataptr)[left], &((char *)p->payload)[offset], buf_copy_len); + copied_total = (u16_t)(copied_total + buf_copy_len); + left = (u16_t)(left + buf_copy_len); + len = (u16_t)(len - buf_copy_len); + offset = 0; + } + } + return copied_total; + } + + void * + pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) + { + const struct pbuf *q; + u16_t out_offset; + + LWIP_ERROR("pbuf_get_contiguous: invalid buf", (p != NULL), return NULL;); + LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (buffer != NULL), return NULL;); + LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (bufsize >= len), return NULL;); + + q = pbuf_skip_const(p, offset, &out_offset); + if (q != NULL) { + if (q->len >= (out_offset + len)) { + /* all data in this pbuf, return zero-copy */ + return (u8_t *)q->payload + out_offset; + } + /* need to copy */ + if (pbuf_copy_partial(q, buffer, len, out_offset) != len) { + /* copying failed: pbuf is too short */ + return NULL; + } + return buffer; + } + /* pbuf is too short (offset does not fit in) */ + return NULL; + } +#endif + private: udp_pcb* _pcb; pbuf* _rx_buf; bool _first_buf_taken; size_t _rx_buf_offset; + size_t _rx_buf_size; int _refcnt; pbuf* _tx_buf_head; pbuf* _tx_buf_cur; @@ -525,12 +705,17 @@ private: { IPAddress srcaddr, dstaddr; int16_t srcport; + netif* input_netif; AddrHelper() { } - AddrHelper(const ip_addr_t* src, const ip_addr_t* dst, uint16_t srcport): - srcaddr(src), dstaddr(dst), srcport(srcport) { } + AddrHelper(const ip_addr_t* src, const ip_addr_t* dst, uint16_t srcport, netif* input_netif): + srcaddr(src), dstaddr(dst), srcport(srcport), input_netif(input_netif) { } }; AddrHelper _currentAddr; + + // rx pbuf depth barrier (counter of buffered UDP received packets) + // keep it small + static constexpr int rxBufMaxDepth = 4; }; diff --git a/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino b/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino index 34ca17942..69ed71fe6 100644 --- a/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino +++ b/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino @@ -43,6 +43,23 @@ void setup() { } +void update_started() { + USE_SERIAL.println("CALLBACK: HTTP update process started"); +} + +void update_finished() { + USE_SERIAL.println("CALLBACK: HTTP update process finished"); +} + +void update_progress(int cur, int total) { + USE_SERIAL.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total); +} + +void update_error(int err) { + USE_SERIAL.printf("CALLBACK: HTTP update fatal error code %d\n", err); +} + + void loop() { // wait for WiFi connection if ((WiFiMulti.run() == WL_CONNECTED)) { @@ -57,6 +74,12 @@ void loop() { // value is used to put the LED on. If the LED is on with HIGH, that value should be passed ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW); + // Add optional callback notifiers + ESPhttpUpdate.onStart(update_started); + ESPhttpUpdate.onEnd(update_finished); + ESPhttpUpdate.onProgress(update_progress); + ESPhttpUpdate.onError(update_error); + t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://server/file.bin"); // Or: //t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin"); diff --git a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp old mode 100644 new mode 100755 index 8787562d6..9d56718c1 --- a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp +++ b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp @@ -294,7 +294,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& if(code <= 0) { DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http.errorToString(code).c_str()); - _lastError = code; + _setLastError(code); http.end(); return HTTP_UPDATE_FAILED; } @@ -334,15 +334,21 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& } } - if(!startUpdate) { - _lastError = HTTP_UE_TOO_LESS_SPACE; + if (!startUpdate) { + _setLastError(HTTP_UE_TOO_LESS_SPACE); ret = HTTP_UPDATE_FAILED; } else { + // Warn main app we're starting up... + if (_cbStart) { + _cbStart(); + } WiFiClient * tcp = http.getStreamPtr(); - WiFiUDP::stopAll(); - WiFiClient::stopAllExcept(tcp); + if (_closeConnectionsOnUpdate) { + WiFiUDP::stopAll(); + WiFiClient::stopAllExcept(tcp); + } delay(100); @@ -360,34 +366,40 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& uint8_t buf[4]; if(tcp->peekBytes(&buf[0], 4) != 4) { DEBUG_HTTP_UPDATE("[httpUpdate] peekBytes magic header failed\n"); - _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + _setLastError(HTTP_UE_BIN_VERIFY_HEADER_FAILED); http.end(); return HTTP_UPDATE_FAILED; } // check for valid first magic byte - if(buf[0] != 0xE9) { + if(buf[0] != 0xE9 && buf[0] != 0x1f) { DEBUG_HTTP_UPDATE("[httpUpdate] Magic header does not start with 0xE9\n"); - _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + _setLastError(HTTP_UE_BIN_VERIFY_HEADER_FAILED); http.end(); return HTTP_UPDATE_FAILED; } - uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4); + if (buf[0] == 0xe9) { + uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4); - // check if new bin fits to SPI flash - if(bin_flash_size > ESP.getFlashChipRealSize()) { - DEBUG_HTTP_UPDATE("[httpUpdate] New binary does not fit SPI Flash size\n"); - _lastError = HTTP_UE_BIN_FOR_WRONG_FLASH; - http.end(); - return HTTP_UPDATE_FAILED; + // check if new bin fits to SPI flash + if(bin_flash_size > ESP.getFlashChipRealSize()) { + DEBUG_HTTP_UPDATE("[httpUpdate] New binary does not fit SPI Flash size\n"); + _setLastError(HTTP_UE_BIN_FOR_WRONG_FLASH); + http.end(); + return HTTP_UPDATE_FAILED; + } } } if(runUpdate(*tcp, len, http.header("x-MD5"), command)) { ret = HTTP_UPDATE_OK; DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n"); http.end(); + // Warn main app we're all done + if (_cbEnd) { + _cbEnd(); + } #ifdef ATOMIC_FS_UPDATE if(_rebootOnUpdate) { @@ -403,7 +415,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& } } } else { - _lastError = HTTP_UE_SERVER_NOT_REPORT_SIZE; + _setLastError(HTTP_UE_SERVER_NOT_REPORT_SIZE); ret = HTTP_UPDATE_FAILED; DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length was 0 or wasn't set by Server?!\n"); } @@ -413,15 +425,15 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& ret = HTTP_UPDATE_NO_UPDATES; break; case HTTP_CODE_NOT_FOUND: - _lastError = HTTP_UE_SERVER_FILE_NOT_FOUND; + _setLastError(HTTP_UE_SERVER_FILE_NOT_FOUND); ret = HTTP_UPDATE_FAILED; break; case HTTP_CODE_FORBIDDEN: - _lastError = HTTP_UE_SERVER_FORBIDDEN; + _setLastError(HTTP_UE_SERVER_FORBIDDEN); ret = HTTP_UPDATE_FAILED; break; default: - _lastError = HTTP_UE_SERVER_WRONG_HTTP_CODE; + _setLastError(HTTP_UE_SERVER_WRONG_HTTP_CODE); ret = HTTP_UPDATE_FAILED; DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code); //http.writeToStream(&Serial1); @@ -439,37 +451,49 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& * @param md5 String * @return true if Update ok */ -bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int command) +bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, const String& md5, int command) { StreamString error; + if (_cbProgress) { + Update.onProgress(_cbProgress); + } + if(!Update.begin(size, command, _ledPin, _ledOn)) { - _lastError = Update.getError(); + _setLastError(Update.getError()); Update.printError(error); error.trim(); // remove line ending DEBUG_HTTP_UPDATE("[httpUpdate] Update.begin failed! (%s)\n", error.c_str()); return false; } + if (_cbProgress) { + _cbProgress(0, size); + } + if(md5.length()) { if(!Update.setMD5(md5.c_str())) { - _lastError = HTTP_UE_SERVER_FAULTY_MD5; + _setLastError(HTTP_UE_SERVER_FAULTY_MD5); DEBUG_HTTP_UPDATE("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str()); return false; } } if(Update.writeStream(in) != size) { - _lastError = Update.getError(); + _setLastError(Update.getError()); Update.printError(error); error.trim(); // remove line ending DEBUG_HTTP_UPDATE("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str()); return false; } + if (_cbProgress) { + _cbProgress(size, size); + } + if(!Update.end()) { - _lastError = Update.getError(); + _setLastError(Update.getError()); Update.printError(error); error.trim(); // remove line ending DEBUG_HTTP_UPDATE("[httpUpdate] Update.end failed! (%s)\n", error.c_str()); diff --git a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h old mode 100644 new mode 100755 index 14c0b6552..8d06def9d --- a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h +++ b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h @@ -47,14 +47,15 @@ #endif /// note we use HTTP client errors too so we start at 100 -#define HTTP_UE_TOO_LESS_SPACE (-100) -#define HTTP_UE_SERVER_NOT_REPORT_SIZE (-101) -#define HTTP_UE_SERVER_FILE_NOT_FOUND (-102) -#define HTTP_UE_SERVER_FORBIDDEN (-103) -#define HTTP_UE_SERVER_WRONG_HTTP_CODE (-104) -#define HTTP_UE_SERVER_FAULTY_MD5 (-105) -#define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106) -#define HTTP_UE_BIN_FOR_WRONG_FLASH (-107) +//TODO - in v3.0.0 make this an enum +constexpr int HTTP_UE_TOO_LESS_SPACE = (-100); +constexpr int HTTP_UE_SERVER_NOT_REPORT_SIZE = (-101); +constexpr int HTTP_UE_SERVER_FILE_NOT_FOUND = (-102); +constexpr int HTTP_UE_SERVER_FORBIDDEN = (-103); +constexpr int HTTP_UE_SERVER_WRONG_HTTP_CODE = (-104); +constexpr int HTTP_UE_SERVER_FAULTY_MD5 = (-105); +constexpr int HTTP_UE_BIN_VERIFY_HEADER_FAILED = (-106); +constexpr int HTTP_UE_BIN_FOR_WRONG_FLASH = (-107); enum HTTPUpdateResult { HTTP_UPDATE_FAILED, @@ -64,6 +65,11 @@ enum HTTPUpdateResult { typedef HTTPUpdateResult t_httpUpdate_return; // backward compatibility +using HTTPUpdateStartCB = std::function; +using HTTPUpdateEndCB = std::function; +using HTTPUpdateErrorCB = std::function; +using HTTPUpdateProgressCB = std::function; + class ESP8266HTTPUpdate { public: @@ -81,6 +87,11 @@ public: _followRedirects = follow; } + void closeConnectionsOnUpdate(bool sever) + { + _closeConnectionsOnUpdate = sever; + } + void setLedPin(int ledPin = -1, uint8_t ledOn = HIGH) { _ledPin = ledPin; @@ -124,20 +135,39 @@ public: #endif t_httpUpdate_return updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion = ""); + // Notification callbacks + void onStart(HTTPUpdateStartCB cbOnStart) { _cbStart = cbOnStart; } + void onEnd(HTTPUpdateEndCB cbOnEnd) { _cbEnd = cbOnEnd; } + void onError(HTTPUpdateErrorCB cbOnError) { _cbError = cbOnError; } + void onProgress(HTTPUpdateProgressCB cbOnProgress) { _cbProgress = cbOnProgress; } int getLastError(void); String getLastErrorString(void); protected: t_httpUpdate_return handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs = false); - bool runUpdate(Stream& in, uint32_t size, String md5, int command = U_FLASH); + bool runUpdate(Stream& in, uint32_t size, const String& md5, int command = U_FLASH); + // Set the error and potentially use a CB to notify the application + void _setLastError(int err) { + _lastError = err; + if (_cbError) { + _cbError(err); + } + } int _lastError; bool _rebootOnUpdate = true; + bool _closeConnectionsOnUpdate = true; private: int _httpClientTimeout; bool _followRedirects; + // Callbacks + HTTPUpdateStartCB _cbStart; + HTTPUpdateEndCB _cbEnd; + HTTPUpdateErrorCB _cbError; + HTTPUpdateProgressCB _cbProgress; + int _ledPin; uint8_t _ledOn; }; diff --git a/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp b/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp index af98b46b6..879119552 100644 --- a/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp +++ b/libraries/ESP8266mDNS/src/ESP8266mDNS_Legacy.cpp @@ -277,7 +277,7 @@ bool MDNSResponder::addServiceTxt(char *name, char *proto, char *key, char *valu return false; //max txt record size } MDNSTxt *newtxt = new MDNSTxt; - newtxt->_txt = String(key) + "=" + String(value); + newtxt->_txt = String(key) + '=' + String(value); newtxt->_next = 0; if (servicePtr->_txts == 0) //no services have been added { diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.cpp b/libraries/ESP8266mDNS/src/LEAmDNS.cpp index 95f07079d..628432411 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.cpp +++ b/libraries/ESP8266mDNS/src/LEAmDNS.cpp @@ -114,33 +114,20 @@ bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress IPAddress sta = WiFi.localIP(); IPAddress ap = WiFi.softAPIP(); - if (!sta.isSet() && !ap.isSet()) + if (sta.isSet()) { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] internal interfaces (STA, AP) are not set (none was specified)\n"))); - return false; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] STA interface selected\n"))); + ipAddress = sta; } - - if (ap.isSet()) + else if (ap.isSet()) { - - if (sta.isSet()) - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface AP selected over STA (none was specified)\n"))); - } - else - { - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface AP selected\n"))); - } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] AP interface selected\n"))); ipAddress = ap; - } else { - - DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] default interface STA selected (none was specified)\n"))); - ipAddress = sta; - + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] standard interfaces are not up, please specify one in ::begin()\n"))); + return false; } // continue to ensure interface is UP @@ -215,18 +202,26 @@ bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress */ bool MDNSResponder::close(void) { + bool bResult = false; - m_GotIPHandler.reset(); // reset WiFi event callbacks. - m_DisconnectedHandler.reset(); + if (0 != m_pUDPContext) + { + m_GotIPHandler.reset(); // reset WiFi event callbacks. + m_DisconnectedHandler.reset(); - _announce(false, true); - _resetProbeStatus(false); // Stop probing + _announce(false, true); + _resetProbeStatus(false); // Stop probing + _releaseServiceQueries(); + _releaseUDPContext(); + _releaseHostname(); - _releaseServiceQueries(); - _releaseUDPContext(); - _releaseHostname(); - - return true; + bResult = true; + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] close: Ignoring call to close!\n"));); + } + return bResult; } /* @@ -280,7 +275,7 @@ bool MDNSResponder::setHostname(const char* p_pcHostname) /* MDNSResponder::setHostname (LEGACY) */ -bool MDNSResponder::setHostname(String p_strHostname) +bool MDNSResponder::setHostname(const String& p_strHostname) { return setHostname(p_strHostname.c_str()); @@ -369,8 +364,8 @@ bool MDNSResponder::removeService(const char* p_pcName, /* MDNSResponder::addService (LEGACY) */ -bool MDNSResponder::addService(String p_strService, - String p_strProtocol, +bool MDNSResponder::addService(const String& p_strService, + const String& p_strProtocol, uint16_t p_u16Port) { @@ -595,10 +590,10 @@ bool MDNSResponder::addServiceTxt(const char* p_pcService, /* MDNSResponder::addServiceTxt (LEGACY) */ -bool MDNSResponder::addServiceTxt(String p_strService, - String p_strProtocol, - String p_strKey, - String p_strValue) +bool MDNSResponder::addServiceTxt(const String& p_strService, + const String& p_strProtocol, + const String& p_strKey, + const String& p_strValue) { return (0 != _addServiceTxt(_findService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str()), p_strKey.c_str(), p_strValue.c_str(), false)); @@ -826,8 +821,8 @@ bool MDNSResponder::removeQuery(void) /* MDNSResponder::queryService (LEGACY) */ -uint32_t MDNSResponder::queryService(String p_strService, - String p_strProtocol) +uint32_t MDNSResponder::queryService(const String& p_strService, + const String& p_strProtocol) { return queryService(p_strService.c_str(), p_strProtocol.c_str()); diff --git a/libraries/ESP8266mDNS/src/LEAmDNS.h b/libraries/ESP8266mDNS/src/LEAmDNS.h index da3aa01a1..39b2bad81 100644 --- a/libraries/ESP8266mDNS/src/LEAmDNS.h +++ b/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -192,7 +192,7 @@ public: // Change hostname (probing is restarted) bool setHostname(const char* p_pcHostname); // for compatibility... - bool setHostname(String p_strHostname); + bool setHostname(const String& p_strHostname); /** hMDNSService (opaque handle to access the service) @@ -213,8 +213,8 @@ public: const char* p_pcServiceName, const char* p_pcProtocol); // for compatibility... - bool addService(String p_strServiceName, - String p_strProtocol, + bool addService(const String& p_strServiceName, + const String& p_strProtocol, uint16_t p_u16Port); @@ -276,10 +276,10 @@ public: const char* p_pcProtocol, const char* p_pcKey, const char* p_pcValue); - bool addServiceTxt(String p_strService, - String p_strProtocol, - String p_strKey, - String p_strValue); + bool addServiceTxt(const String& p_strService, + const String& p_strProtocol, + const String& p_strKey, + const String& p_strValue); /** MDNSDynamicServiceTxtCallbackFn @@ -331,8 +331,8 @@ public: const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); bool removeQuery(void); // for compatibility... - uint32_t queryService(String p_strService, - String p_strProtocol); + uint32_t queryService(const String& p_strService, + const String& p_strProtocol); const char* answerHostname(const uint32_t p_u32AnswerIndex); IPAddress answerIP(const uint32_t p_u32AnswerIndex); diff --git a/libraries/GDBStub/examples/gdbstub_example.ino b/libraries/GDBStub/examples/gdbstub_example.ino new file mode 100644 index 000000000..7b9dec329 --- /dev/null +++ b/libraries/GDBStub/examples/gdbstub_example.ino @@ -0,0 +1,13 @@ +#include + +void setup() { + Serial.begin(115200); + gdbstub_init(); + Serial.printf("Starting...\n"); +} + +void loop() { + static uint32_t cnt = 0; + Serial.printf("%d\n", cnt++); + delay(100); +} diff --git a/libraries/GDBStub/src/internal/gdbstub.c b/libraries/GDBStub/src/internal/gdbstub.c index 860345e20..97b0b1386 100644 --- a/libraries/GDBStub/src/internal/gdbstub.c +++ b/libraries/GDBStub/src/internal/gdbstub.c @@ -67,7 +67,6 @@ OS-less SDK defines. Defines some headers for things that aren't in the include the xthal stack frame struct. */ #include "osapi.h" -#include "user_interface.h" void _xtos_set_exception_handler(int cause, void (exhandler)(struct XTensa_exception_frame_s *frame)); diff --git a/libraries/LittleFS/examples/LittleFS_Timestamp/LittleFS_Timestamp.ino b/libraries/LittleFS/examples/LittleFS_Timestamp/LittleFS_Timestamp.ino new file mode 100644 index 000000000..dfec9ee30 --- /dev/null +++ b/libraries/LittleFS/examples/LittleFS_Timestamp/LittleFS_Timestamp.ino @@ -0,0 +1,189 @@ +/* Example showing timestamp support in LittleFS */ +/* Released into the public domain. */ +/* Earle F. Philhower, III */ + +#include +#include +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char *ssid = STASSID; +const char *pass = STAPSK; + +long timezone = 2; +byte daysavetime = 1; + + +bool getLocalTime(struct tm * info, uint32_t ms) { + uint32_t count = ms / 10; + time_t now; + + time(&now); + localtime_r(&now, info); + + if (info->tm_year > (2016 - 1900)) { + return true; + } + + while (count--) { + delay(10); + time(&now); + localtime_r(&now, info); + if (info->tm_year > (2016 - 1900)) { + return true; + } + } + return false; +} + + +void listDir(const char * dirname) { + Serial.printf("Listing directory: %s\n", dirname); + + Dir root = LittleFS.openDir(dirname); + + while (root.next()) { + File file = root.openFile("r"); + Serial.print(" FILE: "); + Serial.print(root.fileName()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t cr = file.getCreationTime(); + time_t lw = file.getLastWrite(); + file.close(); + struct tm * tmstruct = localtime(&cr); + Serial.printf(" CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + tmstruct = localtime(&lw); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + } +} + + +void readFile(const char * path) { + Serial.printf("Reading file: %s\n", path); + + File file = LittleFS.open(path, "r"); + if (!file) { + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while (file.available()) { + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(const char * path, const char * message) { + Serial.printf("Writing file: %s\n", path); + + File file = LittleFS.open(path, "w"); + if (!file) { + Serial.println("Failed to open file for writing"); + return; + } + if (file.print(message)) { + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + delay(2000); // Make sure the CREATE and LASTWRITE times are different + file.close(); +} + +void appendFile(const char * path, const char * message) { + Serial.printf("Appending to file: %s\n", path); + + File file = LittleFS.open(path, "a"); + if (!file) { + Serial.println("Failed to open file for appending"); + return; + } + if (file.print(message)) { + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(const char * path1, const char * path2) { + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (LittleFS.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(const char * path) { + Serial.printf("Deleting file: %s\n", path); + if (LittleFS.remove(path)) { + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void setup() { + Serial.begin(115200); + // We start by connecting to a WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, pass); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("Contacting Time Server"); + configTime(3600 * timezone, daysavetime * 3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + struct tm tmstruct ; + delay(2000); + tmstruct.tm_year = 0; + getLocalTime(&tmstruct, 5000); + Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec); + Serial.println(""); + Serial.println("Formatting LittleFS filesystem"); + LittleFS.format(); + Serial.println("Mount LittleFS"); + if (!LittleFS.begin()) { + Serial.println("LittleFS mount failed"); + return; + } + listDir("/"); + deleteFile("/hello.txt"); + writeFile("/hello.txt", "Hello "); + appendFile("/hello.txt", "World!\n"); + listDir("/"); + + Serial.println("The timestamp should be valid above"); + + Serial.println("Now unmount and remount and perform the same operation."); + Serial.println("Timestamp should be valid, data should be good."); + LittleFS.end(); + Serial.println("Now mount it"); + if (!LittleFS.begin()) { + Serial.println("LittleFS mount failed"); + return; + } + readFile("/hello.txt"); + listDir("/"); + + +} + +void loop() { } + diff --git a/libraries/LittleFS/lib/littlefs b/libraries/LittleFS/lib/littlefs index abd90cb84..ce2c01f09 160000 --- a/libraries/LittleFS/lib/littlefs +++ b/libraries/LittleFS/lib/littlefs @@ -1 +1 @@ -Subproject commit abd90cb84c818a663b584575b019258d01d0065e +Subproject commit ce2c01f098f4d2b9479de5a796c3bb531f1fe14c diff --git a/libraries/LittleFS/src/LittleFS.cpp b/libraries/LittleFS/src/LittleFS.cpp index b4aba1970..b85075112 100644 --- a/libraries/LittleFS/src/LittleFS.cpp +++ b/libraries/LittleFS/src/LittleFS.cpp @@ -52,7 +52,7 @@ FileImplPtr LittleFSImpl::open(const char* path, OpenMode openMode, AccessMode a int flags = _getFlags(openMode, accessMode); auto fd = std::make_shared(); - if ((openMode && OM_CREATE) && strchr(path, '/')) { + if ((openMode & OM_CREATE) && strchr(path, '/')) { // For file creation, silently make subdirs as needed. If any fail, // it will be caught by the real file open later on char *pathStr = strdup(path); @@ -68,13 +68,26 @@ FileImplPtr LittleFSImpl::open(const char* path, OpenMode openMode, AccessMode a } free(pathStr); } + + time_t creation = 0; + if (timeCallback && (openMode & OM_CREATE)) { + // O_CREATE means we *may* make the file, but not if it already exists. + // See if it exists, and only if not update the creation time + int rc = lfs_file_open(&_lfs, fd.get(), path, LFS_O_RDONLY); + if (rc == 0) { + lfs_file_close(&_lfs, fd.get()); // It exists, don't update create time + } else { + creation = timeCallback(); // File didn't exist or otherwise, so we're going to create this time + } + } + int rc = lfs_file_open(&_lfs, fd.get(), path, flags); if (rc == LFS_ERR_ISDIR) { // To support the SD.openNextFile, a null FD indicates to the LittleFSFile this is just // a directory whose name we are carrying around but which cannot be read or written - return std::make_shared(this, path, nullptr); + return std::make_shared(this, path, nullptr, flags, creation); } else if (rc == 0) { - return std::make_shared(this, path, fd); + return std::make_shared(this, path, fd, flags, creation); } else { DEBUGV("LittleFSDirImpl::openFile: rc=%d fd=%p path=`%s` openMode=%d accessMode=%d err=%d\n", rc, fd.get(), path, openMode, accessMode, rc); @@ -190,6 +203,14 @@ int LittleFSImpl::lfs_flash_sync(const struct lfs_config *c) { #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_LITTLEFS) FS LittleFS = FS(FSImplPtr(new littlefs_impl::LittleFSImpl(FS_PHYS_ADDR, FS_PHYS_SIZE, FS_PHYS_PAGE, FS_PHYS_BLOCK, FS_MAX_OPEN_FILES))); + +extern "C" void littlefs_request_end(void) +{ + // override default weak function + //ets_printf("debug: not weak littlefs end\n"); + LittleFS.end(); +} + #endif #endif // !CORE_MOCK diff --git a/libraries/LittleFS/src/LittleFS.h b/libraries/LittleFS/src/LittleFS.h index 467255ca3..4d417905e 100644 --- a/libraries/LittleFS/src/LittleFS.h +++ b/libraries/LittleFS/src/LittleFS.h @@ -47,11 +47,8 @@ class LittleFSDirImpl; class LittleFSConfig : public FSConfig { public: - LittleFSConfig(bool autoFormat = true) { - _type = LittleFSConfig::fsid::FSId; - _autoFormat = autoFormat; - } - enum fsid { FSId = 0x4c495454 }; + static constexpr uint32_t FSId = 0x4c495454; + LittleFSConfig(bool autoFormat = true) : FSConfig(FSId, autoFormat) { } }; class LittleFSImpl : public FSImpl @@ -92,7 +89,7 @@ public: DirImplPtr openDir(const char *path) override; bool exists(const char* path) override { - if ( !_mounted || !path || !path[0] ) { + if (!_mounted || !path || !path[0]) { return false; } lfs_info info; @@ -101,7 +98,7 @@ public: } bool rename(const char* pathFrom, const char* pathTo) override { - if (!_mounted || !pathFrom || !pathFrom[0] || !pathTo || !pathTo[0]) { + if (!_mounted || !pathFrom || !pathFrom[0] || !pathTo || !pathTo[0]) { return false; } int rc = lfs_rename(&_lfs, pathFrom, pathTo); @@ -176,7 +173,7 @@ public: } bool setConfig(const FSConfig &cfg) override { - if ((cfg._type != LittleFSConfig::fsid::FSId) || _mounted) { + if ((cfg._type != LittleFSConfig::FSId) || _mounted) { return false; } _cfg = *static_cast(&cfg); @@ -326,7 +323,7 @@ protected: class LittleFSFileImpl : public FileImpl { public: - LittleFSFileImpl(LittleFSImpl* fs, const char *name, std::shared_ptr fd) : _fs(fs), _fd(fd), _opened(true) { + LittleFSFileImpl(LittleFSImpl* fs, const char *name, std::shared_ptr fd, int flags, time_t creation) : _fs(fs), _fd(fd), _opened(true), _flags(flags), _creation(creation) { _name = std::shared_ptr(new char[strlen(name) + 1], std::default_delete()); strcpy(_name.get(), name); } @@ -422,9 +419,44 @@ public: lfs_file_close(_fs->getFS(), _getFD()); _opened = false; DEBUGV("lfs_file_close: fd=%p\n", _getFD()); + if (timeCallback && (_flags & LFS_O_WRONLY)) { + // If the file opened with O_CREAT, write the creation time attribute + if (_creation) { + int rc = lfs_setattr(_fs->getFS(), _name.get(), 'c', (const void *)&_creation, sizeof(_creation)); + if (rc < 0) { + DEBUGV("Unable to set creation time on '%s' to %d\n", _name.get(), _creation); + } + } + // Add metadata with last write time + time_t now = timeCallback(); + int rc = lfs_setattr(_fs->getFS(), _name.get(), 't', (const void *)&now, sizeof(now)); + if (rc < 0) { + DEBUGV("Unable to set last write time on '%s' to %d\n", _name.get(), now); + } + } } } + time_t getLastWrite() override { + time_t ftime = 0; + if (_opened && _fd) { + int rc = lfs_getattr(_fs->getFS(), _name.get(), 't', (void *)&ftime, sizeof(ftime)); + if (rc != sizeof(ftime)) + ftime = 0; // Error, so clear read value + } + return ftime; + } + + time_t getCreationTime() override { + time_t ftime = 0; + if (_opened && _fd) { + int rc = lfs_getattr(_fs->getFS(), _name.get(), 'c', (void *)&ftime, sizeof(ftime)); + if (rc != sizeof(ftime)) + ftime = 0; // Error, so clear read value + } + return ftime; + } + const char* name() const override { if (!_opened) { return nullptr; @@ -468,6 +500,8 @@ protected: std::shared_ptr _fd; std::shared_ptr _name; bool _opened; + int _flags; + time_t _creation; }; class LittleFSDirImpl : public DirImpl @@ -496,13 +530,9 @@ public: int nameLen = 3; // Slashes, terminator nameLen += _dirPath.get() ? strlen(_dirPath.get()) : 0; nameLen += strlen(_dirent.name); - char *tmpName = (char*)malloc(nameLen); - if (!tmpName) { - return FileImplPtr(); - } - snprintf(tmpName, nameLen, "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _dirent.name); + char tmpName[nameLen]; + snprintf(tmpName, nameLen, "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _dirent.name); auto ret = _fs->open((const char *)tmpName, openMode, accessMode); - free(tmpName); return ret; } @@ -520,6 +550,15 @@ public: return _dirent.size; } + time_t fileTime() override { + return (time_t)_getAttr4('t'); + } + + time_t fileCreationTime() override { + return (time_t)_getAttr4('c'); + } + + bool isFile() const override { return _valid && (_dirent.type == LFS_TYPE_REG); } @@ -531,6 +570,10 @@ public: bool rewind() override { _valid = false; int rc = lfs_dir_rewind(_fs->getFS(), _getDir()); + // Skip the . and .. entries + lfs_info dirent; + lfs_dir_read(_fs->getFS(), _getDir(), &dirent); + lfs_dir_read(_fs->getFS(), _getDir(), &dirent); return (rc == 0); } @@ -551,6 +594,22 @@ protected: return _dir.get(); } + uint32_t _getAttr4(char attr) { + if (!_valid) { + return 0; + } + int nameLen = 3; // Slashes, terminator + nameLen += _dirPath.get() ? strlen(_dirPath.get()) : 0; + nameLen += strlen(_dirent.name); + char tmpName[nameLen]; + snprintf(tmpName, nameLen, "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _dirent.name); + time_t ftime = 0; + int rc = lfs_getattr(_fs->getFS(), tmpName, attr, (void *)&ftime, sizeof(ftime)); + if (rc != sizeof(ftime)) + ftime = 0; // Error, so clear read value + return ftime; + } + String _pattern; LittleFSImpl *_fs; std::shared_ptr _dir; diff --git a/libraries/SD/examples/listfiles/listfiles.ino b/libraries/SD/examples/listfiles/listfiles.ino index 2b5eaf1ab..55478d708 100644 --- a/libraries/SD/examples/listfiles/listfiles.ino +++ b/libraries/SD/examples/listfiles/listfiles.ino @@ -28,14 +28,11 @@ File root; void setup() { // Open serial communications and wait for port to open: - Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for Leonardo only - } + Serial.begin(115200); Serial.print("Initializing SD card..."); - if (!SD.begin(4)) { + if (!SD.begin(SS)) { Serial.println("initialization failed!"); return; } @@ -70,11 +67,14 @@ void printDirectory(File dir, int numTabs) { } else { // files have sizes, directories do not Serial.print("\t\t"); - Serial.println(entry.size(), DEC); + Serial.print(entry.size(), DEC); + time_t cr = entry.getCreationTime(); + time_t lw = entry.getLastWrite(); + struct tm * tmstruct = localtime(&cr); + Serial.printf("\tCREATION: %d-%02d-%02d %02d:%02d:%02d", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + tmstruct = localtime(&lw); + Serial.printf("\tLAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); } entry.close(); } } - - - diff --git a/libraries/SD/src/SD.cpp b/libraries/SD/src/SD.cpp index 6b40b0e49..a3f0431dd 100644 --- a/libraries/SD/src/SD.cpp +++ b/libraries/SD/src/SD.cpp @@ -3,3 +3,5 @@ #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SD) SDClass SD; #endif + +void (*__SD__userDateTimeCB)(uint16_t*, uint16_t*) = nullptr; diff --git a/libraries/SD/src/SD.h b/libraries/SD/src/SD.h index bb1c696a5..d15d8f85b 100644 --- a/libraries/SD/src/SD.h +++ b/libraries/SD/src/SD.h @@ -29,6 +29,7 @@ #undef FILE_WRITE #define FILE_WRITE (sdfat::O_READ | sdfat::O_WRITE | sdfat::O_CREAT | sdfat::O_APPEND) + class SDClass { public: boolean begin(uint8_t csPin, SPISettings cfg = SPI_HALF_SPEED) { @@ -137,6 +138,17 @@ public: return ((uint64_t)clusterSize() * (uint64_t)totalClusters()); } + void setTimeCallback(time_t (*cb)(void)) { + SDFS.setTimeCallback(cb); + } + + // Wrapper to allow obsolete datetimecallback use, silently convert to time_t in wrappertimecb + void dateTimeCallback(void (*cb)(uint16_t*, uint16_t*)) { + extern void (*__SD__userDateTimeCB)(uint16_t*, uint16_t*); + __SD__userDateTimeCB = cb; + SDFS.setTimeCallback(wrapperTimeCB); + } + private: const char *getMode(uint8_t mode) { bool read = (mode & sdfat::O_READ) ? true : false; @@ -150,8 +162,46 @@ private: else { return "r"; } } + static time_t wrapperTimeCB(void) { + extern void (*__SD__userDateTimeCB)(uint16_t*, uint16_t*); + if (__SD__userDateTimeCB) { + uint16_t d, t; + __SD__userDateTimeCB(&d, &t); + return sdfs::SDFSImpl::FatToTimeT(d, t); + } + return time(nullptr); + } + }; + +// Expose FatStructs.h helpers for MSDOS date/time for use with dateTimeCallback +static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { + return (year - 1980) << 9 | month << 5 | day; +} +static inline uint16_t FAT_YEAR(uint16_t fatDate) { + return 1980 + (fatDate >> 9); +} +static inline uint8_t FAT_MONTH(uint16_t fatDate) { + return (fatDate >> 5) & 0XF; +} +static inline uint8_t FAT_DAY(uint16_t fatDate) { + return fatDate & 0X1F; +} +static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { + return hour << 11 | minute << 5 | second >> 1; +} +static inline uint8_t FAT_HOUR(uint16_t fatTime) { + return fatTime >> 11; +} +static inline uint8_t FAT_MINUTE(uint16_t fatTime) { + return (fatTime >> 5) & 0X3F; +} +static inline uint8_t FAT_SECOND(uint16_t fatTime) { + return 2*(fatTime & 0X1F); +} + + #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SD) extern SDClass SD; #endif diff --git a/libraries/SDFS/src/SDFS.h b/libraries/SDFS/src/SDFS.h index db55fe547..a884552ff 100644 --- a/libraries/SDFS/src/SDFS.h +++ b/libraries/SDFS/src/SDFS.h @@ -45,22 +45,9 @@ class SDFSDirImpl; class SDFSConfig : public FSConfig { public: - SDFSConfig() { - _type = SDFSConfig::fsid::FSId; - _autoFormat = false; - _csPin = 4; - _spiSettings = SD_SCK_MHZ(10); - _part = 0; - } - SDFSConfig(uint8_t csPin, SPISettings spi) { - _type = SDFSConfig::fsid::FSId; - _autoFormat = false; - _csPin = csPin; - _spiSettings = spi; - _part = 0; - } + static constexpr uint32_t FSId = 0x53444653; - enum fsid { FSId = 0x53444653 }; + SDFSConfig(uint8_t csPin = 4, SPISettings spi = SD_SCK_MHZ(10)) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi) { } SDFSConfig setAutoFormat(bool val = true) { _autoFormat = val; @@ -152,7 +139,7 @@ public: bool setConfig(const FSConfig &cfg) override { - if ((cfg._type != SDFSConfig::fsid::FSId) || _mounted) { + if ((cfg._type != SDFSConfig::FSId) || _mounted) { DEBUGV("SDFS::setConfig: invalid config or already mounted\n"); return false; } @@ -169,6 +156,7 @@ public: format(); _mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings); } + sdfat::SdFile::dateTimeCallback(dateTimeCB); return _mounted; } @@ -203,6 +191,31 @@ public: return (clusterSize() * totalClusters()); } + // Helper function, takes FAT and makes standard time_t + static time_t FatToTimeT(uint16_t d, uint16_t t) { + struct tm tiempo; + memset(&tiempo, 0, sizeof(tiempo)); + tiempo.tm_sec = (((int)t) << 1) & 0x3e; + tiempo.tm_min = (((int)t) >> 5) & 0x3f; + tiempo.tm_hour = (((int)t) >> 11) & 0x1f; + tiempo.tm_mday = (int)(d & 0x1f); + tiempo.tm_mon = ((int)(d >> 5) & 0x0f) - 1; + tiempo.tm_year = ((int)(d >> 9) & 0x7f) + 80; + tiempo.tm_isdst = -1; + return mktime(&tiempo); + } + + // Because SdFat has a single, global setting for this we can only use a + // static member of our class to return the time/date. However, since + // this is static, we can't see the time callback variable. Punt for now, + // using time(NULL) as the best we can do. + static void dateTimeCB(uint16_t *dosYear, uint16_t *dosTime) { + time_t now = time(nullptr); + struct tm *tiempo = localtime(&now); + *dosYear = ((tiempo->tm_year - 80) << 9) | ((tiempo->tm_mon + 1) << 5) | tiempo->tm_mday; + *dosTime = (tiempo->tm_hour << 11) | (tiempo->tm_min << 5) | tiempo->tm_sec; + } + protected: friend class SDFileImpl; friend class SDFSDirImpl; @@ -212,6 +225,7 @@ protected: return &_fs; } + static uint8_t _getFlags(OpenMode openMode, AccessMode accessMode) { uint8_t mode = 0; if (openMode & OM_CREATE) { @@ -350,6 +364,29 @@ public: return _opened ? _fd->isDirectory() : false; } + time_t getLastWrite() override { + time_t ftime = 0; + if (_opened && _fd) { + sdfat::dir_t tmp; + if (_fd.get()->dirEntry(&tmp)) { + ftime = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime); + } + } + return ftime; + } + + time_t getCreationTime() override { + time_t ftime = 0; + if (_opened && _fd) { + sdfat::dir_t tmp; + if (_fd.get()->dirEntry(&tmp)) { + ftime = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime); + } + } + return ftime; + } + + protected: SDFSImpl* _fs; @@ -404,6 +441,24 @@ public: return _size; } + time_t fileTime() override + { + if (!_valid) { + return 0; + } + + return _time; + } + + time_t fileCreationTime() override + { + if (!_valid) { + return 0; + } + + return _creation; + } + bool isFile() const override { return _valid ? _isFile : false; @@ -425,6 +480,14 @@ public: _size = file.fileSize(); _isFile = file.isFile(); _isDirectory = file.isDirectory(); + sdfat::dir_t tmp; + if (file.dirEntry(&tmp)) { + _time = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime); + _creation = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime); + } else { + _time = 0; + _creation = 0; + } file.getName(_lfn, sizeof(_lfn)); file.close(); } else { @@ -447,6 +510,8 @@ protected: std::shared_ptr _dir; bool _valid; char _lfn[64]; + time_t _time; + time_t _creation; std::shared_ptr _dirPath; uint32_t _size; bool _isFile; diff --git a/libraries/SPISlave/src/SPISlave.cpp b/libraries/SPISlave/src/SPISlave.cpp index a88915b51..3d58a8672 100644 --- a/libraries/SPISlave/src/SPISlave.cpp +++ b/libraries/SPISlave/src/SPISlave.cpp @@ -63,14 +63,17 @@ void SPISlaveClass::_s_status_tx(void *arg) { reinterpret_cast(arg)->_status_tx(); } - -void SPISlaveClass::begin() +void SPISlaveClass::begin() //backwards compatibility +{ + begin(4); +} +void SPISlaveClass::begin(uint8_t statusLength) { hspi_slave_onData(&_s_data_rx); hspi_slave_onDataSent(&_s_data_tx); hspi_slave_onStatus(&_s_status_rx); hspi_slave_onStatusSent(&_s_status_tx); - hspi_slave_begin(4, this); + hspi_slave_begin(statusLength, this); } void SPISlaveClass::end() { diff --git a/libraries/SPISlave/src/SPISlave.h b/libraries/SPISlave/src/SPISlave.h index a52495cf9..86b30875f 100644 --- a/libraries/SPISlave/src/SPISlave.h +++ b/libraries/SPISlave/src/SPISlave.h @@ -52,6 +52,7 @@ public: {} ~SPISlaveClass() {} void begin(); + void begin(uint8_t statusLength); void end(); void setData(uint8_t * data, size_t len); void setData(const char * data) diff --git a/libraries/SPISlave/src/hspi_slave.c b/libraries/SPISlave/src/hspi_slave.c index a2cbf9d46..c597e7aa8 100644 --- a/libraries/SPISlave/src/hspi_slave.c +++ b/libraries/SPISlave/src/hspi_slave.c @@ -72,11 +72,10 @@ void ICACHE_RAM_ATTR _hspi_slave_isr_handler(void *arg) void hspi_slave_begin(uint8_t status_len, void * arg) { - status_len &= 7; if(status_len > 4) { status_len = 4; //max 32 bits } - if(status_len == 0) { + else if(status_len == 0) { status_len = 1; //min 8 bits } @@ -85,7 +84,13 @@ void hspi_slave_begin(uint8_t status_len, void * arg) pinMode(MISO, SPECIAL); pinMode(MOSI, SPECIAL); - SPI1S = SPISE | SPISBE | 0x3E0; // SPI_SLAVE_REG + SPI1S = SPISE | SPISBE | SPISTRIE | SPISWBIE | SPISRSIE | SPISWSIE | SPISRBIE; //(0x63E0) + //setting config bits in SPI_SLAVE_REG, defined in "esp8266_peri.h" : + //SPISE - spi slave enable + //SPISBE - allows work (read/write) with buffer, without this only? status available + //SPISTRIE - enables TRANS?? interrupt + //other SPISxxIE - enables corresponding interrupts (read(R)/write(W) status(S) and buffer(B)) + SPI1U = SPIUMISOH | SPIUCOMMAND | SPIUSSE; // SPI_USER_REG SPI1CLK = 0; SPI1U2 = (7 << SPILCOMMAND); // SPI_USER2_REG diff --git a/libraries/Servo/src/Servo.h b/libraries/Servo/src/Servo.h index 6b19a477b..c9a381174 100644 --- a/libraries/Servo/src/Servo.h +++ b/libraries/Servo/src/Servo.h @@ -50,6 +50,7 @@ #define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached #define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds +#define MAX_SERVOS 12 #if !defined(ESP8266) diff --git a/libraries/SoftwareSerial b/libraries/SoftwareSerial index 8f85d6490..94b2388a4 160000 --- a/libraries/SoftwareSerial +++ b/libraries/SoftwareSerial @@ -1 +1 @@ -Subproject commit 8f85d649000b5bbdde1862d879dba4f225dd3a51 +Subproject commit 94b2388a4752f2b165371313f4d942daebff6eee diff --git a/libraries/Ticker/Ticker.h b/libraries/Ticker/Ticker.h deleted file mode 100644 index 074e5ba32..000000000 --- a/libraries/Ticker/Ticker.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - Ticker.h - esp8266 library that calls functions periodically - - Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef TICKER_H -#define TICKER_H - -#include -#include -#include - -class Ticker -{ -public: - Ticker(); - ~Ticker(); - - typedef void (*callback_with_arg_t)(void *); - typedef std::function callback_function_t; - - void attach_scheduled(float seconds, callback_function_t callback) - { - attach(seconds, [callback]() { schedule_function(callback); }); - } - - void attach(float seconds, callback_function_t callback) - { - _callback_function = std::move(callback); - _attach_s(seconds, true, _static_callback, this); - } - - void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback) - { - attach_ms(milliseconds, [callback]() { schedule_function(callback); }); - } - - void attach_ms(uint32_t milliseconds, callback_function_t callback) - { - _callback_function = std::move(callback); - _attach_ms(milliseconds, true, _static_callback, this); - } - - template - void attach(float seconds, void (*callback)(TArg), TArg arg) - { - static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - // C-cast serves two purposes: - // static_cast for smaller integer types, - // reinterpret_cast + const_cast for pointer types - _attach_s(seconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); - } - - template - void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) - { - static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - _attach_ms(milliseconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); - } - - void once_scheduled(float seconds, callback_function_t callback) - { - once(seconds, [callback]() { schedule_function(callback); }); - } - - void once(float seconds, callback_function_t callback) - { - _callback_function = std::move(callback); - _attach_s(seconds, false, _static_callback, this); - } - - void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback) - { - once_ms(milliseconds, [callback]() { schedule_function(callback); }); - } - - void once_ms(uint32_t milliseconds, callback_function_t callback) - { - _callback_function = std::move(callback); - _attach_ms(milliseconds, false, _static_callback, this); - } - - template - void once(float seconds, void (*callback)(TArg), TArg arg) - { - static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - _attach_s(seconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); - } - - template - void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) - { - static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); - _attach_ms(milliseconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); - } - - void detach(); - bool active() const; - -protected: - void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, void* arg); - static void _static_callback(void* arg); - - ETSTimer* _timer; - callback_function_t _callback_function = nullptr; - -private: - void _attach_s(float seconds, bool repeat, callback_with_arg_t callback, void* arg); - ETSTimer _etsTimer; -}; - - -#endif//TICKER_H diff --git a/libraries/Ticker/examples/TickerParameter/TickerParameter.ino b/libraries/Ticker/examples/TickerParameter/TickerParameter.ino index 80734a1a6..066905d09 100644 --- a/libraries/Ticker/examples/TickerParameter/TickerParameter.ino +++ b/libraries/Ticker/examples/TickerParameter/TickerParameter.ino @@ -13,9 +13,17 @@ #include -Ticker tickerSetHigh; -Ticker tickerSetAnalog; Ticker tickerSetLow; +Ticker tickerSetHigh; +Ticker tickerSetChar; + +void setPinLow() { + digitalWrite(LED_BUILTIN, 0); +} + +void setPinHigh() { + digitalWrite(LED_BUILTIN, 1); +} void setPin(int state) { digitalWrite(LED_BUILTIN, state); @@ -27,14 +35,15 @@ void setPinChar(char state) { void setup() { pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(1, LOW); - // every 25 ms, call setPin(0) - tickerSetLow.attach_ms(25, setPin, 0); + // every 25 ms, call setPinLow() + tickerSetLow.attach_ms(25, setPinLow); - // every 26 ms, call setPinChar(1) - tickerSetHigh.attach_ms(26, setPinChar, (char)1); + // every 26 ms, call setPinHigh() + tickerSetHigh.attach_ms(26, setPinHigh); + // every 54 ms, call setPinChar(1) + tickerSetChar.attach_ms(26, setPinChar, (char)1); } void loop() { diff --git a/libraries/Ticker/keywords.txt b/libraries/Ticker/keywords.txt index 1ecd8d0ed..ab0b07e03 100644 --- a/libraries/Ticker/keywords.txt +++ b/libraries/Ticker/keywords.txt @@ -1,11 +1,9 @@ -####################################### -# Syntax Coloring Map For Wire -####################################### - ####################################### # Datatypes (KEYWORD1) ####################################### +Ticker KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### @@ -16,14 +14,3 @@ once KEYWORD2 once_ms KEYWORD2 detach KEYWORD2 active KEYWORD2 - -####################################### -# Instances (KEYWORD2) -####################################### - -Ticker KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### - diff --git a/libraries/Ticker/Ticker.cpp b/libraries/Ticker/src/Ticker.cpp similarity index 65% rename from libraries/Ticker/Ticker.cpp rename to libraries/Ticker/src/Ticker.cpp index 35ec21cdc..dca4435dc 100644 --- a/libraries/Ticker/Ticker.cpp +++ b/libraries/Ticker/src/Ticker.cpp @@ -25,60 +25,47 @@ #include "Ticker.h" -namespace -{ - constexpr int ONCE = 0; - constexpr int REPEAT = 1; -} - Ticker::Ticker() - : _timer(nullptr) -{ -} + : _timer(nullptr) {} Ticker::~Ticker() { - detach(); -} - -void Ticker::_attach_s(float seconds, bool repeat, callback_with_arg_t callback, void* arg) -{ - _attach_ms(1000 * seconds, repeat, callback, arg); + detach(); } void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, void* arg) { - if (_timer) - { - os_timer_disarm(_timer); - } - else - { - _timer = &_etsTimer; - } + if (_timer) + { + os_timer_disarm(_timer); + } + else + { + _timer = &_etsTimer; + } - os_timer_setfn(_timer, callback, arg); - os_timer_arm(_timer, milliseconds, (repeat) ? REPEAT : ONCE); + os_timer_setfn(_timer, callback, arg); + os_timer_arm(_timer, milliseconds, repeat); } void Ticker::detach() { - if (!_timer) - return; + if (!_timer) + return; - os_timer_disarm(_timer); - _timer = nullptr; - _callback_function = nullptr; + os_timer_disarm(_timer); + _timer = nullptr; + _callback_function = nullptr; } bool Ticker::active() const { - return _timer; + return _timer; } void Ticker::_static_callback(void* arg) { - Ticker* _this = reinterpret_cast(arg); - if (_this && _this->_callback_function) - _this->_callback_function(); + Ticker* _this = reinterpret_cast(arg); + if (_this && _this->_callback_function) + _this->_callback_function(); } diff --git a/libraries/Ticker/src/Ticker.h b/libraries/Ticker/src/Ticker.h new file mode 100644 index 000000000..436a68ce8 --- /dev/null +++ b/libraries/Ticker/src/Ticker.h @@ -0,0 +1,133 @@ +/* + Ticker.h - esp8266 library that calls functions periodically + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef TICKER_H +#define TICKER_H + +#include +#include +#include + +class Ticker +{ +public: + Ticker(); + ~Ticker(); + + typedef void (*callback_with_arg_t)(void*); + typedef std::function callback_function_t; + + void attach_scheduled(float seconds, callback_function_t callback) + { + _callback_function = [callback]() { schedule_function(callback); }; + _attach_ms(1000UL * seconds, true); + } + + void attach(float seconds, callback_function_t callback) + { + _callback_function = std::move(callback); + _attach_ms(1000UL * seconds, true); + } + + void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback) + { + _callback_function = [callback]() { schedule_function(callback); }; + _attach_ms(milliseconds, true); + } + + void attach_ms(uint32_t milliseconds, callback_function_t callback) + { + _callback_function = std::move(callback); + _attach_ms(milliseconds, true); + } + + template + void attach(float seconds, void (*callback)(TArg), TArg arg) + { + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_ms(1000UL * seconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); + } + + template + void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) + { + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_ms(milliseconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); + } + + void once_scheduled(float seconds, callback_function_t callback) + { + _callback_function = [callback]() { schedule_function(callback); }; + _attach_ms(1000UL * seconds, false); + } + + void once(float seconds, callback_function_t callback) + { + _callback_function = std::move(callback); + _attach_ms(1000UL * seconds, false); + } + + void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback) + { + _callback_function = [callback]() { schedule_function(callback); }; + _attach_ms(milliseconds, false); + } + + void once_ms(uint32_t milliseconds, callback_function_t callback) + { + _callback_function = std::move(callback); + _attach_ms(milliseconds, false); + } + + template + void once(float seconds, void (*callback)(TArg), TArg arg) + { + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_ms(1000UL * seconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); + } + + template + void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) + { + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_ms(milliseconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); + } + + void detach(); + bool active() const; + +protected: + static void _static_callback(void* arg); + void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, void* arg); + void _attach_ms(uint32_t milliseconds, bool repeat) + { + _attach_ms(milliseconds, repeat, _static_callback, this); + } + + ETSTimer* _timer; + callback_function_t _callback_function = nullptr; + +private: + ETSTimer _etsTimer; +}; + + +#endif //TICKER_H diff --git a/libraries/esp8266/examples/CallBackList/CallBackGeneric.ino b/libraries/esp8266/examples/CallBackList/CallBackGeneric.ino new file mode 100644 index 000000000..ce4dac247 --- /dev/null +++ b/libraries/esp8266/examples/CallBackList/CallBackGeneric.ino @@ -0,0 +1,64 @@ +#include +#include +#include "CallBackList.h" + +using namespace experimental::CBListImplentation; + +class exampleClass { + public: + exampleClass() {}; + + using exCallBack = std::function; + using exHandler = CallBackList::CallBackHandler; + + CallBackList myHandlers; + + exHandler setHandler(exCallBack cb) { + return myHandlers.add(cb); + } + + void removeHandler(exHandler hnd) { + myHandlers.remove(hnd); + } + + void trigger(int t) { + myHandlers.execute(t); + } +}; + +exampleClass myExample; + +void cb1(int in) { + Serial.printf("Callback 1, in = %d\n", in); +} + +void cb2(int in) { + Serial.printf("Callback 2, in = %d\n", in); +} + +void cb3(int in, int s) { + Serial.printf("Callback 3, in = %d, s = %d\n", in, s); +} + +Ticker tk, tk2, tk3; +exampleClass::exHandler e1 = myExample.setHandler(cb1); +exampleClass::exHandler e2 = myExample.setHandler(cb2); +exampleClass::exHandler e3 = myExample.setHandler(std::bind(cb3, std::placeholders::_1, 10)); + +void setup() { + Serial.begin(115200); + + tk.attach_ms(2000, []() { + Serial.printf("trigger %d\n", (uint32_t)millis()); + myExample.trigger(millis()); + }); + tk2.once_ms(10000, []() { + myExample.removeHandler(e2); + }); + tk3.once_ms(20000, []() { + e3.reset(); + }); +} + +void loop() { +} diff --git a/libraries/esp8266/examples/CheckFlashCRC/CheckFlashCRC.ino b/libraries/esp8266/examples/CheckFlashCRC/CheckFlashCRC.ino new file mode 100644 index 000000000..b00194a46 --- /dev/null +++ b/libraries/esp8266/examples/CheckFlashCRC/CheckFlashCRC.ino @@ -0,0 +1,45 @@ +/* + Demonstrate CRC check passing and failing by simulating a bit flip in flash. + WARNING!!! You would never want to actually do this in a real application! + + Released to the Public Domain by Earle F. Philhower, III +*/ + +extern "C" { +#include "spi_flash.h" +} +// Artificially create a space in PROGMEM that fills multipe sectors so +// we can corrupt one without crashing the system +const int corruptme[SPI_FLASH_SEC_SIZE * 4] PROGMEM = { 0 }; + +void setup() { + Serial.begin(115200); + Serial.printf("Starting\n"); + Serial.printf("CRC check: %s\n", ESP.checkFlashCRC() ? "OK" : "ERROR"); + Serial.printf("...Corrupting a portion of flash in the array...\n"); + + uint32_t ptr = (uint32_t)corruptme; + // Find a page aligned spot inside the array + ptr += 2 * SPI_FLASH_SEC_SIZE; + ptr &= ~(SPI_FLASH_SEC_SIZE - 1); // Sectoralign + uint32_t sector = ((((uint32_t)ptr - 0x40200000) / SPI_FLASH_SEC_SIZE)); + + // Create a sector with 1 bit set (i.e. fake corruption) + uint32_t *space = (uint32_t*)calloc(SPI_FLASH_SEC_SIZE, 1); + space[42] = 64; + + // Write it into flash at the spot in question + spi_flash_erase_sector(sector); + spi_flash_write(sector * SPI_FLASH_SEC_SIZE, (uint32_t*)space, SPI_FLASH_SEC_SIZE); + Serial.printf("CRC check: %s\n", ESP.checkFlashCRC() ? "OK" : "ERROR"); + + Serial.printf("...Correcting the flash...\n"); + memset(space, 0, SPI_FLASH_SEC_SIZE); + spi_flash_erase_sector(sector); + spi_flash_write(sector * SPI_FLASH_SEC_SIZE, (uint32_t*)space, SPI_FLASH_SEC_SIZE); + Serial.printf("CRC check: %s\n", ESP.checkFlashCRC() ? "OK" : "ERROR"); +} + + +void loop() { +} diff --git a/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino new file mode 100644 index 000000000..7556c5882 --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/LowPowerDemo.ino @@ -0,0 +1,439 @@ +/* This example demonstrates the different low-power modes of the ESP8266 + + The initial setup was a WeMos D1 Mini with 3.3V connected to the 3V3 pin through a meter + so that it bypassed the on-board voltage regulator and USB chip. There's still about + 0.3 mA worth of leakage amperage due to the unpowered chips. These tests should work with + any module, although on-board components will affect the actual current measurement. + While the modem is turned on the amperage is > 67 mA or changing with a minimum value. + To verify the 20 uA Deep Sleep amperage the voltage regulator and USB chip were removed. + + This test series requires an active WiFi connection to illustrate two tests. If you + have problems with WiFi, uncomment the #define DEBUG for additional WiFi error messages. + The test requires a pushbutton switch connected between D3 and GND to advance the tests. + You'll also need to connect D0/GPIO16 to RST for the Deep Sleep tests. If you forget to + connect D0 to RST it will hang after the first Deep Sleep test. D0 is driven high during + Deep Sleep, so you should use a Schottky diode between D0 and RST if you want to use a + reset switch; connect the anode of the diode to RST, and the cathode to D0. + + Additionally, you can connect an LED from any free pin through a 1K ohm resistor to the + 3.3V supply, though preferably not the 3V3 pin on the module or it adds to the measured + amperage. When the LED blinks you can proceed to the next test. When the LED is lit + continuously it's connecting WiFi, and when it's off the CPU is asleep. The LED blinks + slowly when the tests are complete. Test progress can also be shown on the serial monitor. + + WiFi connections will be made over twice as fast if you can use a static IP address. + + This example is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This example is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this example; if not, write to the Free Software Foundation, Inc., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include +#include // crc32() +#include +#include // WiFiState structure details + +//#define DEBUG // prints WiFi connection info to serial, uncomment if you want WiFi messages +#ifdef DEBUG +#define DEBUG_PRINTLN(x) Serial.println(x) +#define DEBUG_PRINT(x) Serial.print(x) +#else +#define DEBUG_PRINTLN(x) +#define DEBUG_PRINT(x) +#endif + +#define WAKE_UP_PIN 0 // D3/GPIO0, can also force a serial flash upload with RESET +// you can use any GPIO for WAKE_UP_PIN except for D0/GPIO16 as it doesn't support interrupts + +// uncomment one of the two lines below for your LED connection (optional) +#define LED 5 // D1/GPIO5 external LED for modules with built-in LEDs so it doesn't add amperage +//#define LED 2 // D4/GPIO2 LED for ESP-01,07 modules; D4 is LED_BUILTIN on most other modules +// you can use LED_BUILTIN, but it adds to the measured amperage by 0.3mA to 6mA. + +ADC_MODE(ADC_VCC); // allows you to monitor the internal VCC level; it varies with WiFi load +// don't connect anything to the analog input pin(s)! + +// enter your WiFi configuration below +const char* AP_SSID = "SSID"; // your router's SSID here +const char* AP_PASS = "password"; // your router's password here +IPAddress staticIP(0, 0, 0, 0); // parameters below are for your static IP address, if used +IPAddress gateway(0, 0, 0, 0); +IPAddress subnet(0, 0, 0, 0); +IPAddress dns1(0, 0, 0, 0); +IPAddress dns2(0, 0, 0, 0); +uint32_t timeout = 30E3; // 30 second timeout on the WiFi connection + +//#define TESTPOINT // used to track the timing of several test cycles (optional) +#ifdef TESTPOINT +#define testPointPin 4 // D2/GPIO4, you can use any pin that supports interrupts +#define testPoint_HIGH digitalWrite(testPointPin, HIGH) +#define testPoint_LOW digitalWrite(testPointPin, LOW) +#else +#define testPoint_HIGH +#define testPoint_LOW +#endif + +// This structure is stored in RTC memory to save the WiFi state and reset count (number of Deep Sleeps), +// and it reconnects twice as fast as the first connection; it's used several places in this demo +struct nv_s { + WiFiState wss; // core's WiFi save state + + struct { + uint32_t crc32; + uint32_t rstCount; // stores the Deep Sleep reset count + // you can add anything else here that you want to save, must be 4-byte aligned + } rtcData; +}; + +static nv_s* nv = (nv_s*)RTC_USER_MEM; // user RTC RAM area + +uint32_t resetCount = 0; // keeps track of the number of Deep Sleep tests / resets + +const uint32_t blinkDelay = 100; // fast blink rate for the LED when waiting for the user +esp8266::polledTimeout::periodicMs blinkLED(blinkDelay); // LED blink delay without delay() +esp8266::polledTimeout::oneShotMs altDelay(blinkDelay); // tight loop to simulate user code +esp8266::polledTimeout::oneShotMs wifiTimeout(timeout); // 30 second timeout on WiFi connection +// use fully qualified type and avoid importing all ::esp8266 namespace to the global namespace + +void wakeupCallback() { // unlike ISRs, you can do a print() from a callback function + testPoint_LOW; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW + printMillis(); // show time difference across sleep; millis is wrong as the CPU eventually stops + Serial.println(F("Woke from Light Sleep - this is the callback")); +} + +void setup() { +#ifdef TESTPOINT + pinMode(testPointPin, OUTPUT); // test point for Light Sleep and Deep Sleep tests + testPoint_LOW; // Deep Sleep reset doesn't clear GPIOs, testPoint LOW shows boot time +#endif + pinMode(LED, OUTPUT); // activity and status indicator + digitalWrite(LED, LOW); // turn on the LED + pinMode(WAKE_UP_PIN, INPUT_PULLUP); // polled to advance tests, interrupt for Forced Light Sleep + Serial.begin(115200); + Serial.println(); + Serial.print(F("\nReset reason = ")); + String resetCause = ESP.getResetReason(); + Serial.println(resetCause); + resetCount = 0; + if ((resetCause == "External System") || (resetCause == "Power on")) { + Serial.println(F("I'm awake and starting the Low Power tests")); + } + + // Read previous resets (Deep Sleeps) from RTC memory, if any + uint32_t crcOfData = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); + if ((crcOfData = nv->rtcData.crc32) && (resetCause == "Deep-Sleep Wake")) { + resetCount = nv->rtcData.rstCount; // read the previous reset count + resetCount++; + } + nv->rtcData.rstCount = resetCount; // update the reset count & CRC + updateRTCcrc(); + + if (resetCount == 1) { // show that millis() is cleared across the Deep Sleep reset + printMillis(); + } +} // end of setup() + +void loop() { + if (resetCount == 0) { // if first loop() since power on or external reset + runTest1(); + runTest2(); + runTest3(); + runTest4(); + runTest5(); + runTest6(); + runTest7(); // first Deep Sleep test, all these end with a RESET + } + if (resetCount < 4) { + initWiFi(); // optional re-init of WiFi for the Deep Sleep tests + } + if (resetCount == 1) { + runTest8(); + } else if (resetCount == 2) { + runTest9(); + } else if (resetCount == 3) { + runTest10(); + } else if (resetCount == 4) { + resetTests(); + } +} //end of loop() + +void runTest1() { + Serial.println(F("\n1st test - running with WiFi unconfigured")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); +} + +void runTest2() { + Serial.println(F("\n2nd test - Automatic Modem Sleep")); + Serial.println(F("connecting WiFi, please wait until the LED blinks")); + initWiFi(); + if (WiFi.localIP()) { // won't go into Automatic Sleep without an active WiFi connection + Serial.println(F("The amperage will drop in 7 seconds.")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(true, 90); /* This is using a special feature: below 100 mS blink delay, + the LED blink delay is padding 100 mS time with 'program cycles' to fill the 100 mS. + At 90 mS delay, 90% of the blink time is delay(), and 10% is 'your program running'. + Below 90% you'll see a difference in the average amperage: less delay() = more amperage. + At 100 mS and above it's essentially all delay() time. On an oscilloscope you'll see the + time between beacons at > 67 mA more often with less delay() percentage. You can change + the '90' mS to other values to see the effect it has on Automatic Modem Sleep. */ + } else { + Serial.println(F("no WiFi connection, test skipped")); + } +} + +void runTest3() { + Serial.println(F("\n3rd test - Forced Modem Sleep")); + WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // shut the modem down and save the WiFi state for faster reconnection + // WiFi.forceSleepBegin(delay_in_uS); // alternate method of Forced Modem Sleep for an optional timed shutdown, + // with WiFi.forceSleepBegin(0xFFFFFFF); the modem sleeps until you wake it, with values <= 0xFFFFFFE it's timed + // delay(10); // it doesn't always go to sleep unless you delay(10); yield() wasn't reliable + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(true, 99); /* Using the same < 100 mS feature. If you drop the delay below 100, you + will see the effect of program time vs. delay() time on minimum amperage. Above ~ 97 (97% of the + time in delay) there is little change in amperage, so you need to spend maximum time in delay() + to get minimum amperage.*/ +} + +void runTest4() { + Serial.println(F("\n4th test - Automatic Light Sleep")); + Serial.println(F("reconnecting WiFi with forceSleepWake")); + Serial.println(F("Automatic Light Sleep begins after WiFi connects (LED blinks)")); + // on successive loops after power-on, WiFi shows 'connected' several seconds before Sleep happens + // and WiFi reconnects after the forceSleepWake more quickly + digitalWrite(LED, LOW); // visual cue that we're reconnecting WiFi + uint32_t wifiBegin = millis(); + WiFi.forceSleepWake(); // reconnect with previous STA mode and connection settings + WiFi.setSleepMode(WIFI_LIGHT_SLEEP, 3); // Automatic Light Sleep, DTIM listen interval = 3 + // at higher DTIM intervals you'll have a hard time establishing and maintaining a connection + wifiTimeout.reset(timeout); + while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (!wifiTimeout)) { + yield(); + } + if ((WiFi.status() == WL_CONNECTED) && WiFi.localIP()) { + // won't go into Automatic Sleep without an active WiFi connection + float reConn = (millis() - wifiBegin); + Serial.print(F("WiFi connect time = ")); + Serial.printf("%1.2f seconds\n", reConn / 1000); + readVoltage(); // read internal VCC + Serial.println(F("long press of the switch to continue")); + waitPushbutton(true, 350); /* Below 100 mS delay it only goes into 'Automatic Modem Sleep', + and below ~ 350 mS delay() the 'Automatic Light Sleep' is less frequent. Above 500 mS + delay() doesn't make significant improvement in power savings. */ + } else { + Serial.println(F("no WiFi connection, test skipped")); + } +} + +void runTest5() { + Serial.println(F("\n5th test - Timed Light Sleep, wake in 10 seconds")); + Serial.println(F("Press the button when you're ready to proceed")); + waitPushbutton(true, blinkDelay); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + readVoltage(); // read internal VCC + printMillis(); // show millis() across sleep, including Serial.flush() + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running + testPoint_HIGH; // testPoint LOW in callback tracks delay from testPoint HIGH to LOW + extern os_timer_t *timer_list; + timer_list = nullptr; // stop (but don't disable) the 4 OS timers + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); // GPIO wakeup (optional) + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation + wifi_fpm_set_wakeup_cb(wakeupCallback); // set wakeup callback + // the callback is optional, but without it the modem will wake in 10 seconds then delay(10 seconds) + // with the callback the sleep time is only 10 seconds total, no extra delay() afterward + wifi_fpm_open(); + wifi_fpm_do_sleep(10E6); // Sleep range = 10000 ~ 268,435,454 uS (0xFFFFFFE, 2^28-1) + delay(10e3 + 1); // delay needs to be 1 mS longer than sleep or it only goes into Modem Sleep + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed +} + +void runTest6() { + Serial.println(F("\n6th test - Forced Light Sleep, wake with GPIO interrupt")); + Serial.flush(); + WiFi.mode(WIFI_OFF); // you must turn the modem off; using disconnect won't work + digitalWrite(LED, HIGH); // turn the LED off so they know the CPU isn't running + readVoltage(); // read internal VCC + Serial.println(F("CPU going to sleep, pull WAKE_UP_PIN low to wake it (press the switch)")); + printMillis(); // show millis() across sleep, including Serial.flush() + testPoint_HIGH; // testPoint tracks latency from WAKE_UP_PIN LOW to testPoint LOW in callback + wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); + gpio_pin_wakeup_enable(GPIO_ID_PIN(WAKE_UP_PIN), GPIO_PIN_INTR_LOLEVEL); + // only LOLEVEL or HILEVEL interrupts work, no edge, that's an SDK or CPU limitation + wifi_fpm_set_wakeup_cb(wakeupCallback); // Set wakeup callback (optional) + wifi_fpm_open(); + wifi_fpm_do_sleep(0xFFFFFFF); // only 0xFFFFFFF, any other value and it won't disconnect the RTC timer + delay(10); // it goes to sleep during this delay() and waits for an interrupt + Serial.println(F("Woke up!")); // the interrupt callback hits before this is executed*/ +} + +void runTest7() { + Serial.println(F("\n7th test - Deep Sleep for 10 seconds, reset and wake with RF_DEFAULT")); + initWiFi(); // initialize WiFi since we turned it off in the last test + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + while (!digitalRead(WAKE_UP_PIN)) { // wait for them to release the switch from the previous test + delay(10); + } + delay(50); // debounce time for the switch, pushbutton released + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + digitalWrite(LED, LOW); // turn the LED on, at least briefly + //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, + // and no extended RFCAL as it goes into Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + printMillis(); // show time difference across sleep + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleep(10E6, WAKE_RF_DEFAULT); // good night! D0 fires a reset in 10 seconds... + // if you do ESP.deepSleep(0, mode); it needs a RESET to come out of sleep (RTC is disconnected) + // maximum timed Deep Sleep interval ~ 3 to 4 hours depending on the RTC timer, see the README + // the 2 uA GPIO amperage during Deep Sleep can't drive the LED so it's not lit now, although + // depending on the LED used, you might see it very dimly lit in a dark room during this test + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void runTest8() { + Serial.println(F("\n8th test - in RF_DEFAULT, Deep Sleep for 10 seconds, reset and wake with RFCAL")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep, + // and no extended RFCAL as it goes into Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleep(10E6, WAKE_RFCAL); // good night! D0 fires a reset in 10 seconds... + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void runTest9() { + Serial.println(F("\n9th test - in RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with NO_RFCAL")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + WiFi.mode(WIFI_SHUTDOWN, &nv->wss); // Forced Modem Sleep for a more Instant Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleepInstant(10E6, WAKE_NO_RFCAL); // good night! D0 fires a reset in 10 seconds... + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void runTest10() { + Serial.println(F("\n10th test - in NO_RFCAL, Deep Sleep Instant for 10 seconds, reset and wake with RF_DISABLED")); + readVoltage(); // read internal VCC + Serial.println(F("press the switch to continue")); + waitPushbutton(false, blinkDelay); // set true if you want to see Automatic Modem Sleep + //WiFi.mode(WIFI_SHUTDOWN); // Forced Modem Sleep for a more Instant Deep Sleep + Serial.println(F("going into Deep Sleep now...")); + Serial.flush(); // needs a delay(10) or Serial.flush() else it doesn't print the whole message + testPoint_HIGH; // testPoint set HIGH to track Deep Sleep period, cleared at startup() + ESP.deepSleepInstant(10E6, WAKE_RF_DISABLED); // good night! D0 fires a reset in 10 seconds... + Serial.println(F("What... I'm not asleep?!?")); // it will never get here +} + +void resetTests() { + readVoltage(); // read internal VCC + Serial.println(F("\nTests completed, in RF_DISABLED, press the switch to do an ESP.restart()")); + memset(&nv->wss, 0, sizeof(nv->wss) * 2); // wipe saved WiFi states, comment this if you want to keep them + waitPushbutton(false, 1000); + ESP.restart(); +} + +void waitPushbutton(bool usesDelay, unsigned int delayTime) { // loop until they press the switch + // note: 2 different modes, as 3 of the power saving modes need a delay() to activate fully + if (!usesDelay) { // quick interception of pushbutton press, no delay() used + blinkLED.reset(delayTime); + while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press + if (blinkLED) { + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + } + yield(); // this would be a good place for ArduinoOTA.handle(); + } + } else { // long delay() for the 3 modes that need it, but it misses quick switch presses + while (digitalRead(WAKE_UP_PIN)) { // wait for a pushbutton press + digitalWrite(LED, !digitalRead(LED)); // toggle the activity LED + delay(delayTime); // another good place for ArduinoOTA.handle(); + if (delayTime < 100) { + altDelay.reset(100 - delayTime); // pad the time < 100 mS with some real CPU cycles + while (!altDelay) { // this simulates 'your program running', not delay() time + } + } + } + } + delay(50); // debounce time for the switch, pushbutton pressed + while (!digitalRead(WAKE_UP_PIN)) { // now wait for them to release the pushbutton + delay(10); + } + delay(50); // debounce time for the switch, pushbutton released +} + +void readVoltage() { // read internal VCC + float volts = ESP.getVcc(); + Serial.printf("The internal VCC reads %1.2f volts\n", volts / 1000); +} + +void printMillis() { + Serial.print(F("millis() = ")); // show that millis() isn't correct across most Sleep modes + Serial.println(millis()); + Serial.flush(); // needs a Serial.flush() else it may not print the whole message before sleeping +} + +void updateRTCcrc() { // updates the reset count CRC + nv->rtcData.crc32 = crc32((uint8_t*) &nv->rtcData.rstCount, sizeof(nv->rtcData.rstCount)); +} + +void initWiFi() { + digitalWrite(LED, LOW); // give a visual indication that we're alive but busy with WiFi + uint32_t wifiBegin = millis(); // how long does it take to connect + if ((crc32((uint8_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)) && !WiFi.shutdownValidCRC(&nv->wss))) { + // if good copy of wss, overwrite invalid (primary) copy + memcpy((uint32_t*) &nv->wss, (uint32_t*) &nv->rtcData.rstCount + 1, sizeof(nv->wss)); + } + if (WiFi.shutdownValidCRC(&nv->wss)) { // if we have a valid WiFi saved state + memcpy((uint32_t*) &nv->rtcData.rstCount + 1, (uint32_t*) &nv->wss, sizeof(nv->wss)); // save a copy of it + Serial.println(F("resuming WiFi")); + } + if (!(WiFi.mode(WIFI_RESUME, &nv->wss))) { // couldn't resume, or no valid saved WiFi state yet + /* Explicitly set the ESP8266 as a WiFi-client (STAtion mode), otherwise by default it + would try to act as both a client and an access-point and could cause network issues + with other WiFi devices on your network. */ + WiFi.persistent(false); // don't store the connection each time to save wear on the flash + WiFi.mode(WIFI_STA); + WiFi.setOutputPower(10); // reduce RF output power, increase if it won't connect + WiFi.config(staticIP, gateway, subnet); // if using static IP, enter parameters at the top + WiFi.begin(AP_SSID, AP_PASS); + Serial.print(F("connecting to WiFi ")); + Serial.println(AP_SSID); + DEBUG_PRINT(F("my MAC: ")); + DEBUG_PRINTLN(WiFi.macAddress()); + } + wifiTimeout.reset(timeout); + while (((!WiFi.localIP()) || (WiFi.status() != WL_CONNECTED)) && (!wifiTimeout)) { + yield(); + } + if ((WiFi.status() == WL_CONNECTED) && WiFi.localIP()) { + DEBUG_PRINTLN(F("WiFi connected")); + Serial.print(F("WiFi connect time = ")); + float reConn = (millis() - wifiBegin); + Serial.printf("%1.2f seconds\n", reConn / 1000); + DEBUG_PRINT(F("WiFi Gateway IP: ")); + DEBUG_PRINTLN(WiFi.gatewayIP()); + DEBUG_PRINT(F("my IP address: ")); + DEBUG_PRINTLN(WiFi.localIP()); + } else { + Serial.println(F("WiFi timed out and didn't connect")); + } + WiFi.setAutoReconnect(true); +} diff --git a/libraries/esp8266/examples/LowPowerDemo/README.md b/libraries/esp8266/examples/LowPowerDemo/README.md new file mode 100644 index 000000000..f08034811 --- /dev/null +++ b/libraries/esp8266/examples/LowPowerDemo/README.md @@ -0,0 +1,125 @@ +#
Low-Power Demo
+ +There is a lot of confusion, out-of-date information, and poor or non-working examples of how to use the 5 basic low-power modes of the ESP8266. This demo code shows you how to use them reliably. If you're here for very low power, then the 2 Light Sleep modes and Deep Sleep are what you want. + +The two relevant reference manuals from Espressif are the [Low-Power Solutions](https://www.espressif.com/sites/default/files/documentation/9b-esp8266-low_power_solutions__en.pdf) and the [Non-OS SDK API Reference](https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf). There is more information in the two PDFs than is presented here, so you'll want both of them for your reference. + + +The table below is an expanded version of Table 1.1 from the Low-Power Solutions PDF. The amperages listed are absolute minimums, and most people will not get that low with typical hardware and programs. + +| item | Automatic Modem Sleep | Forced Modem Sleep | Automatic Light Sleep | Timed / Forced Light Sleep | Forced Deep Sleep | +|:---------------------:|:---------------------:|:------------------:|:---------------------:|:------------------:|:------------------:| +| WiFi connectivity | Connected | Disconnected | Connected | Disconnected | Disconnected | +| GPIO state | Unchanged | Unchanged | Unchanged | Unchanged | Low amperage (2 uA) | +| WiFi | ON | OFF | ON | OFF | OFF | +| System Clock | ON | ON | CYCLING | OFF | OFF | +| RTC | ON | ON | ON | ON (1) | ON (2) | +| CPU | ON | ON | ON | ON | OFF | +| Substrate Amperage | 15 mA | 15 mA | 1-15 mA (3) | 0.4 mA | 20 uA | +| Avg Amperage DTIM = 1 | 16.2 mA | | (1.8 mA) | | | +| Avg Amperage DTIM = 3 | 15.4 mA | | (0.9 mA) | | | +| Avg Amperage DTIM = 10 | 15.2 mA | | (0.55 mA) | | | + +Notes: + +(1) setting a sleep time of 0xFFFFFFF for Light Sleep disconnects the RTC, requiring a GPIO interrupt to wake the CPU + +(2) setting a sleep time of 0 for Deep Sleep disconnects the RTC, requiring an external RESET to wake the CPU + +(3) minimum amperage was never measured less than ~ 1 mA and is frequently 15 mA between TIM beacons + +The Average Amperage with different DTIM settings is unverified, and will likely be higher in a real-world environment. All of the amperages listed in this README are for the ESP8266 chip only, compiled for 80 MHz CPU Frequency as 160 MHz uses even more power. Modules that have voltage regulators, USB chips, LEDs or other hardware will draw additional amperage. + +--- + +## Basic Tests in the Demo + +1. Unconfigured modem +2. Automatic Modem Sleep +3. Forced Modem Sleep +4. Automatic Light Sleep +5. Timed Light Sleep - stop the CPU for (x microseconds) +6. Forced Light Sleep, wake with GPIO interrupt +7. Deep Sleep for 10 seconds, wake with default modem power settings +8. Deep Sleep for 10 seconds, wake with RFCAL +9. Deep Sleep Instant for 10 seconds, wake with NO_RFCAL +10. Deep Sleep Instant for 10 seconds, wake with RF_DISABLED + +--- + +### Test 1 - Unconfigured modem + +This is typical for programs that don't use WiFi, and is a high continuous drain of at least 67 mA. This isn't a test as much as setting a baseline or reference point for comparing the power savings. You can stop during any test while the CPU is halted or the LED is blinking to measure the amperage. + +### Test 2 - Automatic Modem Sleep + +This is the default power saving mode when you have an active WiFi connection. You don't need to add anything to your code to get this mode. The only time the modem sleeps is when your program spends time in delay() frequently in STA mode. Any delay() time works as long as it happens frequently. The test is doing **delay(100)** to get the modem to sleep. While in delay() your sketch isn't doing anything worthwhile. Amperage during Automatic Modem Sleep is 15 mA minimum. Without a delay() the amperage is > 67 mA with brief spikes > 250-350 mA as transmissions occur. When the WiFi has traffic (even a couple of pings), the modem can turn on for over 2 seconds continuous at 67 mA, and it may stay on for a second after the traffic. In a high traffic environment you won't get any power savings with either of the 2 Automatic modes. Automatic Modem Sleep turns on 7-8 seconds after an active connection is established. + +### Test 3 - Forced Modem Sleep + +Turns off the modem (losing the connection), and reducing the amperage by > 50 mA. This test uses a WiFi library function and saves the WiFi connection state for faster reconnection later in the tests. Forced Modem Sleep is good if there is a long interval with no expected WiFi traffic, as you can do other things while only drawing 15 to 20 mA. The longer you spend in delay(), the closer the amperage approaches 15 mA. The test loops on delay(100) until you press the button. The CPU will be drawing 15 to 16 mA during the looped delay(), and 19-20 mA without a delay(). Doing WiFi.forceSleepWake() to wake the modem later can take twice as long as a re-initialize of WiFi. + +### Test 4 - Automatic Light Sleep + +Like Automatic Modem Sleep, with similar restrictions. Once configured it's immediately active when a connection is established. During periods of long delay() the amperage can drop to ~ 2 mA average. In a network with sparse traffic you might get something near 2-5 mA average. The LED blinks more slowly during this test as it's doing delay(350) to get the modem to sleep. With delay() times shorter than the TIM beacon interval (100 mS beacons for these tests) the modem only goes into Automatic Modem Sleep, and with a longer delay() it will go more fully into Automatic Light Sleep. Although the CPU clock is cycling on and off to achieve low power, millis() and micros() are correct. You can't stop OS_timers to get the low amperage recorded by Espressif as WiFi needs system timers running. + +### Test 5 - Timed Light Sleep + +Similar to timed Deep Sleep, but it wakes with an interrupt at the next line in your code and continues. The chip sleeps at 0.4 mA amperage until it is woken by the RTC timer. If you have a design that needs to be woken more often than every 2 seconds then you should consider using Timed Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter timed Light Sleep so you will need to re-initialize it if you are using WiFi. Any timers (including OS_timers and PWM) will keep the chip from going into timed Light Sleep, and it will fall through to the next line in your code if any timers are running. If you do a print() before Sleep, be sure to do Serial.flush() to stop the UART. The interrupt callback is recommended, and you can set a optional GPIO interrupt to wake the CPU as well as the RTC timer. + +### Test 6 - Forced Light Sleep, wake with GPIO interrupt + +Similar to ESP.deepSleep(0). The chip sleeps at 0.4 mA amperage until it is woken by an external interrupt. The only allowed interrupts are high level and low level; edge interrupts won't work. If you have a design that needs to be woken more often than every 2 seconds then you should consider using Forced Light Sleep. For sleep periods longer than 2 seconds, Deep Sleep will be more energy efficient. The chip wakes after an interrupt in about 3 to 5.5 mS (regardless of CPU speed), but WiFi was turned off to enter Forced Light Sleep so you will need to re-initialize it if you are using WiFi. Any user timers (including PWM) will keep the chip from going fully into Forced Light Sleep, and amperage will be ~ 2 mA with timers enabled. + +### Test 7 - Deep Sleep, wake with RF_DEFAULT + +In Deep Sleep almost everything is turned off, and the chip draws ~ 20 uA. If you have D0/GPIO16 connected to RST, you can use the RTC timer to wake the chip up at a timed interval. You can also wake it solely with an external RESET with ESP.deepSleep(0, wake option), which disconnects the timer. Waking with RF_DEFAULT means it will do an RFCAL if it needs to. Doing **ESP.deepSleep(time)** without the mode variable uses this wake mode. These first two Deep Sleep tests use the standard Deep Sleep function, so the WiFi connection is closed and the modem turned off, which takes up to 270 mS before Deep Sleep begins. Deep Sleep ends with a RESET, and the boot time after that is ~ 130 mS. Any Deep Sleep less than 2 seconds is wasting energy due to the modem shut-off and boot times, and Forced Light Sleep will be a better choice as it recovers in < 5.5 mS from the previous program state. The Deep Sleep tests will not go into Automatic Modem Sleep because delay() is not used. + +Note that a RESET during Deep Sleep (either external or from D0/GPIO16) does not clear the GPIO pins; some of them hold their previous state. It's unknown how much else survives a reset, as it's not well documented. + +### Test 8 - Deep Sleep, wake with RFCAL + +Identical to the test above, but the modem always does an RF power calibration when booting. In normal use, most people would do WAKE_RF_DEFAULT instead to avoid the extra RFCAL power burst coming out of Deep Sleep if it's not needed. Note that most of the time both of these modes (WAKE_RF_DEFAULT and WAKE_RFCAL) do a 100 mS long RFCAL *before* going into Deep Sleep (the RFCAL after Deep Sleep is much shorter). If the modem is shut down, this long RFCAL doesn't happen. + +### Test 9 - Deep Sleep Instant, wake with NO_RFCAL + +This variation doesn't do an RF calibration on return, so power requirements will be slightly less. Additionally, frequently it immediately goes into Deep Sleep without turning off the modem (that's the INSTANT part). There's another bug in SDK 2, and the SDK functions the WiFi-class calls occasionally do a modem shut-down before Deep Sleep; it's not always Instant. When it doesn't do the modem shut-down it saves an extra 270 mS of power. With the modem turned off (Forced Modem Sleep) you **always** get an instant Deep Sleep; doing WiFi.mode(WIFI_OFF) doesn't help, as the SDK still spends 270 mS of time shutting the modem down before going into Deep Sleep. + +### Test 10 - Deep Sleep Instant, wake with RF_DISABLED + +This last variation also uses Deep Sleep Instant, but it wakes up with the modem disabled so amperage after Deep Sleep is only 15 mA. Each of the 4 WAKE modes has their own use, depending on what you need. + +--- + +All of the Deep Sleep modes end with a RESET, so you must re-initialize nearly everything. You can store *some* information in the RTC memory to survive a Deep Sleep reset, which was done in this demo to illustrate the RTC memory. See the **RTCUserMemory** and **WiFiShutdown** examples for more on this feature. + +Since SDK 2.1 the maximum Deep Sleep time has changed. The old maximum was based on uint32_t(micros) or ~71.58 minutes (2^32-1 microseconds). The new maximum is calculated from the RTC clock, which drifts with temperature from 5 to 7 timer ticks per microsecond, and will return a different number each time you read **system_rtc_clock_cali_proc()**. Depending on CPU and temperature, you will get between 3 and 4 hours maximum Deep Sleep. You can read the current theoretical maximum with **uint64_t deepSleepMax = ESP.deepSleepMax();** although you should set your time a little less than that due to the RTC drift. If you go over the maximum time when you finally enter Deep Sleep, it disconnects the timer and won't wake without an external RESET. + +If you need a longer sleep time than 3 hours, you can pass zero as the time variable to Deep Sleep and it disconnects the RTC. The only way to wake it at that point is an external RESET; D0 can't do it. Both Forced Light Sleep and Deep Sleep(0) are woken by an external signal, so short delays are more efficient with Forced Light Sleep, and longer delays are more energy efficient with Deep Sleep. + + +--- + +### Lower Power without the WiFi library (Forced Modem Sleep): + +If all you want to do is reduce power for a sketch that doesn't need WiFi, add these SDK 2 functions to your code: + +At the top of your program, add: +```c +#include +``` + +and in setup() add: +```c + wifi_set_opmode_current(NULL_MODE); // set Wi-Fi working mode to unconfigured, don't save to flash + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); // set the sleep type to modem sleep + wifi_fpm_open(); // enable Forced Modem Sleep + wifi_fpm_do_sleep(0xFFFFFFF); // force the modem to enter sleep mode + delay(10); // without a minimum of delay(1) here it doesn't reliably enter sleep +``` +This code allows you to shut down the modem *without* loading the WiFi library, dropping your amperage by > 50 mA, or ~ 1/4th of the initial power. It doesn't time out at 268 seconds, as you might think from the (0xFFFFFFF). If you put a delay value smaller than 0xFFFFFFF it will end Modem Sleep at the number of uS you have entered: 10E6 would be 10 seconds of Modem Sleep. The Forced Modem Sleep test does the same thing with a WiFi library call that encapsulates something similar to the code above. + +If you want to reduce the start-up power even more, see https://github.com/esp8266/Arduino/issues/6642#issuecomment-578462867 + +You can also use the Deep Sleep modes without loading the WiFi library, as Deep Sleep use ESP API functions. The Deep Sleep tests above turn the WiFi on to show you the differences after the 4 reset modes. but WiFi is not required for Deep Sleep. + diff --git a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino index fe713e02d..33cd14603 100644 --- a/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino +++ b/libraries/esp8266/examples/NTP-TZ-DST/NTP-TZ-DST.ino @@ -85,6 +85,16 @@ static bool time_machine_running = false; // return 15000; // 15s //} +#define PTM(w) \ + Serial.print(" " #w "="); \ + Serial.print(tm->tm_##w); + +void printTm(const char* what, const tm* tm) { + Serial.print(what); + PTM(isdst); PTM(yday); PTM(wday); + PTM(year); PTM(mon); PTM(mday); + PTM(hour); PTM(min); PTM(sec); +} void showTime() { gettimeofday(&tv, nullptr); @@ -124,13 +134,14 @@ void showTime() { Serial.println((uint32_t)now); // timezone and demo in the future - Serial.printf("timezone: %s\n", MYTZ); + Serial.printf("timezone: %s\n", getenv("TZ")); // human readable Serial.print("ctime: "); Serial.print(ctime(&now)); #if LWIP_VERSION_MAJOR > 1 + // LwIP v2 is able to list more details about the currently configured SNTP servers for (int i = 0; i < SNTP_MAX_SERVERS; i++) { IPAddress sntp = *sntp_getserver(i); @@ -152,18 +163,6 @@ void showTime() { Serial.println(); } - -#define PTM(w) \ - Serial.print(" " #w "="); \ - Serial.print(tm->tm_##w); - -void printTm(const char* what, const tm* tm) { - Serial.print(what); - PTM(isdst); PTM(yday); PTM(wday); - PTM(year); PTM(mon); PTM(mday); - PTM(hour); PTM(min); PTM(sec); -} - void time_is_set_scheduled() { // everything is allowed in this function @@ -205,8 +204,7 @@ void setup() { // it will be used until NTP server will send us real current time time_t rtc = RTC_UTC_TEST; timeval tv = { rtc, 0 }; - timezone tz = { 0, 0 }; - settimeofday(&tv, &tz); + settimeofday(&tv, nullptr); // install callback - called when settimeofday is called (by SNTP or us) // once enabled (by DHCP), SNTP is updated every hour @@ -214,8 +212,18 @@ void setup() { // NTP servers may be overriden by your DHCP server for a more local one // (see below) + + // ----> Here is the ONLY ONE LINE needed in your sketch + configTime(MYTZ, "pool.ntp.org"); + // Here is the ONLY ONE LINE needed in your sketch <---- + // pick a value from TZ.h (search for this file in your filesystem) for MYTZ + + // former configTime is still valid, here is the call for 7 hours to the west + // with an enabled 30mn DST + //configTime(7 * 3600, 3600 / 2, "pool.ntp.org"); + // OPTIONAL: disable obtaining SNTP servers from DHCP //sntp_servermode_dhcp(0); // 0: disable obtaining SNTP servers from DHCP (enabled by default) diff --git a/libraries/esp8266/examples/SerialStress/SerialStress.ino b/libraries/esp8266/examples/SerialStress/SerialStress.ino index 5500b10a6..1412abd2b 100644 --- a/libraries/esp8266/examples/SerialStress/SerialStress.ino +++ b/libraries/esp8266/examples/SerialStress/SerialStress.ino @@ -72,8 +72,8 @@ void setup() { // using HardwareSerial0 pins, // so we can still log to the regular usbserial chips - SoftwareSerial* ss = new SoftwareSerial; - ss->begin(SSBAUD, 3, 1); + SoftwareSerial* ss = new SoftwareSerial(3, 1); + ss->begin(SSBAUD); ss->enableIntTx(false); logger = ss; logger->println(); diff --git a/package.json b/package.json index 13dfbedf2..5ad2898f7 100644 --- a/package.json +++ b/package.json @@ -2,5 +2,5 @@ "name": "framework-arduinoespressif8266", "description": "Arduino Wiring-based Framework (ESP8266 Core)", "url": "https://github.com/esp8266/Arduino", - "version": "2.5.0-dev" + "version": "2.7.0-dev" } diff --git a/package/README.md b/package/README.md index 84b905913..76157a420 100644 --- a/package/README.md +++ b/package/README.md @@ -109,7 +109,7 @@ The following points assume work in a direct clone of the repository, and not in 2. Make a PR with the following, wait for Travis CI, and merge. - * platform.txt: update `version` to the release E.g. `3.0.0`, + * platform.txt and package.json: update `version` to the release E.g. `3.0.0`, * `cores/esp8266/TZ.h`: import the latest database with the following shell command:\ `$ cd tools; sh TZupdate.sh`. @@ -120,7 +120,9 @@ The following points assume work in a direct clone of the repository, and not in git tag -a -m "Release 3.0.0" 3.0.0 ``` - then push the tag created in step 3 to esp8266/Arduino Github repository: + navigate to [Travis CI options](https://travis-ci.org/esp8266/Arduino/settings), enable `Build pushed branches`, + + then push the tag created above to esp8266/Arduino Github repository: ``` git push origin 3.0.0 @@ -132,7 +134,9 @@ The following points assume work in a direct clone of the repository, and not in * Release must be deleted: github > releases > edit x.y.z > remove all files > delete button appears -5. Wait for Travis CI build for the tag to pass, see https://travis-ci.org/esp8266/Arduino/builds. +5. Wait for Travis CI build for the tag to pass, see https://travis-ci.org/esp8266/Arduino/builds, + + return to the Travis CI options and disable `Build pushed branches`. 6. Check that the new (draft) release has been created (no editing at this point!), see https://github.com/esp8266/Arduino/releases. Check that the boards manager package .zip file has been successfully uploaded as a release artifact. @@ -146,7 +150,7 @@ The following points assume work in a direct clone of the repository, and not in 11. Create a commit to the master branch, updating: - * The version in platform.txt file. This should correspond to the version of the *next* milestone, plus `-dev` suffix. E.g. `3.1.0-dev`. + * The version in platform.txt and package.json files. This should correspond to the version of the *next* milestone, plus `-dev` suffix. E.g. `3.1.0-dev`. * In main README.md: diff --git a/package/build_boards_manager_package.sh b/package/build_boards_manager_package.sh index f5ffff447..372fa2c63 100755 --- a/package/build_boards_manager_package.sh +++ b/package/build_boards_manager_package.sh @@ -1,13 +1,13 @@ #!/bin/bash -# #set -x ver=`git describe --tag` visiblever=$ver -if [ "$ver" = 0.0.1 ]; then +# match 0.0.* +if [ "${ver%.*}" = 0.0 ]; then - git tag -d 0.0.1 + git tag -d ${ver} ver=`git describe --tag HEAD` plain_ver=$ver @@ -94,7 +94,7 @@ $SED 's/^tools.esptool.network_cmd=.*//g' | \ $SED 's/^#tools.esptool.cmd=/tools.esptool.cmd=/g' | \ $SED 's/^#tools.esptool.network_cmd=/tools.esptool.network_cmd=/g' | \ $SED 's/tools.mkspiffs.path={runtime.platform.path}\/tools\/mkspiffs/tools.mkspiffs.path=\{runtime.tools.mkspiffs.path\}/g' |\ -$SED 's/recipe.hooks.core.prebuild.pattern.*//g' |\ +$SED 's/recipe.hooks.*makecorever.*//g' |\ $SED "s/version=.*/version=$ver/g" |\ $SED -E "s/name=([a-zA-Z0-9\ -]+).*/name=\1($ver)/g"\ > $outdir/platform.txt @@ -167,8 +167,21 @@ curl -L -o $old_json "https://github.com/esp8266/Arduino/releases/download/${bas new_json=package_esp8266com_index.json set +e -# Merge the old and new, then drop any obsolete package versions -python3 ../../merge_packages.py $new_json $old_json | python3 ../../drop_versions.py - tools 1.20.0-26-gb404fb9 >tmp && mv tmp $new_json && rm $old_json +# Merge the old and new +python3 ../../merge_packages.py $new_json $old_json > tmp + +# additional json to merge (for experimental releases) +echo "Additional json package files: ${MOREJSONPACKAGES}" +for json in ${MOREJSONPACKAGES}; do + if [ ! -z "$json" -a -r "$json" ]; then + echo "- merging $json" + python3 ../../merge_packages.py tmp $json > tmp2 + mv tmp2 tmp + fi +done + +# drop any obsolete package versions +python3 ../../drop_versions.py - tools 1.20.0-26-gb404fb9 < tmp > tmp2 && mv tmp2 $new_json && rm $old_json tmp # Verify the JSON file can be read, fail if it's not OK set -e diff --git a/package/package_esp8266com_index.template.json b/package/package_esp8266com_index.template.json index 709238253..86a9570bf 100644 --- a/package/package_esp8266com_index.template.json +++ b/package/package_esp8266com_index.template.json @@ -62,6 +62,9 @@ { "name": "SparkFun ESP8266 Thing Dev" }, + { + "name": "SparkFun Blynk Board" + }, { "name": "SweetPea ESP-210" }, @@ -106,6 +109,15 @@ }, { "name": "ESPectro Core" + }, + { + "name": "Schirmilabs Eduino WiFi" + }, + { + "name": "ITEAD Sonoff" + }, + { + "name": "DOIT ESP-Mx DevKit (ESP8285)" } ], "toolsDependencies": [ @@ -121,7 +133,7 @@ }, { "packager": "esp8266", - "version": "2.5.0-4-b40a506", + "version": "2.5.0-4-fe5bb56", "name": "mklittlefs" }, { @@ -156,38 +168,38 @@ }, { "host": "aarch64-linux-gnu", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-placeholder.tar.gz", - "archiveFileName": "python3-placeholder.tar.gz", - "checksum": "SHA-256:d8cf9d9d66423d7b90978ebe285a73a6e8611995cd0d5e6273e929a0cf2c9850", - "size": "191" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-via-env.tar.gz", + "archiveFileName": "python3-via-env.tar.gz", + "checksum": "SHA-256:c9237bfe0f62842d7187a39495baa4a7e3ab8b87c0b433614294b023cf0bc0f3", + "size": "292" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-placeholder.tar.gz", - "archiveFileName": "python3-placeholder.tar.gz", - "checksum": "SHA-256:d8cf9d9d66423d7b90978ebe285a73a6e8611995cd0d5e6273e929a0cf2c9850", - "size": "191" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-via-env.tar.gz", + "archiveFileName": "python3-via-env.tar.gz", + "checksum": "SHA-256:c9237bfe0f62842d7187a39495baa4a7e3ab8b87c0b433614294b023cf0bc0f3", + "size": "292" }, { "host": "i686-pc-linux-gnu", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-placeholder.tar.gz", - "archiveFileName": "python3-placeholder.tar.gz", - "checksum": "SHA-256:d8cf9d9d66423d7b90978ebe285a73a6e8611995cd0d5e6273e929a0cf2c9850", - "size": "191" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-via-env.tar.gz", + "archiveFileName": "python3-via-env.tar.gz", + "checksum": "SHA-256:c9237bfe0f62842d7187a39495baa4a7e3ab8b87c0b433614294b023cf0bc0f3", + "size": "292" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-macosx-placeholder.tar.gz", - "archiveFileName": "python3-macosx-placeholder.tar.gz", - "checksum": "SHA-256:5bfa0d4c2dc3edeeaa913f4eac42ef3ff0bf8c8fe9f11be112a8ca7911de2dae", - "size": "198" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-via-env.tar.gz", + "archiveFileName": "python3-via-env.tar.gz", + "checksum": "SHA-256:c9237bfe0f62842d7187a39495baa4a7e3ab8b87c0b433614294b023cf0bc0f3", + "size": "292" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-placeholder.tar.gz", - "archiveFileName": "python3-placeholder.tar.gz", - "checksum": "SHA-256:d8cf9d9d66423d7b90978ebe285a73a6e8611995cd0d5e6273e929a0cf2c9850", - "size": "191" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/python3-via-env.tar.gz", + "archiveFileName": "python3-via-env.tar.gz", + "checksum": "SHA-256:c9237bfe0f62842d7187a39495baa4a7e3ab8b87c0b433614294b023cf0bc0f3", + "size": "292" } ] }, @@ -302,22 +314,29 @@ ] }, { - "version": "2.5.0-4-b40a506", + "version": "2.5.0-4-fe5bb56", "name": "mklittlefs", "systems": [ { "host": "aarch64-linux-gnu", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/aarch64-linux-gnu.mklittlefs-7f77f2b.1563313032.tar.gz", - "archiveFileName": "aarch64-linux-gnu.mklittlefs-7f77f2b.1563313032.tar.gz", - "checksum": "SHA-256:25c4dcf818d175e19c3cc22bc0388c61fa3d9bdf82a1fad388323cef34caa169", - "size": "44059" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/aarch64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz", + "archiveFileName": "aarch64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz", + "checksum": "SHA-256:ac50bae3b580053ba98a181ae3700fafd2b2f8a37ed9c16bc22a5d7c1659388e", + "size": "44433" }, { "host": "arm-linux-gnueabihf", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/arm-linux-gnueabihf.mklittlefs-7f77f2b.1563313032.tar.gz", - "archiveFileName": "arm-linux-gnueabihf.mklittlefs-7f77f2b.1563313032.tar.gz", - "checksum": "SHA-256:75a284f4e8c54d302b1880df46dd48e18857f69c21baa0977b1e6efc404caf18", - "size": "36567" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/arm-linux-gnueabihf.mklittlefs-fe5bb56.1578453304.tar.gz", + "archiveFileName": "arm-linux-gnueabihf.mklittlefs-fe5bb56.1578453304.tar.gz", + "checksum": "SHA-256:092555612e7e229fbe622df75db70560896c3aea8d0ac2e5fa16d92dc16857cf", + "size": "36917" + }, + { + "host": "i686-pc-linux-gnu", + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/i686-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz", + "archiveFileName": "i686-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz", + "checksum": "SHA-256:060e2525223269d2a5d01055542ff36837f0b19598d78cb02d58563aeda441cd", + "size": "47833" }, { "host": "i686-pc-linux-gnu", @@ -328,35 +347,35 @@ }, { "host": "i686-mingw32", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/i686-w64-mingw32.mklittlefs-7f77f2b.1563313032.zip", - "archiveFileName": "i686-w64-mingw32.mklittlefs-7f77f2b.1563313032.zip", - "checksum": "SHA-256:7778209e9df8c8c5f5da82660ff9a95b866defee3c9eb5c22371e0fd84b1addc", - "size": "332057" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/i686-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip", + "archiveFileName": "i686-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip", + "checksum": "SHA-256:2e570bed4ec59a9ecc73290e16c31ed53ee15e3abd8c82cb038b2148596d112e", + "size": "332329" }, { "host": "x86_64-apple-darwin", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-apple-darwin14.mklittlefs-7f77f2b.1563313032.tar.gz", - "archiveFileName": "x86_64-apple-darwin14.mklittlefs-7f77f2b.1563313032.tar.gz", - "checksum": "SHA-256:c465da766026c6c66d731442b741fb5a7f8b741e9473d181e6c5e588c541f588", - "size": "362014" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-apple-darwin14.mklittlefs-fe5bb56.1578453304.tar.gz", + "archiveFileName": "x86_64-apple-darwin14.mklittlefs-fe5bb56.1578453304.tar.gz", + "checksum": "SHA-256:fcb57ff58eceac79e988cc26a9e009a11ebda68d4ae97e44fed8e7c6d98a35b5", + "size": "362389" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-linux-gnu.mklittlefs-7f77f2b.1563313032.tar.gz", - "archiveFileName": "x86_64-linux-gnu.mklittlefs-7f77f2b.1563313032.tar.gz", - "checksum": "SHA-256:6a358716d4c780fa459b4c774723302431b3ad5e1ee3f7edae62be331541615c", - "size": "46164" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz", + "archiveFileName": "x86_64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz", + "checksum": "SHA-256:5ef79d76e8e76f8287dc70d10c33f020d4cf5320354571adf666665eeef2e2de", + "size": "46580" }, { "host": "x86_64-mingw32", - "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-w64-mingw32.mklittlefs-7f77f2b.1563313032.zip", - "archiveFileName": "x86_64-w64-mingw32.mklittlefs-7f77f2b.1563313032.zip", - "checksum": "SHA-256:d5d44b5f21681a831318a23b31957bc9368c50f0766964ead409c3d2fe4747d2", - "size": "344578" + "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip", + "archiveFileName": "x86_64-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip", + "checksum": "SHA-256:a460f410a22a59e23d7f862b8d08d6b7dfbc93aa558f8161a3d640d4df2ab86f", + "size": "344792" } ] } ] } ] -} \ No newline at end of file +} diff --git a/platform.txt b/platform.txt index dfeee3ae0..678be1ba9 100644 --- a/platform.txt +++ b/platform.txt @@ -5,8 +5,8 @@ # For more info: # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification -name=ESP8266 Boards (2.6.0-dev) -version=2.6.0-dev +name=ESP8266 Boards (2.7.0-dev) +version=2.7.0-dev # These will be removed by the packager script when doing a JSON release runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}/tools/xtensa-lx106-elf @@ -39,7 +39,12 @@ build.stdcpp_level=-std=gnu++11 build.float=-u _printf_float -u _scanf_float build.led= + +# default SDK for all boards +# (generic board overrides this variable) build.sdk=NONOSDK22x_190703 +#build.sdk=NONOSDK22x_191024 +#build.sdk=NONOSDK22x_191105 compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/ compiler.sdk.path={runtime.platform.path}/tools/sdk @@ -144,7 +149,7 @@ tools.esptool.upload.params.quiet= # First, potentially perform an erase or nothing # Next, do the binary upload # Combined in one rule because Arduino doesn't suport upload.1.pattern/upload.3.pattern -tools.esptool.upload.pattern="{cmd}" "{runtime.platform.path}/tools/upload.py" --chip esp8266 --port "{serial.port}" --baud "{upload.speed}" "{upload.verbose}" {upload.erase_cmd} --end --chip esp8266 --port "{serial.port}" --baud "{upload.speed}" "{upload.verbose}" write_flash 0x0 "{build.path}/{build.project_name}.bin" --end +tools.esptool.upload.pattern="{cmd}" "{runtime.platform.path}/tools/upload.py" --chip esp8266 --port "{serial.port}" --baud "{upload.speed}" "{upload.verbose}" {upload.erase_cmd} {upload.resetmethod} write_flash 0x0 "{build.path}/{build.project_name}.bin" tools.esptool.upload.network_pattern="{network_cmd}" "{runtime.platform.path}/tools/espota.py" -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin" diff --git a/tests/common.sh b/tests/common.sh index bf329b3ac..b2878ea02 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -34,17 +34,11 @@ function print_size_info() elf_name=$(basename $elf_file) sketch_name="${elf_name%.*}" # echo $sketch_name + xtensa-lx106-elf-size --format=sysv $elf_file | sed s/irom0.text/irom0text/g > size.txt declare -A segments - while read -a tokens; do - seg=${tokens[0]} - seg=${seg//./} - size=${tokens[1]} - addr=${tokens[2]} - if [ "$addr" -eq "$addr" -a "$addr" -ne "0" ] 2>/dev/null; then - segments[$seg]=$size - fi - - done < <(xtensa-lx106-elf-size --format=sysv $elf_file | sed 's/\r//g' ) + for seg in data rodata bss text irom0text; do + segments[$seg]=$(grep ^.$seg size.txt | awk '{sum += $2} END {print sum}') + done total_ram=$((${segments[data]} + ${segments[rodata]} + ${segments[bss]})) total_flash=$((${segments[data]} + ${segments[rodata]} + ${segments[text]} + ${segments[irom0text]})) @@ -165,16 +159,20 @@ function install_ide() local core_path=$2 local debug=$3 if [ "$WINDOWS" = "1" ]; then - # Acquire needed packages from Windows package manager - choco install --no-progress python3 >& pylog.txt - # Parse the python instrall dir from the output log. Sorry, can't set it via choco on the free version - PYDIR=$(cat pylog.txt | grep "^Installed to:" | cut -f2 -d"'" | sed 's/C:\\/\/c\//') - echo "Detected python3 install dir: $PYDIR" - export PATH="$PYDIR:$PATH" # Ensure it's live from now on... - cp "$PYDIR/python.exe" "$PYDIR/python3.exe" - choco install --no-progress unzip - choco install --no-progress sed - #choco install --no-progress golang + mkdir /c/mybin + pushd /c/mybin + # Use Python.org to install python3 and make sure it is in path + wget -nv https://www.python.org/ftp/python/3.8.1/python-3.8.1-embed-win32.zip + unzip -q python-3.8.1-embed-win32.zip + cp "python.exe" "python3.exe" + wget -nv -O sed.exe https://github.com/mbuilov/sed-windows/raw/master/sed-4.8-x64.exe + #wget -nv https://fossies.org/windows/misc/unz600xn.exe + #unzip -q ./unz600xn.exe + popd + export PATH="c:\\mybin:$PATH" # Ensure it's live from now on... + python3 --version + sed --version + awk --version test -r arduino-windows.zip || wget -nv -O arduino-windows.zip "${ideurl}-windows.zip" unzip -q arduino-windows.zip mv arduino-${idever} arduino-distrib diff --git a/tests/device/Makefile b/tests/device/Makefile index dab0ef379..c60135c81 100644 --- a/tests/device/Makefile +++ b/tests/device/Makefile @@ -1,6 +1,5 @@ SHELL := /bin/bash V ?= 0 -TEST_LIST ?= $(wildcard test_*/*.ino) ESP8266_CORE_PATH ?= $(realpath ../..) BUILD_DIR ?= $(PWD)/.build HARDWARE_DIR ?= $(PWD)/.hardware @@ -12,13 +11,18 @@ UPLOAD_BAUD ?= 460800 UPLOAD_BOARD ?= nodemcu BS_DIR ?= libraries/BSTest DEBUG_LEVEL ?= lvl=None____ -#FQBN ?= esp8266com:esp8266:generic:CpuFrequency=80,FlashFreq=40,FlashMode=dio,UploadSpeed=115200,FlashSize=4M1M,LwIPVariant=v2mss536,ResetMethod=none,Debug=Serial,$(DEBUG_LEVEL) -FQBN ?= esp8266com:esp8266:generic:xtal=160,FlashFreq=40,FlashMode=dio,baud=115200,eesz=4M1M,ip=lm2f,ResetMethod=none,dbg=Serial,$(DEBUG_LEVEL) +FQBN ?= esp8266com:esp8266:generic:xtal=160,FlashFreq=40,FlashMode=dio,baud=115200,eesz=4M1M,ip=lm2f,ResetMethod=nodemcu,dbg=Serial,$(DEBUG_LEVEL) BUILD_TOOL := $(ARDUINO_IDE_PATH)/arduino-builder TEST_CONFIG := test_env.cfg TEST_REPORT_XML := test_report.xml TEST_REPORT_HTML := test_report.html +ifeq ("$(MOCK)", "1") +# To enable a test for mock testing, just rename dir+files to '*_sw_*' +TEST_LIST ?= $(wildcard test_sw_*/*.ino) +else +TEST_LIST ?= $(wildcard test_*/*.ino) +endif ifneq ("$(V)","1") SILENT = @ @@ -29,6 +33,17 @@ else #UPLOAD_VERBOSE_FLAG = -v endif +help: + @echo + @echo 'make list - show list of tests' + @echo 'make sometest/sometest.ino - run one test' + @echo 'make all - run all tests' + @echo 'make MOCK=1 all - run all emulation-on-host compatible tests' + @echo 'variables needed: $$ARDUINO_IDE_PATH $$ESP8266_CORE_PATH' + @echo 'make options: V=1 NO_BUILD=1 NO_UPLOAD=1 NO_RUN=1 MOCK=1' + @echo + +list: showtestlist all: count tests test_report @@ -47,6 +62,18 @@ $(TEST_LIST): @echo "--------------------------------" @echo "Running test '$@' of $(words $(TEST_LIST)) tests" $(SILENT)mkdir -p $(LOCAL_BUILD_DIR) +ifeq ("$(MOCK)", "1") + @echo Compiling $(notdir $@) + (cd ../host; make ULIBDIRS=../device/libraries/BSTest ../device/$(@:%.ino=%)) + $(SILENT)source $(BS_DIR)/virtualenv/bin/activate && \ + $(PYTHON) $(BS_DIR)/runner.py \ + $(RUNNER_DEBUG_FLAG) \ + -e "$(ESP8266_CORE_PATH)/tests/host/bin/$(@:%.ino=%)" \ + -n $(basename $(notdir $@)) \ + -o $(LOCAL_BUILD_DIR)/test_result.xml \ + --env-file $(TEST_CONFIG) \ + `test -f $(addsuffix .py, $(basename $@)) && echo "-m $(addsuffix .py, $(basename $@))" || echo ""` +else ifneq ("$(NO_BUILD)","1") @test -n "$(ARDUINO_IDE_PATH)" || (echo "Please export ARDUINO_IDE_PATH" && exit 1) @echo Compiling $(notdir $@) @@ -102,6 +129,7 @@ ifneq ("$(NO_RUN)","1") --env-file $(TEST_CONFIG) \ `test -f $(addsuffix .py, $(basename $@)) && echo "-m $(addsuffix .py, $(basename $@))" || echo ""` endif +endif $(TEST_REPORT_XML): $(HARDWARE_DIR) virtualenv $(SILENT)$(BS_DIR)/xunitmerge $(shell find $(BUILD_DIR) -name 'test_result.xml' | xargs echo) $(TEST_REPORT_XML) diff --git a/tests/device/test_WiFi_events/test_WiFi_events.ino b/tests/device/test_WiFi_events/test_WiFi_events.ino index 88777b61a..e5a4079ff 100644 --- a/tests/device/test_WiFi_events/test_WiFi_events.ino +++ b/tests/device/test_WiFi_events/test_WiFi_events.ino @@ -95,7 +95,7 @@ TEST_CASE("STA mode events are called both when using DHCP and static config", " delay(100); REQUIRE(events == "connected,got_ip,disconnected,"); - events = String(); + events.clear(); // now run the same with static IP config saved above diff --git a/tests/device/test_http_server/test_http_server.ino b/tests/device/test_http_server/test_http_server.ino index e9f8bda92..07bbe3cb9 100644 --- a/tests/device/test_http_server/test_http_server.ino +++ b/tests/device/test_http_server/test_http_server.ino @@ -55,7 +55,10 @@ TEST_CASE("HTTP GET Parameters", "[HTTPServer]") server.on("/get", HTTP_GET, &handle_request); uint32_t startTime = millis(); while(siteHits == 0 && (millis() - startTime) < 10000) + { + MDNS.update(); server.handleClient(); + } REQUIRE(siteHits > 0 && siteData.equals("var1 = val with spaces\nva=r+ = so&me%")); } } @@ -68,7 +71,10 @@ TEST_CASE("HTTP POST Parameters", "[HTTPServer]") server.on("/post", HTTP_POST, &handle_request); uint32_t startTime = millis(); while(siteHits == 0 && (millis() - startTime) < 10000) + { + MDNS.update(); server.handleClient(); + } REQUIRE(siteHits > 0 && siteData.equals("var2 = val with spaces")); } } @@ -81,11 +87,15 @@ TEST_CASE("HTTP GET+POST Parameters", "[HTTPServer]") server.on("/get_and_post", HTTP_POST, &handle_request); uint32_t startTime = millis(); while(siteHits == 0 && (millis() - startTime) < 10000) + { + MDNS.update(); server.handleClient(); + } REQUIRE(siteHits > 0 && siteData.equals("var3 = val with spaces\nva&r+ = so=me%")); } } +#if 0 TEST_CASE("HTTP Upload", "[HTTPServer]") { { @@ -103,10 +113,14 @@ TEST_CASE("HTTP Upload", "[HTTPServer]") }); uint32_t startTime = millis(); while(siteHits == 0 && (millis() - startTime) < 10000) + { + MDNS.update(); server.handleClient(); + } REQUIRE(siteHits > 0 && siteData.equals("test.txt:16\nvar4 = val with spaces")); } } +#endif void loop() { diff --git a/tests/device/test_http_server/test_http_server.py b/tests/device/test_http_server/test_http_server.py index e184e367e..bf4f140a7 100644 --- a/tests/device/test_http_server/test_http_server.py +++ b/tests/device/test_http_server/test_http_server.py @@ -4,18 +4,20 @@ from threading import Thread from poster3.encode import MultipartParam from poster3.encode import multipart_encode from poster3.streaminghttp import register_openers +import sys import urllib def http_test(res, url, get=None, post=None): response = '' try: if get: - url += '?' + urllib.urlencode(get) + url += '?' + urllib.parse.urlencode(get) if post: - post = urllib.parse.quote(post) + post = bytes(urllib.parse.urlencode(post).encode('utf-8')) request = urllib.request.urlopen(url, post, 2) response = request.read() - except: + except Exception as e: + print('http_test: Exception: ', e, file=sys.stderr) return 1 if response != res: return 1 @@ -51,23 +53,25 @@ def setup_http_getpost_params(e): def teardown_http_getpost_params(e): return 0 -@setup('HTTP Upload') -def setup_http_upload(e): - def testRun(): - response = '' - try: - register_openers() - p = MultipartParam("file", "0123456789abcdef", "test.txt", "text/plain; charset=utf8") - datagen, headers = multipart_encode( [("var4", "val with spaces"), p] ) - request = urllib.request('http://etd.local/upload', datagen, headers) - response = urllib.request.urlopen(request, None, 2).read() - except: - return 1 - if response != 'test.txt:16\nvar4 = val with spaces': - return 1 - return 0 - Thread(target=testRun).start() - -@teardown('HTTP Upload') -def teardown_http_upload(e): - return 0 +#@setup('HTTP Upload') +#def setup_http_upload(e): +# def testRun(): +# response = '' +# try: +# register_openers() +# p = MultipartParam("file", "0123456789abcdef", "test.txt", "text/plain; charset=utf8") +# datagen, headers = multipart_encode( [("var4", "val with spaces"), p] ) +# request = urllib.request.Request('http://etd.local/upload', datagen, headers) +# opener = urllib.request.build_opener() +# response = opener.open(request) +# except Exception as e: +# print('testRun: Exception: ', e, file=sys.stderr) +# return 1 +# if response != 'test.txt:16\nvar4 = val with spaces': +# return 1 +# return 0 +# Thread(target=testRun).start() +# +#@teardown('HTTP Upload') +#def teardown_http_upload(e): +# return 0 diff --git a/tests/device/test_overrides/test_overrides.ino b/tests/device/test_overrides/test_overrides.ino index e8737f7cb..959caf00d 100644 --- a/tests/device/test_overrides/test_overrides.ino +++ b/tests/device/test_overrides/test_overrides.ino @@ -30,7 +30,7 @@ TEST_CASE("ADC_MODE override works", "[core]") auto vcc = ESP.getVcc(); Serial.printf("VCC: %d\r\n", vcc); Serial.printf("A0: %d\r\n", analogRead(A0)); - CHECK(vcc > 3000 && vcc < 3600); + CHECK(vcc > 2500 && vcc < 3600); } TEST_CASE("RF_PRE_INIT override works", "[core]") diff --git a/tests/device/test_FS/test_FS.ino b/tests/device/test_sw_FS/test_sw_FS.ino similarity index 100% rename from tests/device/test_FS/test_FS.ino rename to tests/device/test_sw_FS/test_sw_FS.ino diff --git a/tests/device/test_Print_printf/test_Print_printf.ino b/tests/device/test_sw_Print_printf/test_sw_Print_printf.ino similarity index 100% rename from tests/device/test_Print_printf/test_Print_printf.ino rename to tests/device/test_sw_Print_printf/test_sw_Print_printf.ino diff --git a/tests/device/test_WiFiServer/test_WiFiServer.ino b/tests/device/test_sw_WiFiServer/test_sw_WiFiServer.ino similarity index 98% rename from tests/device/test_WiFiServer/test_WiFiServer.ino rename to tests/device/test_sw_WiFiServer/test_sw_WiFiServer.ino index 5af9cfce2..109ce4db4 100644 --- a/tests/device/test_WiFiServer/test_WiFiServer.ino +++ b/tests/device/test_sw_WiFiServer/test_sw_WiFiServer.ino @@ -36,7 +36,7 @@ TEST_CASE("Simple echo server", "[WiFiServer]") int replyCount = 0; while (millis() - start < timeout) { - delay(50); + MDNS.update(); WiFiClient client = server.available(); if (!client) { continue; diff --git a/tests/device/test_WiFiServer/test_WiFiServer.py b/tests/device/test_sw_WiFiServer/test_sw_WiFiServer.py similarity index 91% rename from tests/device/test_WiFiServer/test_WiFiServer.py rename to tests/device/test_sw_WiFiServer/test_sw_WiFiServer.py index f74dd49a0..b64de33e1 100644 --- a/tests/device/test_WiFiServer/test_WiFiServer.py +++ b/tests/device/test_sw_WiFiServer/test_sw_WiFiServer.py @@ -18,11 +18,11 @@ def setup_echo_server(e): sock.connect((server_address, 5000)) sock.settimeout(1.0) buf = 'a' * 1023 + '\n' - sock.sendall(buf) + sock.sendall(bytes(buf.encode('utf-8'))) data = '' retries = 0 while len(data) < 1024 and retries < 3: - data += sock.recv(1024) + data += sock.recv(1024).decode('utf-8') retries += 1 print('Received {} bytes'.format(len(data))) if len(data) != 1024: diff --git a/tests/device/test_http_client/server.crt b/tests/device/test_sw_http_client/server.crt similarity index 100% rename from tests/device/test_http_client/server.crt rename to tests/device/test_sw_http_client/server.crt diff --git a/tests/device/test_http_client/server.csr b/tests/device/test_sw_http_client/server.csr similarity index 100% rename from tests/device/test_http_client/server.csr rename to tests/device/test_sw_http_client/server.csr diff --git a/tests/device/test_http_client/server.key b/tests/device/test_sw_http_client/server.key similarity index 100% rename from tests/device/test_http_client/server.key rename to tests/device/test_sw_http_client/server.key diff --git a/tests/device/test_http_client/test_http_client.ino b/tests/device/test_sw_http_client/test_sw_http_client.ino similarity index 99% rename from tests/device/test_http_client/test_http_client.ino rename to tests/device/test_sw_http_client/test_sw_http_client.ino index 4757fdb4f..6de2314fa 100644 --- a/tests/device/test_http_client/test_http_client.ino +++ b/tests/device/test_sw_http_client/test_sw_http_client.ino @@ -210,6 +210,7 @@ TEST_CASE("HTTPS GET request", "[HTTPClient]") // // Same tests with axTLS // +#if !CORE_MOCK { // small request #pragma GCC diagnostic push @@ -242,6 +243,7 @@ TEST_CASE("HTTPS GET request", "[HTTPClient]") } } } +#endif } void loop() diff --git a/tests/device/test_http_client/test_http_client.py b/tests/device/test_sw_http_client/test_sw_http_client.py similarity index 99% rename from tests/device/test_http_client/test_http_client.py rename to tests/device/test_sw_http_client/test_sw_http_client.py index 83bc4e8c1..9a3094505 100644 --- a/tests/device/test_http_client/test_http_client.py +++ b/tests/device/test_sw_http_client/test_sw_http_client.py @@ -37,7 +37,7 @@ def setup_http_get(e): return redirect("http://{}:8088/target".format(request.args['host']), code=302) @app.route("/redirect303", methods = ['POST']) def redirect303(): - return redirect("http://{}:8088/target".format(request.data), code=303) + return redirect("http://{}:8088/target".format(request.data.decode()), code=303) @app.route("/redirect307") def redirect307(): return redirect("http://{}:8088/target".format(request.args['host']), code=307) diff --git a/tests/device/test_newlib/test_newlib.ino b/tests/device/test_sw_newlib/test_sw_newlib.ino similarity index 100% rename from tests/device/test_newlib/test_newlib.ino rename to tests/device/test_sw_newlib/test_sw_newlib.ino diff --git a/tests/device/test_schedule/test_schedule.ino b/tests/device/test_sw_schedule/test_sw_schedule.ino similarity index 100% rename from tests/device/test_schedule/test_schedule.ino rename to tests/device/test_sw_schedule/test_sw_schedule.ino diff --git a/tests/device/test_tests/test_tests.ino b/tests/device/test_sw_tests/test_sw_tests.ino similarity index 78% rename from tests/device/test_tests/test_tests.ino rename to tests/device/test_sw_tests/test_sw_tests.ino index 62110126b..d0d382a7f 100644 --- a/tests/device/test_tests/test_tests.ino +++ b/tests/device/test_sw_tests/test_sw_tests.ino @@ -20,7 +20,7 @@ TEST_CASE("this test runs successfully", "[bs]") REQUIRE(2 * 2 == 4); } -TEST_CASE("another test which fails", "[bs][fail]") +TEST_CASE("another test which successfully fails", "[bs][fail]") { CHECK(true); CHECK(false); @@ -28,7 +28,7 @@ TEST_CASE("another test which fails", "[bs][fail]") CHECK(false); } -TEST_CASE("another test which fails and crashes", "[bs][fail]") +TEST_CASE("another test which successfully fails and crashes", "[bs][fail]") { CHECK(true); REQUIRE(false); diff --git a/tests/host/Makefile b/tests/host/Makefile index aaf8a88d9..f6361f36a 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -6,6 +6,7 @@ LIBRARIES_PATH := ../../libraries FORCE32 ?= 1 OPTZ ?= -Os V ?= 0 +DEFSYM_FS ?= -Wl,--defsym,_FS_start=0x40300000 -Wl,--defsym,_FS_end=0x411FA000 -Wl,--defsym,_FS_page=0x100 -Wl,--defsym,_FS_block=0x2000 -Wl,--defsym,_EEPROM_start=0x411fb000 MAKEFILE = $(word 1, $(MAKEFILE_LIST)) @@ -70,6 +71,7 @@ CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\ Schedule.cpp \ HardwareSerial.cpp \ crc32.cpp \ + Updater.cpp \ ) \ $(addprefix $(LIBRARIES_PATH)/ESP8266SdFat/src/, \ FatLib/FatFile.cpp \ @@ -98,6 +100,7 @@ MOCK_CPP_FILES_COMMON := $(addprefix common/,\ MockUART.cpp \ MockTools.cpp \ MocklwIP.cpp \ + MockDigital.cpp \ ) MOCK_CPP_FILES := $(MOCK_CPP_FILES_COMMON) $(addprefix common/,\ @@ -136,7 +139,8 @@ TEST_CPP_FILES := \ core/test_md5builder.cpp \ core/test_string.cpp \ core/test_PolledTimeout.cpp \ - core/test_Print.cpp + core/test_Print.cpp \ + core/test_Updater.cpp PREINCLUDES := \ -include common/mock.h \ @@ -233,7 +237,7 @@ $(BINDIR)/core.a: $(C_OBJECTS) $(CPP_OBJECTS_CORE) ranlib -c $@ $(OUTPUT_BINARY): $(CPP_OBJECTS_TESTS) $(BINDIR)/core.a - $(VERBLD) $(CXX) $(LDFLAGS) $^ -o $@ + $(VERBLD) $(CXX) $(DEFSYM_FS) $(LDFLAGS) $^ -o $@ ################################################# # building ino sources diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp index 5192028e7..8a0162b47 100644 --- a/tests/host/common/Arduino.cpp +++ b/tests/host/common/Arduino.cpp @@ -37,9 +37,14 @@ extern "C" void yield() { } +extern "C" bool can_yield() +{ + return true; +} + extern "C" void optimistic_yield (uint32_t interval_us) { - usleep(interval_us); + (void)interval_us; } extern "C" void esp_yield() @@ -69,3 +74,4 @@ cont_t* g_pcont = NULL; extern "C" void cont_yield(cont_t*) { } + diff --git a/tests/host/common/ArduinoMain.cpp b/tests/host/common/ArduinoMain.cpp index 565c7942d..7bfcd9703 100644 --- a/tests/host/common/ArduinoMain.cpp +++ b/tests/host/common/ArduinoMain.cpp @@ -174,7 +174,7 @@ void control_c (int sig) int main (int argc, char* const argv []) { bool fast = false; - bool blocking_uart = false; + blocking_uart = false; // global signal(SIGINT, control_c); if (geteuid() == 0) diff --git a/tests/host/common/MockDigital.cpp b/tests/host/common/MockDigital.cpp new file mode 100644 index 000000000..aa04527ab --- /dev/null +++ b/tests/host/common/MockDigital.cpp @@ -0,0 +1,56 @@ +/* + digital.c - wiring digital implementation for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#define ARDUINO_MAIN +#include "wiring_private.h" +#include "pins_arduino.h" +#include "c_types.h" +#include "eagle_soc.h" +#include "ets_sys.h" +#include "user_interface.h" +#include "core_esp8266_waveform.h" +#include "interrupts.h" + +extern "C" { + +static uint8_t _mode[17]; +static uint8_t _gpio[17]; + +extern void pinMode(uint8_t pin, uint8_t mode) { + if (pin < 17) { + _mode[pin] = mode; + } +} + +extern void digitalWrite(uint8_t pin, uint8_t val) { + if (pin < 17) { + _gpio[pin] = val; + } +} + +extern int digitalRead(uint8_t pin) { + if (pin < 17) { + return _gpio[pin] != 0; + } else { + return 0; + } +} + +}; diff --git a/tests/host/common/MockEsp.cpp b/tests/host/common/MockEsp.cpp index 8ff16cd01..c5ca502ed 100644 --- a/tests/host/common/MockEsp.cpp +++ b/tests/host/common/MockEsp.cpp @@ -120,7 +120,7 @@ uint32_t EspClass::getFreeSketchSpace() uint8_t EspClass::getCpuFreqMHz() { - return 160; + return F_CPU / 1000000; } const char *EspClass::getSdkVersion() diff --git a/tests/host/common/MockUART.cpp b/tests/host/common/MockUART.cpp index db0d8c889..023c775bf 100644 --- a/tests/host/common/MockUART.cpp +++ b/tests/host/common/MockUART.cpp @@ -39,6 +39,8 @@ extern "C" { +bool blocking_uart = true; // system default + static int s_uart_debug_nr = UART1; static uart_t *UART[2] = { NULL, NULL }; @@ -190,6 +192,13 @@ uart_read(uart_t* uart, char* userbuffer, size_t usersize) if(uart == NULL || !uart->rx_enabled) return 0; + if (!blocking_uart) + { + char c; + if (read(0, &c, 1) == 1) + uart_new_data(0, c); + } + size_t ret = 0; while (ret < usersize && uart_rx_available_unsafe(uart->rx_buffer)) { @@ -323,10 +332,11 @@ uart_get_bit_length(const int uart_nr) } uart_t* -uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size) +uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size, bool invert) { (void) config; (void) tx_pin; + (void) invert; uart_t* uart = (uart_t*) malloc(sizeof(uart_t)); if(uart == NULL) return NULL; diff --git a/tests/host/common/MockWiFiServer.cpp b/tests/host/common/MockWiFiServer.cpp index 6b8b7e83c..132ca5e88 100644 --- a/tests/host/common/MockWiFiServer.cpp +++ b/tests/host/common/MockWiFiServer.cpp @@ -59,7 +59,7 @@ WiFiClient WiFiServer::available (uint8_t* status) { (void)status; if (hasClient()) - return WiFiClient(new ClientContext(serverAccept(pcb2int(_pcb)))); + return WiFiClient(new ClientContext(serverAccept(pcb2int(_listen_pcb)))); return WiFiClient(); } diff --git a/tests/host/common/MockWiFiServerSocket.cpp b/tests/host/common/MockWiFiServerSocket.cpp index c791577d0..f56b9f424 100644 --- a/tests/host/common/MockWiFiServerSocket.cpp +++ b/tests/host/common/MockWiFiServerSocket.cpp @@ -60,6 +60,13 @@ int serverAccept (int srvsock) void WiFiServer::begin (uint16_t port) { + return begin(port, !0); +} + +void WiFiServer::begin (uint16_t port, uint8_t backlog) +{ + if (!backlog) + return; _port = port; return begin(); } @@ -109,13 +116,13 @@ void WiFiServer::begin () // store int into pointer - _pcb = int2pcb(sock); + _listen_pcb = int2pcb(sock); } bool WiFiServer::hasClient () { struct pollfd p; - p.fd = pcb2int(_pcb); + p.fd = pcb2int(_listen_pcb); p.events = POLLIN; return poll(&p, 1, 0) && p.revents == POLLIN; } @@ -134,7 +141,7 @@ size_t WiFiServer::write (const uint8_t *buf, size_t size) void WiFiServer::close () { - if (pcb2int(_pcb) >= 0) - ::close(pcb2int(_pcb)); - _pcb = int2pcb(-1); + if (pcb2int(_listen_pcb) >= 0) + ::close(pcb2int(_listen_pcb)); + _listen_pcb = int2pcb(-1); } diff --git a/tests/host/common/mock.h b/tests/host/common/mock.h index a908b2aba..27a2da4c4 100644 --- a/tests/host/common/mock.h +++ b/tests/host/common/mock.h @@ -61,6 +61,29 @@ typedef uint32_t uint32; // +#define ARDUINO 267 +#define ESP8266 1 +#define A0 0 +#define LED_BUILTIN 0 +#define F_CPU 80000000 +#define LWIP_OPEN_SRC +#define TCP_MSS 536 +#define LWIP_FEATURES 1 + +// + +#define D0 0 +#define D1 1 +#define D2 3 +#define D3 3 +#define D4 4 +#define D5 5 +#define D6 6 +#define D7 7 +#define D8 8 + +// + #include // @@ -81,12 +104,14 @@ extern "C" { #endif int ets_printf (const char* fmt, ...) __attribute__ ((format (printf, 1, 2))); #define os_printf_plus printf +#define ets_vsnprintf vsnprintf int mockverbose (const char* fmt, ...) __attribute__ ((format (printf, 1, 2))); extern const char* host_interface; // cmdline parameter extern bool serial_timestamp; extern int mock_port_shifter; +extern bool blocking_uart; #define NO_GLOBAL_BINDING 0xffffffff extern uint32_t global_ipv4_netfmt; // selected interface addresse to bind to @@ -143,29 +168,6 @@ void mock_stop_littlefs (); // -#define ARDUINO 267 -#define ESP8266 1 -#define A0 0 -#define LED_BUILTIN 0 -#define F_CPU 80000000 -#define LWIP_OPEN_SRC -#define TCP_MSS 536 -#define LWIP_FEATURES 1 - -// - -#define D0 0 -#define D1 1 -#define D2 3 -#define D3 3 -#define D4 4 -#define D5 5 -#define D6 6 -#define D7 7 -#define D8 8 - -// - #include // diff --git a/tests/host/core/test_Updater.cpp b/tests/host/core/test_Updater.cpp new file mode 100644 index 000000000..f3b850e13 --- /dev/null +++ b/tests/host/core/test_Updater.cpp @@ -0,0 +1,56 @@ +/* + test_Updater.cpp - Updater tests + Copyright © 2019 Earle F. Philhower, III + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + */ + +#include +#include + + +// Use a SPIFFS file because we can't instantiate a virtual class like Print +TEST_CASE("Updater fails when writes overflow requested size", "[core][Updater]") +{ + UpdaterClass *u; + uint8_t buff[6000]; + memset(buff, 0, sizeof(buff)); + u = new UpdaterClass(); + REQUIRE(u->begin(6000)); + REQUIRE(u->write(buff, 1000)); + REQUIRE(u->write(buff, 1000)); + REQUIRE(u->write(buff, 1000)); + REQUIRE(u->write(buff, 1000)); + REQUIRE(u->write(buff, 1000)); + REQUIRE(u->write(buff, 1000)); + REQUIRE(u->remaining() == 0); + // All bytes written, should fail next + REQUIRE(!u->write(buff, 1000)); + delete u; + + // Updater to a 4K aligned size, check nomissing over/underflow + u = new UpdaterClass(); + REQUIRE(u->begin(8192)); + REQUIRE(u->remaining() == 8192); + REQUIRE(u->write(buff, 4096)); + REQUIRE(u->write(buff, 4096)); + REQUIRE(!u->write(buff, 1)); + delete u; + + // Issue #4674 + u = new UpdaterClass(); + REQUIRE(u->begin(5000)); + REQUIRE(u->write(buff, 2048)); + REQUIRE(u->write(buff, 2048)); + // Should fail, would write 6KB + REQUIRE(!u->write(buff, 2048)); + delete u; +} diff --git a/tests/host/core/test_string.cpp b/tests/host/core/test_string.cpp index 93dc85e46..2d8ced73f 100644 --- a/tests/host/core/test_string.cpp +++ b/tests/host/core/test_string.cpp @@ -131,6 +131,22 @@ TEST_CASE("String concantenation", "[core][String]") REQUIRE(str == "-100"); str = String((long)-100, 10); REQUIRE(str == "-100"); + // Non-zero-terminated array concatenation + const char buff[] = "abcdefg"; + String n; + n = "1234567890"; // Make it a SSO string, fill with non-0 data + n = "1"; // Overwrite [1] with 0, but leave old junk in SSO space still + n.concat(buff, 3); + REQUIRE(n == "1abc"); // Ensure the trailing 0 is always present even w/this funky concat + for (int i=0; i<20; i++) + n.concat(buff, 1); // Add 20 'a's to go from SSO to normal string + REQUIRE(n == "1abcaaaaaaaaaaaaaaaaaaaa"); + n = ""; + for (int i=0; i<=5; i++) + n.concat(buff, i); + REQUIRE(n == "aababcabcdabcde"); + n.concat(buff, 0); // And check no add'n + REQUIRE(n == "aababcabcdabcde"); } TEST_CASE("String comparison", "[core][String]") diff --git a/tests/platformio.sh b/tests/platformio.sh index bacd1704e..4f1cbbb78 100755 --- a/tests/platformio.sh +++ b/tests/platformio.sh @@ -6,13 +6,13 @@ source "$TRAVIS_BUILD_DIR"/tests/common.sh function install_platformio() { - pip install --user -U https://github.com/platformio/platformio/archive/develop.zip + pip3 install --user -U https://github.com/platformio/platformio/archive/develop.zip platformio platform install "https://github.com/platformio/platform-espressif8266.git#feature/stage" sed -i 's/https:\/\/github\.com\/esp8266\/Arduino\.git/*/' ~/.platformio/platforms/espressif8266/platform.json - ln -s $TRAVIS_BUILD_DIR ~/.platformio/packages/framework-arduinoespressif8266 + ln -sf $TRAVIS_BUILD_DIR ~/.platformio/packages/framework-arduinoespressif8266 # Install dependencies: # - esp8266/examples/ConfigFile - pio lib install "ArduinoJson@^6.11.0" + pio lib --global install "ArduinoJson@^6.11.0" } function build_sketches_with_platformio() diff --git a/tests/run_CI_locally.sh b/tests/run_CI_locally.sh index a370461f6..c079c2a63 100755 --- a/tests/run_CI_locally.sh +++ b/tests/run_CI_locally.sh @@ -80,9 +80,6 @@ EOF test -z "$BUILD_TYPE" || break done -# use pip2 for python2 with python3 is around, platformio doesn't like it -cp tests/platformio.sh tests/platformio-custom.sh -sed -i 's,pip ,pip2 ,g' tests/platformio-custom.sh git submodule update --init @@ -117,11 +114,11 @@ elif [ "$BUILD_TYPE" = "build1_odd" ]; then BUILD_PARITY=odd tests/build1.sh elif [ "$BUILD_TYPE" = "platformio" ]; then - tests/platformio-custom.sh + tests/platformio.sh elif [ "$BUILD_TYPE" = "platformio_even" ]; then - BUILD_PARITY=even tests/platformio-custom.sh + BUILD_PARITY=even tests/platformio.sh elif [ "$BUILD_TYPE" = "platformio_odd" ]; then - BUILD_PARITY=odd tests/platformio-custom.sh + BUILD_PARITY=odd tests/platformio.sh elif [ "$BUILD_TYPE" = host ]; then tests/ci/host_test.sh diff --git a/tools/boards.txt.py b/tools/boards.txt.py index ec29c5d27..ff582896d 100755 --- a/tools/boards.txt.py +++ b/tools/boards.txt.py @@ -40,6 +40,9 @@ import getopt import re import json +requiredboards = [ 'generic', 'esp8285' ] + +################################################################ # serial upload speed order in menu # default is 115 for every board unless specified with 'serial' in board # or by user command line @@ -55,6 +58,7 @@ speeds = collections.OrderedDict([ ( '3000', [ 's3000','s57', 's115', 's230', 's256', 's460', 's512', 's921' ]), ]) +################################################################ # boards list boards = collections.OrderedDict([ @@ -296,9 +300,9 @@ boards = collections.OrderedDict([ ( '.build.board', 'ESP8266_ESP13' ), ( '.build.variant', 'ESPDuino' ), ( '.menu.ResetMethod.v2', 'ESPduino-V2' ), - ( '.menu.ResetMethod.v2.upload.resetmethod', 'nodemcu' ), + ( '.menu.ResetMethod.v2.upload.resetmethod', '--before default_reset --after hard_reset' ), ( '.menu.ResetMethod.v1', 'ESPduino-V1' ), - ( '.menu.ResetMethod.v1.upload.resetmethod', 'ck' ), + ( '.menu.ResetMethod.v1.upload.resetmethod', '--before no_reset --after soft_reset' ), ( '.menu.UploadTool.esptool', 'Serial' ), ( '.menu.UploadTool.esptool.upload.tool', 'esptool' ), ( '.menu.UploadTool.esptool.upload.verbose', '--trace' ), @@ -363,7 +367,7 @@ boards = collections.OrderedDict([ '', 'Product page: https://xinabox.cc/products/CW01' ], - }), + }), ( 'espresso_lite_v1', { 'name': 'ESPresso Lite 1.0', 'opts': { @@ -465,6 +469,7 @@ boards = collections.OrderedDict([ 'flashmode_dio', 'flashfreq_40', '4M', + 'led216', ], 'desc': [ 'This module is sold under many names for around $6.50 on AliExpress and it\'s one of the cheapest, fully integrated ESP8266 solutions.', '', @@ -532,6 +537,20 @@ boards = collections.OrderedDict([ ], 'desc': [ 'Product page: https://www.sparkfun.com/products/13711' ], }), + ( 'blynk', { + 'name': 'SparkFun Blynk Board', + 'opts': { + '.build.board': 'ESP8266_THING', + '.build.variant': 'thing', + }, + 'macro': [ + 'resetmethod_nodemcu', + 'flashmode_qio', + 'flashfreq_40', + '4M', + ], + 'desc': [ 'Product page: https://www.sparkfun.com/products/13794' ], + }), ( 'esp210', { 'name': 'SweetPea ESP-210', 'opts': { @@ -589,7 +608,7 @@ boards = collections.OrderedDict([ '1M', ], 'serial': '921', - 'desc': [ + 'desc': [ 'Parameters in Arduino IDE:', '~~~~~~~~~~~~~~~~~~~~~~~~~~', '', @@ -843,8 +862,100 @@ boards = collections.OrderedDict([ '', 'More details at https://shop.makestro.com/product/espectrocore/', ], + }), + + ( 'eduinowifi', { + 'name': 'Schirmilabs Eduino WiFi', + 'opts': { + '.build.board': 'ESP8266_SCHIRMILABS_EDUINO_WIFI', + '.build.variant': 'eduinowifi', + }, + 'macro': [ + 'resetmethod_nodemcu', + 'flashmode_dio', + 'flashfreq_40', + '4M', + ], + 'serial': '512', + 'desc': [ 'Eduino WiFi is an Arduino-compatible DIY WiFi development board using an ESP-12 module', + '', + 'Product page: https://schirmilabs.de/?page_id=165', + ] + + }), + ( 'sonoff', { + 'name': 'ITEAD Sonoff', + 'opts': { + '.build.board': 'ESP8266_SONOFF_SV', + '.build.variant': 'itead', + '.build.extra_flags': '-DESP8266', + '.build.flash_size': '1M', + '.menu.BoardModel.sonoffSV': 'ITEAD Sonoff SV', + '.menu.BoardModel.sonoffSV.build.board': 'ESP8266_SONOFF_SV', + '.menu.BoardModel.sonoffTH': 'ITEAD Sonoff TH', + '.menu.BoardModel.sonoffTH.build.board': 'ESP8266_SONOFF_TH', + '.menu.BoardModel.sonoffBasic': 'ITEAD Sonoff Basic', + '.menu.BoardModel.sonoffBasic.build.board': 'ESP8266_SONOFF_BASIC', + '.menu.BoardModel.sonoffS20': 'ITEAD Sonoff S20', + '.menu.BoardModel.sonoffS20.build.board': 'ESP8266_SONOFF_S20', + }, + 'macro': [ + 'resetmethod_none', + 'flashmode_dout', + 'flashfreq_40', + '1M', + ], + 'desc': [ + 'ESP8266 based devices from ITEAD: Sonoff SV, Sonoff TH, Sonoff Basic, ' + 'and Sonoff S20', + '', + 'These are not development boards. The development process is ' + 'inconvenient with these devices. When flashing firmware you will ' + 'need a Serial Adapter to connect it to your computer.', + '', + ' | Most of these devices, during normal operation, are connected to ' + '*wall power (AKA Mains Electricity)*. **NEVER** try to flash these ' + 'devices when connected to *wall power*. **ALWAYS** have them ' + 'disconnected from *wall power* when connecting them to your ' + 'computer. Your life may depend on it!', + '', + 'When flashing you will need to hold down the push button connected ' + 'to the GPIO0 pin, while powering up with a safe 3.3 Volt source. Some USB ' + 'Serial Adapters may supply enough power to handle flashing; ' + 'however, it many may not supply enough power to handle the ' + 'activities when the device reboots.', + '', + 'More product details at the bottom of https://www.itead.cc/wiki/Product/' + ], + }), + ( 'espmxdevkit', { + 'name': 'DOIT ESP-Mx DevKit (ESP8285)', + 'opts': { + '.build.board': 'ESP8266_ESP01', + '.build.variant': 'esp8285', + '.build.led': '-DLED_BUILTIN=16', + }, + 'macro': [ + 'resetmethod_nodemcu', + 'flashmode_dout', + 'flashfreq_40', + '1M', + ], + 'desc': [ + 'DOIT ESP-Mx DevKit - This is a development board by DOIT, with a DOIT ESP-Mx module ' + '(`datasheet `__) ' + 'using a ESP8285 Chip. With the DOIT ESP-Mx module, GPIO pins 9 and 10 are not available. ' + 'The DOIT ESP-Mx DevKit board has a red power LED and a blue LED connected to GPIO16 ' + 'and is active low to turn on. It uses a CH340C, USB to Serial converter chip. ' + '', + 'ESP8285 (`datasheet `__) ' + 'is a multi-chip package which contains ESP8266 and 1MB flash. ', + '', + ], + }) - ]) + ]) + ################################################################ @@ -853,7 +964,7 @@ macros = { ( '.upload.tool', 'esptool' ), ( '.upload.maximum_data_size', '81920' ), ( '.upload.wait_for_upload_port', 'true' ), - ( '.upload.erase_cmd', 'version'), + ( '.upload.erase_cmd', ''), ( '.serial.disableDTR', 'true' ), ( '.serial.disableRTS', 'true' ), ( '.build.mcu', 'esp8266' ), @@ -922,37 +1033,39 @@ macros = { ####################### menu.resetmethod 'resetmethod_menu': collections.OrderedDict([ - ( '.menu.ResetMethod.ck', 'ck' ), - ( '.menu.ResetMethod.ck.upload.resetmethod', 'ck' ), - ( '.menu.ResetMethod.nodemcu', 'nodemcu' ), - ( '.menu.ResetMethod.nodemcu.upload.resetmethod', 'nodemcu' ), + ( '.menu.ResetMethod.nodemcu', 'dtr (aka nodemcu)' ), + ( '.menu.ResetMethod.nodemcu.upload.resetmethod', '--before default_reset --after hard_reset' ), + ( '.menu.ResetMethod.ck', 'no dtr (aka ck)' ), + ( '.menu.ResetMethod.ck.upload.resetmethod', '--before no_reset --after soft_reset' ), ]), 'resetmethod_menu_extra': collections.OrderedDict([ - ( '.menu.ResetMethod.none', 'none' ), - ( '.menu.ResetMethod.none.upload.resetmethod', 'none' ), - ( '.menu.ResetMethod.dtrset', 'dtrset' ), - ( '.menu.ResetMethod.dtrset.upload.resetmethod', 'dtrset' ), + ( '.menu.ResetMethod.nodtr_nosync', 'no dtr, no_sync' ), + ( '.menu.ResetMethod.nodtr_nosync.upload.resetmethod', '--before no_reset_no_sync --after soft_reset' ), ]), - ####################### upload.resetmethod + ####################### upload.resetmethod (new esptool.py options) 'resetmethod_ck': collections.OrderedDict([ - ( '.upload.resetmethod', 'ck' ), + ( '.upload.resetmethod', '--before no_reset --after soft_reset' ), ]), 'resetmethod_nodemcu': collections.OrderedDict([ - ( '.upload.resetmethod', 'nodemcu' ), + ( '.upload.resetmethod', '--before default_reset --after hard_reset' ), ]), - + 'resetmethod_none': collections.OrderedDict([ - ( '.upload.resetmethod', 'none' ), + ( '.upload.resetmethod', '--before no_reset --after soft_reset' ), ]), 'resetmethod_dtrset': collections.OrderedDict([ - ( '.upload.resetmethod', 'dtrset' ), + ( '.upload.resetmethod', '--before default_reset --after hard_reset' ), ]), - + + 'resetmethod_nodtr_nosync': collections.OrderedDict([ + ( '.upload.resetmethod', '--before no_reset_no_sync --after soft_reset' ), + ]), + ####################### menu.FlashMode 'flashmode_menu': collections.OrderedDict([ @@ -1079,7 +1192,7 @@ macros = { 'flash_erase_menu': collections.OrderedDict([ ( '.menu.wipe.none', 'Only Sketch' ), - ( '.menu.wipe.none.upload.erase_cmd', 'version' ), + ( '.menu.wipe.none.upload.erase_cmd', '' ), ( '.menu.wipe.sdk', 'Sketch + WiFi Settings' ), ( '.menu.wipe.sdk.upload.erase_cmd', 'erase_region "{build.rfcal_addr}" 0x4000' ), ( '.menu.wipe.all', 'All Flash Contents' ), @@ -1347,31 +1460,35 @@ def all_flash_map (): ################################################################ # builtin led -def led (default,max): +def led (name, default, ledList): led = collections.OrderedDict([ ('.menu.led.' + str(default), str(default)), ('.menu.led.' + str(default) + '.build.led', '-DLED_BUILTIN=' + str(default)), ]); - for i in range(0,max+1): # Make range incluside of max (16), since there are really 16 GPIOS not 15 + for i in ledList: # Make range incluside of max (16), since there are really 16 GPIOS not 15 if not i == default: led.update( collections.OrderedDict([ ('.menu.led.' + str(i), str(i)), ('.menu.led.' + str(i) + '.build.led', '-DLED_BUILTIN=' + str(i)), ])) - return { 'led': led } + return { name: led } ################################################################ # sdk selection def sdk (): return { 'sdk': collections.OrderedDict([ - ('.menu.sdk.nonosdk222_100', 'nonos-sdk 2.2.1+100 (190703 approved)'), - ('.menu.sdk.nonosdk222_100.build.sdk', 'NONOSDK22x_190703'), - ('.menu.sdk.nonosdk222_111', 'nonos-sdk 2.2.1+111 (191024 testing)'), - ('.menu.sdk.nonosdk222_111.build.sdk', 'NONOSDK22x_191024'), - # ('.menu.sdk.nonosdk222_61', 'nonos-sdk 2.2.1+61 (190313 testing)'), - # ('.menu.sdk.nonosdk222_61.build.sdk', 'NONOSDK22x_190313'), + ('.menu.sdk.nonosdk_190703', 'nonos-sdk 2.2.1+100 (190703)'), + ('.menu.sdk.nonosdk_190703.build.sdk', 'NONOSDK22x_190703'), + ('.menu.sdk.nonosdk_191122', 'nonos-sdk 2.2.1+119 (191122)'), + ('.menu.sdk.nonosdk_191122.build.sdk', 'NONOSDK22x_191122'), + ('.menu.sdk.nonosdk_191105', 'nonos-sdk 2.2.1+113 (191105)'), + ('.menu.sdk.nonosdk_191105.build.sdk', 'NONOSDK22x_191105'), + ('.menu.sdk.nonosdk_191024', 'nonos-sdk 2.2.1+111 (191024)'), + ('.menu.sdk.nonosdk_191024.build.sdk', 'NONOSDK22x_191024'), + # ('.menu.sdk.nonosdk_190313', 'nonos-sdk 2.2.1+61 (190313 testing)'), + # ('.menu.sdk.nonosdk_190313.build.sdk', 'NONOSDK22x_190313'), ('.menu.sdk.nonosdk221', 'nonos-sdk 2.2.1 (legacy)'), ('.menu.sdk.nonosdk221.build.sdk', 'NONOSDK221'), ('.menu.sdk.nonosdk3v0', 'nonos-sdk pre-3 (180626 known issues)'), @@ -1383,29 +1500,59 @@ def sdk (): def all_boards (): - if boardsgen: + if boardsgen or boardslocalgen: checkdir() - # check if backup already exists - if not os.path.isfile("boards.txt.orig"): - os.rename("boards.txt", "boards.txt.orig") + if boardsgen: + # check if backup already exists + if not os.path.isfile("boards.txt.orig"): + os.rename("boards.txt", "boards.txt.orig") - realstdout = sys.stdout - sys.stdout = open("boards.txt", 'w') + realstdout = sys.stdout + sys.stdout = open("boards.txt", 'w') + else: + # make backup of boards.local.txt + if os.path.isfile("boards.local.txt"): + if not os.path.isfile("boards.local.txt.orig"): + os.rename("boards.local.txt", "boards.local.txt.orig") + + realstdout = sys.stdout + sys.stdout = open("boards.local.txt", 'w') macros.update(all_flash_map()) macros.update(all_debug()) - macros.update(led(led_default, led_max)) + macros.update(led('led', led_default, range(0,led_max+1))) + macros.update(led('led216', 2, { 16 })) macros.update(sdk()) + if boardfilteropt or excludeboards: + print('#') + print('# Do not create pull-requests with this abridged file!') + print('# Do as instructed further down.') + print('#') + + out = "" + for a in sys.argv: + out += " " + a + print('# Abridged boards.txt or boards.local.txt created by:' + out) + out = "" + for a in boardlist: + out += " " + a + print('# The following boards were included: ' + out) + print('#') + + print('#') print('# Do not create pull-requests for this file only, CI will not accept them.') print('# You *must* edit/modify/run ' + os.path.basename(sys.argv[0]) + ' to regenerate boards.txt.') print('# All modified files after running with option "--allgen" must be included in the pull-request.') print('#') print('') + # With Arduino IDE 1.8.7 the order of the menu items will be honored from the tools pull down list. print('menu.BoardModel=Model') + print('menu.ESPModule=Module') + print('menu.led=Builtin Led') print('menu.baud=Upload Speed') print('menu.xtal=CPU Frequency') print('menu.CrystalFreq=Crystal Frequency') @@ -1413,19 +1560,22 @@ def all_boards (): print('menu.FlashMode=Flash Mode') print('menu.FlashFreq=Flash Frequency') print('menu.ResetMethod=Reset Method') - print('menu.ESPModule=Module') print('menu.dbg=Debug port') print('menu.lvl=Debug Level') print('menu.ip=lwIP Variant') print('menu.vt=VTables') print('menu.exception=Exceptions') - print('menu.led=Builtin Led') print('menu.wipe=Erase Flash') print('menu.sdk=Espressif FW') print('menu.ssl=SSL Support') print('') - for id in boards: + missingboards = [] + for id in boardlist: + if id not in boards: + missingboards += [ id ]; + continue + print('##############################################################') board = boards[id] print(id + '.name=' + board['name']) @@ -1463,10 +1613,19 @@ def all_boards (): print('') - if boardsgen: + if boardsgen or boardslocalgen: sys.stdout.close() sys.stdout = realstdout + + if missingboards: + print("No board definitions were found for the following boards:") + print(missingboards) + print("") + + if boardsgen: print("generated: boards.txt") + else: + print("generated: boards.local.txt") ################################################################ @@ -1490,7 +1649,7 @@ def package (): substitution = '"boards": [\n' board_items = [' {\n "name": "%s"\n }' % boards[id]['name'] for id in boards] - substitution += ',\n'.join(board_items) + substitution += ',\n'.join(board_items) substitution += '\n ],' newfilestr = re.sub(r'"boards":[^\]]*\],', substitution, filestr, re.MULTILINE) @@ -1498,7 +1657,7 @@ def package (): # To get consistent indent/formatting read the JSON and write it out programattically if packagegen: with open(pkgfname, 'w') as package_file: - filejson = json.loads(filestr, object_pairs_hook=collections.OrderedDict) + filejson = json.loads(newfilestr, object_pairs_hook=collections.OrderedDict) package_file.write(json.dumps(filejson, indent=3, separators=(',',': '))) print("updated: %s" % pkgfname) else: @@ -1544,6 +1703,16 @@ def doc (): sys.stdout = realstdout print("generated: doc/boards.rst") +################################################################ + +def boardnames (): + print('# Available board names. Delete or comment out the boards you do not need:') + + for id in boards: + print('{: <20s} # {}'.format(id, boards[id]['name'])) + + sys.exit(0) + ################################################################ # help / usage @@ -1557,22 +1726,27 @@ def usage (name,ret): print(" --lwip - preferred default lwIP version (default %d)" % lwip) print(" --led - preferred default builtin led for generic boards (default %d)" % led_default) print(" --board - board to modify:") + print(" --filter - create a short boards.txt based on the boards listed in ") + print(" --xfilter - create a short boards.txt excluding the boards listed in ") + print(" (For --filter or --xfilter use only one)") print(" --speed - change default serial speed") print(" --customspeed - new serial speed for all boards") print(" --nofloat - disable float support in printf/scanf") print("") print(" mandatory option (at least one):") print("") - print(" --boards - show boards.txt") - print(" --boardsgen - replace boards.txt") - print(" --ld - show ldscripts") - print(" --ldgen - replace ldscripts") - print(" --package - show package") - print(" --packagegen - replace board:[] in package") - print(" --doc - shows doc/boards.rst") - print(" --docgen - replace doc/boards.rst") - print(" --allgen - generate and replace everything") - print(" (useful for pushing on github)") + print(" --boards - show boards.txt") + print(" --boardsgen - replace boards.txt") + print(" --boardslocalgen - replace boards.local.txt instead of boards.txt") + print(" --boardnames - prints a list of board names, one per line") + print(" --ld - show ldscripts") + print(" --ldgen - replace ldscripts") + print(" --package - show package") + print(" --packagegen - replace board:[] in package") + print(" --doc - shows doc/boards.rst") + print(" --docgen - replace doc/boards.rst") + print(" --allgen - generate and replace everything") + print(" (useful for pushing on github)") print("") out = "" @@ -1607,6 +1781,14 @@ ldgen = False ldshow = False boardsgen = False boardsshow = False + +boardlist = [] +boardfilterfile = "" +boardfilteropt = False +excludeboardlist = [] +excludeboards = False +boardslocalgen = False + packageshow = False packagegen = False docshow = False @@ -1620,6 +1802,7 @@ try: opts, args = getopt.getopt(sys.argv[1:], "h", [ "help", "lwip=", "led=", "speed=", "board=", "customspeed=", "nofloat", "noextra4kheap", "allowWPS", + "boardslocalgen", "filter=", "xfilter=", "boardnames", "ld", "ldgen", "boards", "boardsgen", "package", "packagegen", "doc", "docgen", "allgen"] ) except getopt.GetoptError as err: @@ -1634,6 +1817,9 @@ for o, a in opts: if o in ("-h", "--help"): usage(sys.argv[0], 0) + elif o in ("--boardnames"): + boardnames() + elif o in ("--lwip"): lwip = a @@ -1651,6 +1837,14 @@ for o, a in opts: usage(sys.argv[0], 1) board = a + elif o in ("--filter"): + boardfilteropt = True + boardfilterfile = a + + elif o in ("--xfilter"): + excludeboards = True + boardfilterfile = a + elif o in ("--speed"): if board == no: print("board not set") @@ -1680,6 +1874,10 @@ for o, a in opts: boardsshow = True boardsgen = True + elif o in ("--boardslocalgen"): + boardsshow = True + boardslocalgen = True + elif o in ("--package"): packageshow = True @@ -1709,6 +1907,45 @@ for o, a in opts: #### ^^^^ cmdline parsing ends +#### vvvv Filter file processing if we have one + +if boardfilteropt and excludeboards: + print('Specify either --filter or --xfilter, not both.') + usage(sys.argv[0], 1) + +if boardfilteropt or excludeboards: + if not os.path.isfile(boardfilterfile): + print('Filter file missing: ', boardfilterfile) + usage(sys.argv[0], 1) + + f = open(boardfilterfile, 'r') + for line in f: + a = line.split('#', 1)[0].strip() + if a != '': + boardlist += [ a ] + f.close() + + if not boardslocalgen: + if boardfilteropt: + for name in requiredboards: + if name not in boardlist: + boardlist.append(name) + else: + # excludeboards: + for name in requiredboards: + if name in boardlist: + boardlist.remove(name) + + if boardfilteropt: + print('Applying keep filter list:') + else: + print('Applying exclude filter list:') + + print(boardlist) + print('') + +#### ^^^^ Filter file processing finished + did = False if ldshow: @@ -1718,6 +1955,13 @@ if ldshow: if boardsshow: ldshow = False ldgen = False + if not boardfilteropt: + if excludeboards: + excludeboardlist = boardlist + boardlist = [] + for b in boards: + if b not in excludeboardlist: + boardlist += [ b ] all_boards() did = True diff --git a/tools/elf2bin.py b/tools/elf2bin.py index e4423176e..9c4a1b2ce 100755 --- a/tools/elf2bin.py +++ b/tools/elf2bin.py @@ -30,6 +30,9 @@ fmodeb = { 'dout': 3, 'dio': 2, 'qout': 1, 'qio': 0 } ffreqb = { '40': 0, '26': 1, '20': 2, '80': 15 } fsizeb = { '512K': 0, '256K': 1, '1M': 2, '2M': 3, '4M': 4, '8M': 8, '16M': 9 } +crcsize_offset = 4088 +crcval_offset = 4092 + def get_elf_entry(elf, path): p = subprocess.Popen([path + "/xtensa-lx106-elf-readelf", '-h', elf], stdout=subprocess.PIPE, universal_newlines=True ) lines = p.stdout.readlines() @@ -90,10 +93,53 @@ def write_bin(out, elf, segments, to_addr, flash_mode, flash_size, flash_freq, p out.write(bytearray([0])) out.write(bytearray([checksum])) if to_addr != 0: + if total_size + 8 > to_addr: + raise Exception('Bin image of ' + elf + ' is too big, actual size ' + str(total_size + 8) + ', target size ' + str(to_addr) + '.') while total_size < to_addr: out.write(bytearray([0xaa])) total_size += 1 +def crc8266(ldata): + "Return the CRC of ldata using same algorithm as eboot" + crc = 0xffffffff + idx = 0 + while idx < len(ldata): + byte = int(ldata[idx]) + idx = idx + 1 + for i in [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]: + bit = crc & 0x80000000 + if (byte & i) != 0: + if bit == 0: + bit = 1 + else: + bit = 0 + crc = int(crc << 1) & 0xffffffff + if bit != 0: + crc = int(crc ^ 0x04c11db7) + return crc + +def store_word(raw, offset, val): + "Place a 4-byte word in 8266-dependent order in the raw image" + raw[offset] = val & 255 + raw[offset + 1] = (val >> 8) & 255 + raw[offset + 2] = (val >> 16) & 255 + raw[offset + 3] = (val >> 24) & 255 + return raw + +def add_crc(out): + with open(out, "rb") as binfile: + raw = bytearray(binfile.read()) + + # Zero out the spots we're going to overwrite to be idempotent + raw = store_word(raw, crcsize_offset, 0) + raw = store_word(raw, crcval_offset, 0) + crc = crc8266(raw) + raw = store_word(raw, crcsize_offset, len(raw)) + raw = store_word(raw, crcval_offset, int(crc)) + + with open(out, "wb") as binfile: + binfile.write(raw) + def main(): parser = argparse.ArgumentParser(description='Create a BIN file from eboot.elf and Arduino sketch.elf for upload by esptool.py') parser.add_argument('-e', '--eboot', action='store', required=True, help='Path to the Arduino eboot.elf bootloader') @@ -113,6 +159,9 @@ def main(): write_bin(out, args.app, ['.irom0.text', '.text', '.text1', '.data', '.rodata'], 0, args.flash_mode, args.flash_size, args.flash_freq, args.path) out.close() + # Because the CRC includes both eboot and app, can only calculate it after the entire BIN generated + add_crc(args.out) + return 0 diff --git a/tools/esptool b/tools/esptool index 1319c49ad..de30f21a2 160000 --- a/tools/esptool +++ b/tools/esptool @@ -1 +1 @@ -Subproject commit 1319c49adb2fe99d2981151ff781930d6ed62729 +Subproject commit de30f21a222ec62f5a023dd955439b4f57702768 diff --git a/tools/get.py b/tools/get.py index 74b6b510d..af39a10f3 100755 --- a/tools/get.py +++ b/tools/get.py @@ -121,6 +121,9 @@ def main(): if len(sys.argv) == 2: if sys.argv[1] == "-q": verbose = False + # Remove a symlink generated in 2.6.3 which causes later issues since the tarball can't properly overwrite it + if (os.path.exists('python3/python3')): + os.unlink('python3/python3') print('Platform: {0}'.format(identify_platform())) tools_to_download = load_tools_list('../package/package_esp8266com_index.template.json', identify_platform()) mkdir_p(dist_dir) diff --git a/tools/platformio-build.py b/tools/platformio-build.py index 6c52fd670..c595497cb 100644 --- a/tools/platformio-build.py +++ b/tools/platformio-build.py @@ -180,6 +180,16 @@ elif "PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191024" in flatten_cppdefines: CPPDEFINES=[("NONOSDK22x_191024", 1)], LIBPATH=[join(FRAMEWORK_DIR, "tools", "sdk", "lib", "NONOSDK22x_191024")] ) +elif "PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191105" in flatten_cppdefines: + env.Append( + CPPDEFINES=[("NONOSDK22x_191105", 1)], + LIBPATH=[join(FRAMEWORK_DIR, "tools", "sdk", "lib", "NONOSDK22x_191105")] + ) +elif "PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_191122" in flatten_cppdefines: + env.Append( + CPPDEFINES=[("NONOSDK22x_191122", 1)], + LIBPATH=[join(FRAMEWORK_DIR, "tools", "sdk", "lib", "NONOSDK22x_191122")] + ) else: #(default) if "PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703" in flatten_cppdefines: env.Append( CPPDEFINES=[("NONOSDK22x_190703", 1)], @@ -254,6 +264,9 @@ app_ld = env.Command( "Generating LD script $TARGET")) env.Depends("$BUILD_DIR/$PROGNAME$PROGSUFFIX", app_ld) +if not env.BoardConfig().get("build.ldscript", ""): + env.Replace(LDSCRIPT_PATH=env.BoardConfig().get("build.arduino.ldscript", "")) + # # Dynamic core_version.h for staging builds # diff --git a/tools/sdk/include/bearssl/bearssl_ec.h b/tools/sdk/include/bearssl/bearssl_ec.h index f954309eb..acd3a2bf5 100644 --- a/tools/sdk/include/bearssl/bearssl_ec.h +++ b/tools/sdk/include/bearssl/bearssl_ec.h @@ -108,7 +108,7 @@ extern "C" { * * - The multipliers (integers) MUST be lower than the subgroup order. * If this property is not met, then the result is indeterminate, - * but an error value is not ncessearily returned. + * but an error value is not necessarily returned. * * * ## ECDSA diff --git a/tools/sdk/include/bearssl/bearssl_git.h b/tools/sdk/include/bearssl/bearssl_git.h index e494ac683..eb4e910d8 100644 --- a/tools/sdk/include/bearssl/bearssl_git.h +++ b/tools/sdk/include/bearssl/bearssl_git.h @@ -1,2 +1,2 @@ // Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile -#define BEARSSL_GIT 89454af +#define BEARSSL_GIT 5c771be diff --git a/tools/sdk/include/bearssl/bearssl_ssl.h b/tools/sdk/include/bearssl/bearssl_ssl.h index fe3f6be2f..d760dff2d 100644 --- a/tools/sdk/include/bearssl/bearssl_ssl.h +++ b/tools/sdk/include/bearssl/bearssl_ssl.h @@ -2114,7 +2114,7 @@ void br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len); /** * \brief Get buffer for received application data. * - * If the engine has received application data from the peer, hen this + * If the engine has received application data from the peer, then this * call returns a pointer to the buffer from where such data shall be * read, and its length is written in `*len`. Otherwise, `*len` is set * to 0 and `NULL` is returned. diff --git a/tools/sdk/ld/eagle.flash.2m64.ld b/tools/sdk/ld/eagle.flash.2m64.ld new file mode 100644 index 000000000..61a94b26d --- /dev/null +++ b/tools/sdk/ld/eagle.flash.2m64.ld @@ -0,0 +1,28 @@ +/* Flash Split for 2M chips */ +/* sketch @0x40200000 (~1019KB) (1044464B) */ +/* empty @0x402FEFF0 (~964KB) (987152B) */ +/* spiffs @0x403F0000 (~44KB) (45056B) */ +/* eeprom @0x403FB000 (4KB) */ +/* rfcal @0x403FC000 (4KB) */ +/* wifi @0x403FD000 (12KB) */ + +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 = 0x40201010, len = 0xfeff0 +} + +PROVIDE ( _FS_start = 0x403F0000 ); +PROVIDE ( _FS_end = 0x403FB000 ); +PROVIDE ( _FS_page = 0x100 ); +PROVIDE ( _FS_block = 0x1000 ); +PROVIDE ( _EEPROM_start = 0x403fb000 ); +/* The following symbols are DEPRECATED and will be REMOVED in a future release */ +PROVIDE ( _SPIFFS_start = 0x403F0000 ); +PROVIDE ( _SPIFFS_end = 0x403FB000 ); +PROVIDE ( _SPIFFS_page = 0x100 ); +PROVIDE ( _SPIFFS_block = 0x1000 ); + +INCLUDE "local.eagle.app.v6.common.ld" diff --git a/tools/sdk/lib/NONOSDK22x_191105/commitlog-from-22x-191024.txt.gz b/tools/sdk/lib/NONOSDK22x_191105/commitlog-from-22x-191024.txt.gz new file mode 100644 index 000000000..c6e287781 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/commitlog-from-22x-191024.txt.gz differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libairkiss.a b/tools/sdk/lib/NONOSDK22x_191105/libairkiss.a new file mode 100644 index 000000000..cfdcc8423 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libairkiss.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libcrypto.a b/tools/sdk/lib/NONOSDK22x_191105/libcrypto.a new file mode 100644 index 000000000..8a43cb727 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libcrypto.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libespnow.a b/tools/sdk/lib/NONOSDK22x_191105/libespnow.a new file mode 100644 index 000000000..92f6c9ab1 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libespnow.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libmain.a b/tools/sdk/lib/NONOSDK22x_191105/libmain.a new file mode 100644 index 000000000..2bc985793 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libmain.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libnet80211.a b/tools/sdk/lib/NONOSDK22x_191105/libnet80211.a new file mode 100644 index 000000000..2d49d922e Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libnet80211.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libphy.a b/tools/sdk/lib/NONOSDK22x_191105/libphy.a new file mode 100644 index 000000000..cab912d28 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libphy.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libpp.a b/tools/sdk/lib/NONOSDK22x_191105/libpp.a new file mode 100644 index 000000000..2abbe7a3e Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libpp.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libsmartconfig.a b/tools/sdk/lib/NONOSDK22x_191105/libsmartconfig.a new file mode 100644 index 000000000..95aec76c6 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libsmartconfig.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libwpa.a b/tools/sdk/lib/NONOSDK22x_191105/libwpa.a new file mode 100644 index 000000000..41ad4876f Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libwpa.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libwpa2.a b/tools/sdk/lib/NONOSDK22x_191105/libwpa2.a new file mode 100644 index 000000000..07420c5bf Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libwpa2.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/libwps.a b/tools/sdk/lib/NONOSDK22x_191105/libwps.a new file mode 100644 index 000000000..ef0be1c35 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191105/libwps.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191105/version b/tools/sdk/lib/NONOSDK22x_191105/version new file mode 100644 index 000000000..06b3bba6f --- /dev/null +++ b/tools/sdk/lib/NONOSDK22x_191105/version @@ -0,0 +1 @@ +v2.2.1-113-g1848ef1 (shows as SDK:2.2.2-dev(bb83b9b) in debug mode) diff --git a/tools/sdk/lib/NONOSDK22x_191122/commitlog-from-22x-191122.txt b/tools/sdk/lib/NONOSDK22x_191122/commitlog-from-22x-191122.txt new file mode 100644 index 000000000..39dd282d5 --- /dev/null +++ b/tools/sdk/lib/NONOSDK22x_191122/commitlog-from-22x-191122.txt @@ -0,0 +1,60 @@ +commit a0b131126ba803d0069014698a07e9f2fd3decd6 +Merge: a8d1fcb 1e61d28 +Author: Xu Chun Guang +Date: Fri Nov 22 15:13:18 2019 +0800 + + Merge branch 'feature/add_broadcast_support_for_smartconfig' into 'release/v2.2.x' + + feat(sc): add broadcast support for smartconfig + + See merge request sdk/ESP8266_NONOS_SDK!246 + +commit 1e61d284b621527193303828612c3058be137230 +Author: Chen Wen +Date: Thu Nov 21 16:54:46 2019 +0800 + + feat(sc): add broadcast support for smartconfig + +commit a8d1fcbebda3055a89d7378c3fc3591df4420966 +Merge: 173440a 089fe93 +Author: Xu Chun Guang +Date: Tue Nov 19 16:55:11 2019 +0800 + + Merge branch 'cherry-pick-4bfd0469-2' into 'release/v2.2.x' + + feat: Update phy to 1155 + + See merge request sdk/ESP8266_NONOS_SDK!243 + +commit 173440a5c3ab3763230748010d753e4508db15e9 +Merge: 1848ef1 3c337a0 +Author: Xu Chun Guang +Date: Tue Nov 19 16:53:34 2019 +0800 + + Merge branch 'feature/update_core' into 'release/v2.2.x' + + feat: Update at core to fix bugs + + See merge request sdk/ESP8266_NONOS_SDK!240 + +commit 089fe93b5059588bf0da598644f0a16a5f7b3058 +Author: Xu Chun Guang +Date: Tue Nov 19 08:48:39 2019 +0000 + + Merge branch 'feature/update_phy' into 'master' + + feat: Update phy to 1155 + + See merge request sdk/ESP8266_NONOS_SDK!241 + + (cherry picked from commit 4bfd046942c7162678f9545bb4aa0d6f46f47ea5) + + 56dc26ed feat: Update phy to 1155 + +commit 3c337a008b1e881d0945464dce2b6efdbddf097c +Author: Xu Chun Guang +Date: Tue Nov 19 16:39:00 2019 +0800 + + feat: Update at core to fix bugs + + - fix: TCP data lost when link is disconnect diff --git a/tools/sdk/lib/NONOSDK22x_191122/libairkiss.a b/tools/sdk/lib/NONOSDK22x_191122/libairkiss.a new file mode 100644 index 000000000..cfdcc8423 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libairkiss.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libcrypto.a b/tools/sdk/lib/NONOSDK22x_191122/libcrypto.a new file mode 100644 index 000000000..8a43cb727 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libcrypto.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libespnow.a b/tools/sdk/lib/NONOSDK22x_191122/libespnow.a new file mode 100644 index 000000000..92f6c9ab1 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libespnow.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libmain.a b/tools/sdk/lib/NONOSDK22x_191122/libmain.a new file mode 100644 index 000000000..77b7de1b9 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libmain.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libnet80211.a b/tools/sdk/lib/NONOSDK22x_191122/libnet80211.a new file mode 100644 index 000000000..2d49d922e Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libnet80211.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libphy.a b/tools/sdk/lib/NONOSDK22x_191122/libphy.a new file mode 100644 index 000000000..d01d97c68 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libphy.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libpp.a b/tools/sdk/lib/NONOSDK22x_191122/libpp.a new file mode 100644 index 000000000..2abbe7a3e Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libpp.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libsmartconfig.a b/tools/sdk/lib/NONOSDK22x_191122/libsmartconfig.a new file mode 100644 index 000000000..200925e3e Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libsmartconfig.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libwpa.a b/tools/sdk/lib/NONOSDK22x_191122/libwpa.a new file mode 100644 index 000000000..41ad4876f Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libwpa.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libwpa2.a b/tools/sdk/lib/NONOSDK22x_191122/libwpa2.a new file mode 100644 index 000000000..07420c5bf Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libwpa2.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/libwps.a b/tools/sdk/lib/NONOSDK22x_191122/libwps.a new file mode 100644 index 000000000..ef0be1c35 Binary files /dev/null and b/tools/sdk/lib/NONOSDK22x_191122/libwps.a differ diff --git a/tools/sdk/lib/NONOSDK22x_191122/version b/tools/sdk/lib/NONOSDK22x_191122/version new file mode 100644 index 000000000..e79bf535a --- /dev/null +++ b/tools/sdk/lib/NONOSDK22x_191122/version @@ -0,0 +1 @@ +v2.2.1-119-ga0b1311 (shows as SDK:2.2.2-dev(a58da79) in debug mode) diff --git a/tools/sdk/lib/libbearssl.a b/tools/sdk/lib/libbearssl.a index 773eeaf80..9fa5f9cb4 100644 Binary files a/tools/sdk/lib/libbearssl.a and b/tools/sdk/lib/libbearssl.a differ diff --git a/tools/sdk/lib/liblwip2-1460-feat.a b/tools/sdk/lib/liblwip2-1460-feat.a index 4dc84bf8b..6c231417b 100644 Binary files a/tools/sdk/lib/liblwip2-1460-feat.a and b/tools/sdk/lib/liblwip2-1460-feat.a differ diff --git a/tools/sdk/lib/liblwip2-1460.a b/tools/sdk/lib/liblwip2-1460.a index 95c171203..1e56d9391 100644 Binary files a/tools/sdk/lib/liblwip2-1460.a and b/tools/sdk/lib/liblwip2-1460.a differ diff --git a/tools/sdk/lib/liblwip2-536-feat.a b/tools/sdk/lib/liblwip2-536-feat.a index 6de957e3e..fe3218fa7 100644 Binary files a/tools/sdk/lib/liblwip2-536-feat.a and b/tools/sdk/lib/liblwip2-536-feat.a differ diff --git a/tools/sdk/lib/liblwip2-536.a b/tools/sdk/lib/liblwip2-536.a index 04b92dc84..85c3db3bd 100644 Binary files a/tools/sdk/lib/liblwip2-536.a and b/tools/sdk/lib/liblwip2-536.a differ diff --git a/tools/sdk/lib/liblwip6-1460-feat.a b/tools/sdk/lib/liblwip6-1460-feat.a index 3256c5f9b..995020bde 100644 Binary files a/tools/sdk/lib/liblwip6-1460-feat.a and b/tools/sdk/lib/liblwip6-1460-feat.a differ diff --git a/tools/sdk/lib/liblwip6-536-feat.a b/tools/sdk/lib/liblwip6-536-feat.a index 4c8fea615..5e901a687 100644 Binary files a/tools/sdk/lib/liblwip6-536-feat.a and b/tools/sdk/lib/liblwip6-536-feat.a differ diff --git a/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a b/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a index 9c879cdeb..1562ca809 100644 Binary files a/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a and b/tools/sdk/libc/xtensa-lx106-elf/lib/libc.a differ diff --git a/tools/sdk/lwip2/README.md b/tools/sdk/lwip2/README.md index 8f17da128..9ae52ee43 100644 --- a/tools/sdk/lwip2/README.md +++ b/tools/sdk/lwip2/README.md @@ -13,5 +13,3 @@ glue and lwIP debug options are in builder/glue/gluedebug.h MSS values are in builder/Makefile.arduino MSS values in boards.txt are only informative - -current lwip2 submodule repository: https://github.com/d-a-v/esp82xx-nonos-linklayer/tree/arduino-2.4.1 diff --git a/tools/sdk/lwip2/builder b/tools/sdk/lwip2/builder index 354887a25..92add5010 160000 --- a/tools/sdk/lwip2/builder +++ b/tools/sdk/lwip2/builder @@ -1 +1 @@ -Subproject commit 354887a25f83064dc0c795e11704190845812713 +Subproject commit 92add5010fc329cbfbbcb1ce713108451cf9fc8c diff --git a/tools/sdk/lwip2/include/lwip-git-hash.h b/tools/sdk/lwip2/include/lwip-git-hash.h index 42aca1818..8a40c5e20 100644 --- a/tools/sdk/lwip2/include/lwip-git-hash.h +++ b/tools/sdk/lwip2/include/lwip-git-hash.h @@ -1,5 +1,5 @@ // generated by makefiles/make-lwip2-hash #ifndef LWIP_HASH_H #define LWIP_HASH_H -#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-16-ge23a07e" +#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-30-g92add50" #endif // LWIP_HASH_H diff --git a/tools/sdk/lwip2/include/lwip/priv/tcp_priv.h b/tools/sdk/lwip2/include/lwip/priv/tcp_priv.h index 72f9126d4..394d9633a 100644 --- a/tools/sdk/lwip2/include/lwip/priv/tcp_priv.h +++ b/tools/sdk/lwip2/include/lwip/priv/tcp_priv.h @@ -357,7 +357,7 @@ extern struct tcp_pcb ** const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; #if TCP_DEBUG_PCB_LISTS #define TCP_REG(pcbs, npcb) do {\ struct tcp_pcb *tcp_tmp_pcb; \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %"U16_F"\n", (void *)(npcb), (npcb)->local_port)); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %" U16_F "\n", (void *)(npcb), (npcb)->local_port)); \ for (tcp_tmp_pcb = *(pcbs); \ tcp_tmp_pcb != NULL; \ tcp_tmp_pcb = tcp_tmp_pcb->next) { \ diff --git a/tools/sdk/lwip2/include/lwipopts.h b/tools/sdk/lwip2/include/lwipopts.h index e2ae90030..6ee039f7c 100644 --- a/tools/sdk/lwip2/include/lwipopts.h +++ b/tools/sdk/lwip2/include/lwipopts.h @@ -1402,7 +1402,7 @@ * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. */ #if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__ -#define TCP_LISTEN_BACKLOG 0 +#define TCP_LISTEN_BACKLOG LWIP_FEATURES // 0 #endif /** @@ -2278,6 +2278,12 @@ * @ingroup lwip_opts_infrastructure * @{ */ +/** + * LWIP_CHKSUM_ALGORITHM==3: Checksum algorithm fastest for ESP8266 + */ +#if !defined LWIP_CHKSUM_ALGORITHM || defined __DOXYGEN__ +#define LWIP_CHKSUM_ALGORITHM 3 // 2 +#endif /** * LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled * per netif. @@ -3573,7 +3579,7 @@ extern "C" { #define SNTP_SUPPRESS_DELAY_CHECK 1 #define SNTP_UPDATE_DELAY_DEFAULT 3600000 // update delay defined by a default weak function #define SNTP_UPDATE_DELAY sntp_update_delay_MS_rfc_not_less_than_15000() -extern uint32_t SNTP_UPDATE_DELAY; +uint32_t SNTP_UPDATE_DELAY; #if LWIP_FEATURES // esp8266/arduino/lwip-1.4 had 3 possible SNTP servers (constant was harcoded) @@ -3591,7 +3597,7 @@ extern uint32_t SNTP_UPDATE_DELAY; #define SNTP_STARTUP_DELAY 1 // enable startup delay #define SNTP_STARTUP_DELAY_FUNC_DEFAULT 0 // to 0 by default via a default weak function #define SNTP_STARTUP_DELAY_FUNC sntp_startup_delay_MS_rfc_not_less_than_60000() -extern uint32_t SNTP_STARTUP_DELAY_FUNC; +uint32_t SNTP_STARTUP_DELAY_FUNC; /* -------------------------------------------------- @@ -3611,7 +3617,7 @@ struct netif; #error LWIP_ERR_T definition should come from lwip1.4 from espressif #endif //#define LWIP_ERR_T s8 -LWIP_ERR_T lwip_unhandled_packet (struct pbuf* pbuf, struct netif* netif) __attribute__((weak)); +LWIP_ERR_T lwip_unhandled_packet (struct pbuf* pbuf, struct netif* netif); /* -------------------------------------------------- diff --git a/tools/sdk/ssl/bearssl b/tools/sdk/ssl/bearssl index 89454af34..5c771bed8 160000 --- a/tools/sdk/ssl/bearssl +++ b/tools/sdk/ssl/bearssl @@ -1 +1 @@ -Subproject commit 89454af34e3e61ddfc9837f3da5a0bc8ed44c3aa +Subproject commit 5c771bed8b11b968e2f75f26b9b00de51f2e9333 diff --git a/tools/sdk/uzlib b/tools/sdk/uzlib new file mode 160000 index 000000000..80765a42d --- /dev/null +++ b/tools/sdk/uzlib @@ -0,0 +1 @@ +Subproject commit 80765a42d657fcd3a24e036ac9822f9dbf862449 diff --git a/tools/upload.py b/tools/upload.py index 1cc911a70..0d57a63c9 100755 --- a/tools/upload.py +++ b/tools/upload.py @@ -3,11 +3,12 @@ # Wrapper for Arduino core / others that can call esptool.py possibly multiple times # Adds pyserial to sys.path automatically based on the path of the current file -# First parameter is pyserial path, second is esptool path, then a series of command arguments separated with --end -# i.e. upload.py tools/pyserial tools/esptool erase_flash --end write_flash file 0x0 --end +# First parameter is pyserial path, second is esptool path, then a series of command arguments +# i.e. upload.py tools/pyserial tools/esptool write_flash file 0x0 import sys import os +import tempfile sys.argv.pop(0) # Remove executable name toolspath = os.path.dirname(os.path.realpath(__file__)).replace('\\', '/') # CWD in UNIX format @@ -16,20 +17,52 @@ try: sys.path.insert(0, toolspath + "/esptool") # Add esptool dir to search path import esptool # If this fails, we can't continue and will bomb below except: - sys.stderr.write("Error in command line, need pyserial path as 1st arg and esptool path as 2nd.\n") + sys.stderr.write("pyserial or esptool directories not found next to this upload.py tool.\n") sys.exit(1) -fakeargs = []; +cmdline = [] +write_option = '' +write_addr = '0x0' +erase_addr = '' +erase_len = '' + while len(sys.argv): - if sys.argv[0] == '--end': - esptool.main(fakeargs) - sys.argv.pop(0) # Remove --end - fakeargs = [] - else: - # We silently replace the 921kbaud setting with 460k to enable backward - # compatibility with the old esptool-ck.exe. Esptool.py doesn't seem - # work reliably at 921k, but is still significantly faster at 460kbaud. - thisarg = sys.argv.pop(0) - if thisarg == "921600": - thisarg = "460800" - fakeargs = fakeargs + [thisarg] + thisarg = sys.argv.pop(0) + + # We silently replace the 921kbaud setting with 460k to enable backward + # compatibility with the old esptool-ck.exe. Esptool.py doesn't seem + # work reliably at 921k, but is still significantly faster at 460kbaud. + if thisarg == "921600": + thisarg = "460800" + + # 'erase_flash' command is translated to the write_flash --erase-all option + # https://github.com/esp8266/Arduino/issues/6755#issuecomment-553208688 + if thisarg == "erase_flash": + write_option = '--erase-all' + elif thisarg == 'erase_region': + erase_addr = sys.argv.pop(0) + erase_len = sys.argv.pop(0) + elif thisarg == 'write_flash': + write_addr = sys.argv.pop(0) + binary = sys.argv.pop(0) + elif len(thisarg): + cmdline = cmdline + [thisarg] + +cmdline = cmdline + ['write_flash'] +if len(write_option): + cmdline = cmdline + [write_option] +cmdline = cmdline + [write_addr, binary] + +erase_file = '' +if len(erase_addr): + # Generate temporary empty (0xff) file + eraser = tempfile.mkstemp() + erase_file = eraser[1] + os.write(eraser[0], bytearray([255] * int(erase_len, 0))) + os.close(eraser[0]) + cmdline = cmdline + [ erase_addr, erase_file ] + +esptool.main(cmdline) + +if len(erase_file): + os.remove(erase_file) diff --git a/variants/eduinowifi/pins_arduino.h b/variants/eduinowifi/pins_arduino.h new file mode 100644 index 000000000..e64940910 --- /dev/null +++ b/variants/eduinowifi/pins_arduino.h @@ -0,0 +1,57 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + Modified for ESP8266 platform by Ivan Grokhotkov, 2014-2015. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#define PIN_WIRE_SDA (4) +#define PIN_WIRE_SCL (5) + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +//new ESP-12E GPIO2 +#define LED_BUILTIN 2 + +static const uint8_t D0 = 3; +static const uint8_t D1 = 1; +static const uint8_t D2 = 16; +static const uint8_t D3 = 5; +static const uint8_t D4 = 4; +static const uint8_t D5 = 14; +static const uint8_t D6 = 12; +static const uint8_t D7 = 13; +static const uint8_t D8 = 0; +static const uint8_t D9 = 2; +static const uint8_t D10 = 15; +static const uint8_t D11 = 13; +static const uint8_t D12 = 12; +static const uint8_t D13 = 14; +static const uint8_t D14 = 4; +static const uint8_t D15 = 5; + +#include "../generic/common.h" + +#endif /* Pins_Arduino_h */ diff --git a/variants/itead/pins_arduino.h b/variants/itead/pins_arduino.h new file mode 100644 index 000000000..d58c17a6b --- /dev/null +++ b/variants/itead/pins_arduino.h @@ -0,0 +1,53 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + Modified for ESP8266 platform by Ivan Grokhotkov, 2014-2015. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#if defined(ARDUINO_ESP8266_SONOFF_SV) +#define PIN_WIRE_SCL (5) +static const uint8_t SCL = PIN_WIRE_SCL; +#endif + +#if defined(ARDUINO_ESP8266_SONOFF_TH) || defined(ARDUINO_ESP8266_SONOFF_BASIC) +#define PIN_WIRE_SCL (14) +static const uint8_t SCL = PIN_WIRE_SCL; +#endif + +#if defined(ARDUINO_ESP8266_SONOFF_TH) || defined(ARDUINO_ESP8266_SONOFF_SV) +#define PIN_WIRE_SDA (4) +static const uint8_t SDA = PIN_WIRE_SDA; +#endif + +static const uint8_t BUILTIN_BUTTON = 0; +static const uint8_t BUILTIN_RELAY = 12; + +#define BUTTON_BUILTIN (0) +#define LED_BUILTIN (13) +#define RELAY_BUILTIN (12) + +#include "../generic/common.h" + +#endif /* Pins_Arduino_h */ diff --git a/variants/nodemcu/pins_arduino.h b/variants/nodemcu/pins_arduino.h index ceb30691c..dec496838 100644 --- a/variants/nodemcu/pins_arduino.h +++ b/variants/nodemcu/pins_arduino.h @@ -32,7 +32,10 @@ static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; -#define LED_BUILTIN 16 +#ifndef LED_BUILTIN +#define LED_BUILTIN 2 +#endif +#define LED_BUILTIN_AUX 16 static const uint8_t D0 = 16; static const uint8_t D1 = 5;