diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d9554c31..5bfff910 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -9,32 +9,44 @@ on: - '**.md' jobs: - build: + build_esp32: runs-on: ubuntu-latest strategy: fail-fast: false matrix: - environments: - - d1-mini-esp8266_ili9341 - - arduitouch-esp32_ili9341 - - d1-mini-esp32_ili9341 - - esp32-one_st7796 - - esp32-touchdown - - freetouchdeck - - huzzah32-featherwing-24 - - huzzah32-featherwing-35 - - lanbon_l8 - - lolin-d32-pro_ili9341 - - m5stack-core2 - - makerfabs-tft35-cap - - ttgo-t7-v1.5_ili9341 - - wt32-sc01 - - yeacreate-nscreen32 - - linux_sdl_64bits + environment: + - env: arduitouch-esp32_ili9341 + out: arduitouch + - env: d1-mini-esp32_ili9341 + out: d1-mini-esp32 + - env: esp32-one_st7796 + out: esp32-one + - env: esp32-touchdown + out: esp32-touchdown + - env: freetouchdeck + out: freetouchdeck + - out: featherwing + env: "huzzah32-featherwing-24 -e huzzah32-featherwing-35" + - env: lanbon_l8 + out: lanbon_l8 + - env: lolin-d32-pro_ili9341 + out: lolin-d32-pro + - env: m5stack-core2 + out: m5stack + - env: makerfabs-tft35-cap + out: makerfabs-tft + - env: ttgo-t7-v1.5_ili9341 + out: ttgo-t7 + - env: wt32-sc01 + out: wt32-sc01 + - env: yeacreate-nscreen32 + out: yeacreate steps: - uses: actions/checkout@v2 + with: + submodules: 'true' - name: Cache pip uses: actions/cache@v2 with: @@ -53,17 +65,9 @@ jobs: run: | python -m pip install --upgrade pip pip install --upgrade platformio - - name: Enable ESP platforms from platformio_override-template.ini + - name: Enable ESP32 platforms from platformio_override-template.ini run: | - sed 's/; user_setups\/esp/user_setups\/esp/g' platformio_override-template.ini > platformio_override.ini - - name: Enable Linux platform from platformio_override.ini - run: | - sed -i 's/; user_setups\/linux/user_setups\/linux/g' platformio_override.ini - mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src - - name: Install SDL2 library - run: | - sudo apt-get update - sudo apt-get install libsdl2-dev + sed 's/; user_setups\/esp32/user_setups\/esp32/g' platformio_override-template.ini > platformio_override.ini - name: List all files in current folder run: | ls -la @@ -71,11 +75,11 @@ jobs: run: | cat platformio_override.ini - name: Run PlatformIO - run: pio run -e ${{ matrix.environments }} + run: pio run -e ${{ matrix.environment.env }} - name: Upload output file uses: actions/upload-artifact@v2 with: - name: ${{ matrix.environments }} + name: ${{ matrix.environment.out }} path: build_output/firmware/*.bin #- name: Create release and upload firmware # run: | @@ -88,3 +92,51 @@ jobs: # hub release create "${assets[@]}" -m "$tag_name" "$tag_name" # env: # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + linux_build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: 'true' + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + - name: Enable Linux platform from platformio_override.ini + run: | + sed 's/; user_setups\/linux/user_setups\/linux/g' platformio_override-template.ini > platformio_override.ini + mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + - name: Install SDL2 library + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev + - name: List all files in current folder + run: | + ls -la + - name: Cat platformio_override.ini + run: | + cat platformio_override.ini + - name: Enable Linux platform from platformio_override.ini + run: | + sed -i 's/; user_setups\/linux/user_setups\/linux/g' platformio_override.ini + mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + - name: Install SDL2 library + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev + - name: Run PlatformIO + run: pio run -e linux_sdl_64bits \ No newline at end of file diff --git a/.github/workflows/build_linux.yaml b/.github/workflows/build_linux.yaml new file mode 100644 index 00000000..c0b47614 --- /dev/null +++ b/.github/workflows/build_linux.yaml @@ -0,0 +1,74 @@ +name: Build branch + +on: + workflow_dispatch: + paths-ignore: + - '**.md' + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + environments: + - linux_sdl_64bits + + steps: + - uses: actions/checkout@v2 + with: + submodules: 'true' + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + # - name: Enable ESP platforms from platformio_override-template.ini + # run: | + # sed 's/; user_setups\/esp/user_setups\/esp/g' platformio_override-template.ini > platformio_override.ini + - name: Enable Linux platform from platformio_override.ini + run: | + sed -i 's/; user_setups\/linux/user_setups\/linux/g' platformio_override.ini + mkdir -p .pio/libdeps/linux_sdl_64bits/paho/src + - name: Install SDL2 library + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev + - name: List all files in current folder + run: | + ls -la + - name: Cat platformio_override.ini + run: | + cat platformio_override.ini + - name: Run PlatformIO + run: pio run -e ${{ matrix.environments }} + # - name: Upload output file + # uses: actions/upload-artifact@v2 + # with: + # name: ${{ matrix.environments }} + # path: build_output/firmware/*.bin + #- name: Create release and upload firmware + # run: | + # set -x + # assets=() + # for asset in build_output/firmware/*.bin; do + # assets+=("-a" "$asset") + # done + # tag_name="${GITHUB_REF##*/}" + # hub release create "${assets[@]}" -m "$tag_name" "$tag_name" + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcb39b79..5964a5bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,7 +48,7 @@ jobs: run: | cat platformio_override.ini - name: Run PlatformIO - run: pio run -e lolin-d32-pro_ili9341 -e arduitouch-esp32_ili9341 -e esp32-one_st7796 -e makerfabs-tft35-cap -e yeacreate-nscreen32 -e d1-mini-esp32_ili9341 -e esp32-touchdown -e freetouchdeck -e huzzah32-featherwing-24 -e huzzah32-featherwing-35 -e lanbon_l8 -e m5stack-core2 -e wt32-sc01 -e d1-mini-esp8266_ili9341 -e linux_sdl_64bits + run: pio run -e lolin-d32-pro_ili9341 -e arduitouch-esp32_ili9341 -e esp32-one_st7796 -e makerfabs-tft35-cap -e yeacreate-nscreen32 -e d1-mini-esp32_ili9341 -e esp32-touchdown -e freetouchdeck -e huzzah32-featherwing-24 -e huzzah32-featherwing-35 -e lanbon_l8 -e m5stack-core2 -e wt32-sc01 -e linux_sdl_64bits - name: Upload output file uses: actions/upload-artifact@v2 with: diff --git a/.gitignore b/.gitignore index e65d6fd8..4b197432 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ data/* !data/vars.css !data/style.css !data/style.css.gz +!data/script.js +!data/script.js.gz src/user_setups/active/* include/user_config_override.h src/user_config_override.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..90d1c1d0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "lib/freetype"] + path = lib/freetype + url = https://github.com/fvanroie/freetype + \ No newline at end of file diff --git a/CHANGLELOG.md b/CHANGLELOG.md index 97f977b6..adfb4d47 100644 --- a/CHANGLELOG.md +++ b/CHANGLELOG.md @@ -1,5 +1,33 @@ # openHASP Changelog +## v0.7.0 + +### Fonts +- Use FreeType fonts from flash +- Use LVGL binary fonts from flash, loaded into PSram +- Removed defunct .zi font support +- Breaking: The UTF codes for the built-in icons have changed from the previous list! +- _Breaking: Font ID is replaced by xxxx?_ + +### Web UI +- Updated to modern responsive design +- Allow for a customizible `vars.css`, `style.css`, `script.js` and `edit.htm` +- _Selectable dark/light theme?_ + +### Commands +- Hide cursor during `antiburn` and `idle` if the pointer is enabled + +### Custom component +- Expose `antiburn` for the CC +- Expose the device URL in discovery messages + +### Architecture +- Moved to Arduino 2.0 with native LittleFS library +- Moved to ESP-IDF 4.4 with fix for FragAttacks CVEs +- Prepare support for ESP32S2 +- Breaking: Removed support for ESP8266 + + ## v0.6.2 ### Initial Setup diff --git a/README.md b/README.md index e5819470..587c89ca 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This project is a re-implementation of the popular HASwitchPlate sketch created The [HASPone][1] project uses a Wemos D1 mini and requires a Nextion/TJC HMI display. This rewrite removes the Nextion/TJC hardware requirement by using the [Light and Versatile Graphics Library][2] on the MCU to drive a commodity display. -openHASP also adds ESP32 and STM32F4 support to take advantage of the additional hardware capabilities. +openHASP uses the ESP32 and STM32F4 to take advantage of the hardware capabilities. ## Demo Screens @@ -25,19 +25,18 @@ openHASP also adds ESP32 and STM32F4 support to take advantage of the additional ## Features -| Feature (v0.6.x) | ESP8266 | ESP32 | STM32F4 -|-------------------------|---------|---------|---------- -| SPI display | :white_check_mark: yes | :white_check_mark: yes | :white_check_mark: yes -| Parallel display | :x: no | :white_check_mark: yes | :white_check_mark: yes -| PWM Screen dimming | :white_check_mark: yes | :white_check_mark: yes | :white_check_mark: yes -| Maximum Page Count | 4 | 12 | 12 -| [Object Types / Widgets][7]| 20 | 20 | 20 -| Dynamic Objects | :white_check_mark: yes | :white_check_mark: yes | :white_check_mark: yes -| Theme Support | yes | yes | yes -| [Custom .zi V5 font][4] | :white_check_mark: yes (latin1) | :white_check_mark: yes (latin1) | no -| MDI Icons | :white_check_mark: yes | :white_check_mark: yes | no -| [PNG images][8] | :x: no | :white_check_mark: yes | :white_check_mark: yes -| Network | :white_check_mark: Wi-Fi | :white_check_mark: Wi-Fi | :white_check_mark: Ethernet +| Feature (v0.6.x) | ESP32 | STM32F4 +|-------------------------|---------|--------- +| SPI display | :white_check_mark: yes | :white_check_mark: yes +| Parallel display | :white_check_mark: yes | :white_check_mark: yes +| PWM Screen dimming | :white_check_mark: yes | :white_check_mark: yes +| Maximum Page Count | 12 | 12 +| [Object Types / Widgets][7]| 20 | 20 +| Dynamic Objects | :white_check_mark: yes | :white_check_mark: yes +| Theme Support | yes | yes +| MDI Icons | :white_check_mark: yes | :white_check_mark: yes +| [PNG images][8] | :white_check_mark: yes | :white_check_mark: yes +| Network | :white_check_mark: Wi-Fi | :white_check_mark: Ethernet ## Getting Started diff --git a/data/script.js b/data/script.js new file mode 100644 index 00000000..9a8e4bea --- /dev/null +++ b/data/script.js @@ -0,0 +1 @@ +function aref(e){setTimeout(function(){ref("")},1e3*e)}function ref(e){var o=(new Date).getTime();return document.getElementById("bmp").src="?a="+e+"&q="+o,!1}function about(){document.getElementById("doc").innerHTML='
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.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Based on the previous work of the following open source developers:
Copyright© 2019 Allen Derusha allen @derusha.orgMIT License
Copyright© 2021 LVGL KftMIT License
Copyright© 2020-2021 Francis Van RoieMIT License
Copyright© 2020 Bodmer (https://github.com/Bodmer) All rights reserved.FreeBSD License
includes parts from the Adafruit_GFX libraryCopyright© 2012 Adafruit Industries. All rights reservedBSD License
Copyright© 2014-2021 Benoit BLANCHONMIT License
Copyright© 2008-2015 Nicholas O'LearyMIT License
Copyright© 2017,2018 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, dhylands, Josha blemasle, mfalkviddMIT License
Copyright© Project NayukiMIT License
Copyright© 2018 Brian T. ParkMIT License
'} \ No newline at end of file diff --git a/data/script.js.gz b/data/script.js.gz new file mode 100644 index 00000000..35c934fd Binary files /dev/null and b/data/script.js.gz differ diff --git a/data/style.css b/data/style.css index d679ee4f..68f4b5d2 100644 --- a/data/style.css +++ b/data/style.css @@ -1 +1,269 @@ -:root{--star:url('data:image/svg+xml,')}a.foot:link,a.foot:visited{color:var(--footfg)}input:not([type=file]){background-color:var(--fldbg);color:var(--fldfg)}input[type=checkbox],input[type=radio]{width:1em}select{background-color:var(--fldbg);color:var(--fldfg)}input:invalid{border:1px solid var(--fldred)}body{font-family:verdana;margin:auto;background:var(--bg);color:var(--txt)}.c,body{text-align:center}.clear{clear:both}.foot{background-color:transparent!important;all:revert;float:right;margin:0;font-size:.6em}.red{background-color:var(--btnred)}.red:focus,.red:hover{background-color:var(--btnredhi)}#doc{text-align:left;margin:0 auto;display:inline-block;color:var(--txt);width:80%;min-width:300px;max-width:600px;display:table}td{font-size:.87rem;padding-bottom:0;padding-top:0}th{padding-top:.5em}*{box-sizing:border-box}a,input,select,textarea{width:100%;padding:12px;border:1px solid #ccc;border-radius:.6rem;resize:vertical}label{padding:12px 18px 12px 0;display:inline-block}.required{background-image:var(--star);background-size:1.5em 1.5em;background-position:right;background-repeat:no-repeat}a,button,input[type=submit]{padding:12px;border:1px solid var(--btnbrd);border-radius:.6rem;background-color:var(--btnbg);color:var(--btnfg);font-size:1rem;width:100%;margin:12px 0;display:flex;align-items:center;justify-content:center;text-align:center;text-decoration:none}a:hover,button:hover,input[type=submit]:hover{background-color:var(--btnbghi)}.container{background-color:var(--grpbg);color:var(--grpfg);border-radius:.6rem;padding:10px;margin:20px 0}.dist{display:flex;justify-content:space-between;width:100%}.dist > a{flex-grow:1;margin:0 6px}.dist>a:first-child{margin-left:0}.dist>a:last-child{margin-right:0}.col-25{float:left;width:25%;text-align:right;margin:0}.col-75{margin:0;float:left;width:75%}.row:after{content:"";display:table;clear:both}.row{font-size:.833rem;margin:5px}.gap,.row:last-of-type{margin:5px 5px 20px}.error,.info,.success,.validation,.warning{border:1px solid;margin:10px auto;padding:15px 10px 15px 50px;background-repeat:no-repeat;background-position:10px center;max-width:500px}.info{color:#00529B;background-color:#BDE5F8}.success{color:#4F8A10;background-color:#DFF2BF}.warning{color:#9F6000;background-color:#FEEFB3}.error{color:#D8000C;background-color:#FFD2D2}@media screen and (max-width:800px){.col-25,.col-75,input[type=submit]{width:100%;margin-top:0}.col-25{text-align:left}label{padding:5px 18px 5px 0}} \ No newline at end of file +:root { + --star: url('data:image/svg+xml,'); + --trash: url('data:image/svg+xml,') +} + +a.foot:link, +a.foot:visited { + color: var(--footfg) +} + +input:not([type=file]) { + background-color: var(--fldbg); + color: var(--fldfg) +} + +input[type=checkbox], +input[type=radio] { + width: 1em +} + +select { + background-color: var(--fldbg); + color: var(--fldfg) +} + +input:invalid { + border: 1px solid var(--fldred) +} + +body { + font-family: verdana; + margin: auto; + background: var(--bg); + color: var(--txt) +} + +.c, +body { + text-align: center +} + +.clear { + clear: both +} + +.foot { + background-color: transparent!important; + all: revert; + float: right; + margin: 0; + font-size: .6em +} + +#doc>a.red, +button.red { + background-color: var(--btnred) +} + +#doc>a.red:focus, +#doc>a.red:hover, +button.red:focus, +button.red:hover { + background-color: var(--btnredhi) +} + +#doc { + text-align: left; + margin: 0 auto; + display: inline-block; + color: var(--txt); + width: 80%; + min-width: 300px; + max-width: 600px; + display: table +} + +td { + font-size: .87rem; + padding-bottom: 0; + padding-top: 0 +} + +th { + padding-top: .5em +} + +* { + box-sizing: border-box +} + +input, +select, +textarea { + width: 100%; + padding: 12px; + border: 1px solid #ccc; + border-radius: .6rem; + resize: vertical +} + +label { + padding: 12px 18px 12px 0; + display: inline-block +} + +.required { + background-image: var(--star); + background-size: 1.5em 1.5em; + background-position: right; + background-repeat: no-repeat +} + +.edit::before { + content: "\0000a0" +} + +.edit { + background-image: var(--edit); + background-size: 1.5em 1.5em; + background-position: left; + background-repeat: no-repeat; + width: 1.5em; + display: inline-block; + text-decoration: none +} + +.trash::before { + content: "\0000a0" +} + +.trash { + background-image: var(--trash); + background-size: 1.5em 1.5em; + background-position: left; + background-repeat: no-repeat; + width: 1.5em; + display: inline-block; + text-decoration: none +} + +#doc>a, +.dist>a, +button, +input[type=submit] { + padding: 12px; + border: 1px solid var(--btnbrd); + border-radius: .6rem; + background-color: var(--btnbg); + color: var(--btnfg); + font-size: 1rem; + width: 100%; + margin: 12px 0; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + text-decoration: none +} + +#doc>a:hover, +.dist>a:hover, +button:hover, +input[type=submit]:hover { + background-color: var(--btnbghi) +} + +.container { + background-color: var(--grpbg); + color: var(--grpfg); + border-radius: .6rem; + padding: 10px; + margin: 20px 0 +} + +.dist { + display: flex; + justify-content: space-between; + width: 100% +} + +.dist>a { + flex-grow: 1; + margin: 0 6px +} + +.dist>a:first-child { + margin-left: 0 +} + +.dist>a:last-child { + margin-right: 0 +} + +.col-25 { + float: left; + width: 25%; + text-align: right; + margin: 0 +} + +.col-75 { + margin: 0; + float: left; + width: 75% +} + +.row:after { + content: ""; + display: table; + clear: both +} + +.row { + font-size: .833rem; + margin: 5px +} + +.gap, +.row:last-of-type { + margin: 5px 5px 20px +} + +.error, +.info, +.success, +.validation, +.warning { + border: 1px solid; + margin: 10px auto; + padding: 15px 10px 15px 50px; + background-repeat: no-repeat; + background-position: 10px center; + max-width: 500px +} + +.info { + color: #00529B; + background-color: #BDE5F8 +} + +.success { + color: #4F8A10; + background-color: #DFF2BF +} + +.warning { + color: #9F6000; + background-color: #FEEFB3 +} + +.error { + color: #D8000C; + background-color: #FFD2D2 +} + +@media screen and (max-width:800px) { + .col-25, + .col-75, + input[type=submit] { + width: 100%; + margin-top: 0 + } + .col-25 { + text-align: left + } + label { + padding: 5px 18px 5px 0 + } +} \ No newline at end of file diff --git a/data/style.css.gz b/data/style.css.gz index 9a9fe282..de937799 100644 Binary files a/data/style.css.gz and b/data/style.css.gz differ diff --git a/include/hasp_conf.h b/include/hasp_conf.h index 2a58d3c0..b739f249 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -11,6 +11,17 @@ // language specific defines #include "lang/lang.h" +// Lengths +#ifndef MAX_PASSWORD_LENGTH +#define MAX_PASSWORD_LENGTH 64 +#endif +#ifndef MAX_USERNAME_LENGTH +#define MAX_USERNAME_LENGTH 32 +#endif +#ifndef MAX_HOSTNAME_LENGTH +#define MAX_HOSTNAME_LENGTH 128 +#endif + // TFT defines #ifndef TFT_BACKLIGHT_ON #define TFT_BACKLIGHT_ON HIGH @@ -192,7 +203,7 @@ #if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) -#include "lv_zifont.h" +// #include "lv_zifont.h" #endif #endif diff --git a/src/hasp_png.h b/include/hasp_png.h similarity index 91% rename from src/hasp_png.h rename to include/hasp_png.h index 0fa8b8fb..ee1325cd 100644 --- a/src/hasp_png.h +++ b/include/hasp_png.h @@ -12,6 +12,7 @@ extern "C" { #endif +void* lodepng_calloc(size_t num,size_t size); void* lodepng_malloc(size_t size); void* lodepng_realloc(void* ptr, size_t new_size); void lodepng_free(void* ptr); diff --git a/lib/freetype b/lib/freetype new file mode 160000 index 00000000..aa40dd17 --- /dev/null +++ b/lib/freetype @@ -0,0 +1 @@ +Subproject commit aa40dd17b51500448a5601478a4278d21ac74386 diff --git a/lib/lv_lib_freetype/LICENSE b/lib/lv_lib_freetype/LICENSE new file mode 100644 index 00000000..cc227abe --- /dev/null +++ b/lib/lv_lib_freetype/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 LittlevGL + +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. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/lv_lib_freetype/README.md b/lib/lv_lib_freetype/README.md new file mode 100644 index 00000000..2bfbddb4 --- /dev/null +++ b/lib/lv_lib_freetype/README.md @@ -0,0 +1,44 @@ +# FreeType integration with LVGL +Interface to FreeType to generate font bitmaps run time + +## Install FreeType +- Download Freetype from [here](https://sourceforge.net/projects/freetype/files/) +- `make` +- `sudo make install` + +## Add FreeType to your project +- Add include path: `/usr/include/freetype2` (for GCC: `-I/usr/include/freetype2 -L/usr/local/lib`) +- Add library: `freetype` (for GCC: `-L/usr/local/lib -lfreetype`) + +## Usage in LVGL + +To enable cache, set`LV_USE_FT_CACHE_MANAGER 1`in lv_freetype.h. + +```c +/* init freetype library */ +lv_freetype_init(64, 1, 0); + +/*Create a font*/ +lv_ft_info_t info; +info.name = "./lv_lib_freetype/arial.ttf""; +info.size = 16; +info.style = FT_FONT_STYLE_NORMAL; +lv_ft_font_init(&info); + +/*Create style with the new font*/ +static lv_style_t style; +lv_style_init(&style); +lv_style_set_text_font(&style, LV_STATE_DEFAULT, info.font); + +/*Create a label with the new style*/ +lv_obj_t * label = lv_label_create(lv_scr_act(), NULL); +lv_obj_add_style(label, LV_LABEL_PART_MAIN, &style); +lv_label_set_text(label, "Hello world"); + +/* free font */ +//lv_ft_font_destroy(info.font); +``` + +## Learn more +- FreeType [tutorial](https://www.freetype.org/freetype2/docs/tutorial/step1.html) +- LVGL's [font interface](https://docs.lvgl.io/v7/en/html/overview/font.html#add-a-new-font-engine) diff --git a/lib/lv_lib_freetype/arial.ttf b/lib/lv_lib_freetype/arial.ttf new file mode 100644 index 00000000..886789b8 Binary files /dev/null and b/lib/lv_lib_freetype/arial.ttf differ diff --git a/lib/lv_lib_freetype/lv_freetype.c b/lib/lv_lib_freetype/lv_freetype.c new file mode 100644 index 00000000..61f20d5f --- /dev/null +++ b/lib/lv_lib_freetype/lv_freetype.c @@ -0,0 +1,473 @@ +/** + * @file lv_freetype.c + * + */ + +#if defined(ARDUINO_ARCH_ESP32) + +/********************* + * INCLUDES + *********************/ + +#include "lv_freetype.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" + +#if CONFIG_FREERTOS_UNICORE +#define ARDUINO_RUNNING_CORE 0 +#else +#define ARDUINO_RUNNING_CORE 1 +#endif + +/* + * FreeType requires up to 32KB of stack to run, which overflows the stack of 8KB. + * + * We delegate to a FreeRTOS sub-task with a bigger stack. + * + * Parameters are passed via a RequestQueue, and response back via ResponseQueue + * + * The function that uses this scheme is `get_glyph_dsc_cb()`` + * + */ + +QueueHandle_t FTRequestQueue; +QueueHandle_t FTResponseQueue; +TaskHandle_t FTTaskHandle; +void FT_loop_task(void *pvParameters); + +typedef struct FT_glyph_dsc_request { + const lv_font_t * font; + lv_font_glyph_dsc_t * dsc_out; + uint32_t unicode_letter; + uint32_t unicode_letter_next; +} FT_glyph_dsc_request; + +typedef bool FT_glyph_dsc_response; + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static FT_Face face_find_in_list(lv_ft_info_t *info); +static void face_add_to_list(FT_Face face); +static void face_remove_from_list(FT_Face face); + +static void face_generic_finalizer(void* object); +static bool get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, + uint32_t unicode_letter, uint32_t unicode_letter_next); +static const uint8_t * get_glyph_bitmap_cb(const lv_font_t * font, uint32_t unicode_letter); + +#if LV_USE_FT_CACHE_MANAGER +static FT_Error font_face_requester(FTC_FaceID face_id, + FT_Library library_is,FT_Pointer req_data,FT_Face* aface); +#endif + + /********************** + * STATIC VARIABLES + **********************/ +static FT_Library library; + +#if LV_USE_FT_CACHE_MANAGER +static FTC_Manager cache_manager; +static FTC_CMapCache cmap_cache; +static FTC_SBitCache sbit_cache; +static FTC_SBit sbit; +#endif + +static lv_faces_control_t face_control; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +bool lv_freetype_init(FT_UInt max_faces, FT_UInt max_sizes, FT_ULong max_bytes) +{ + face_control.cnt = 0; + face_control.num = max_faces; + _lv_ll_init(&face_control.face_ll, sizeof(FT_Face *)); + + FT_Error error = FT_Init_FreeType(&library); + if (error) { + LV_LOG_ERROR("init freeType error(%d)", error); + return false; + } + +#if LV_USE_FT_CACHE_MANAGER + error = FTC_Manager_New(library, max_faces, max_sizes, + max_bytes, font_face_requester, NULL, &cache_manager); + if (error) { + FT_Done_FreeType(library); + LV_LOG_ERROR("Failed to open cache manager"); + return false; + } + + error = FTC_CMapCache_New(cache_manager, &cmap_cache); + if(error) { + LV_LOG_ERROR("Failed to open Cmap Cache"); + goto Fail; + } + + error = FTC_SBitCache_New(cache_manager, &sbit_cache); + if(error){ + LV_LOG_ERROR("Failed to open sbit cache"); + goto Fail; + } + + // initialize the queues to send request and receive response + FTRequestQueue = xQueueCreate(1, sizeof(FT_glyph_dsc_request)); + FTResponseQueue = xQueueCreate(1, sizeof(FT_glyph_dsc_response)); + + xTaskCreatePinnedToCore(FT_loop_task, "FreeType_task", LV_USE_FT_STACK_SIZE, NULL, 1, &FTTaskHandle, ARDUINO_RUNNING_CORE); + + if (FTRequestQueue && FTResponseQueue) { + return true; + } +Fail: + FTC_Manager_Done(cache_manager); + FT_Done_FreeType(library); + return false; +#else + LV_UNUSED(max_sizes); + LV_UNUSED(max_bytes); + return true; +#endif/* LV_USE_FT_CACHE_MANAGER */ +} + +void lv_freetype_destroy(void) +{ +#if LV_USE_FT_CACHE_MANAGER + FTC_Manager_Done(cache_manager); +#endif + FT_Done_FreeType(library); +} + +bool lv_ft_font_init(lv_ft_info_t *info) +{ + lv_font_fmt_ft_dsc_t * dsc = lv_mem_alloc(sizeof(lv_font_fmt_ft_dsc_t)); + if(dsc == NULL) return false; + + dsc->font = lv_mem_alloc(sizeof(lv_font_t)); + if(dsc->font == NULL) { + lv_mem_free(dsc); + return false; + } + + lv_face_info_t *face_info = NULL; + FT_Face face = face_find_in_list(info); + if (face == NULL) { + if (face_control.cnt == face_control.num - 1) { + LV_LOG_WARN("face full"); + goto Fail; + } + face_info = lv_mem_alloc(sizeof(lv_face_info_t) + strlen(info->name) + 1); + if(face_info == NULL) { + goto Fail; + } + FT_Error error = FT_New_Face(library, info->name, 0, &face); + if(error){ + lv_mem_free(face_info); + LV_LOG_WARN("create face error(%d)", error); + goto Fail; + } + + face_info->name = ((char *)face_info) + sizeof(lv_face_info_t); + strcpy(face_info->name, info->name); + face_info->cnt = 1; + face->generic.data = face_info; + face->generic.finalizer = face_generic_finalizer; + face_add_to_list(face); + } + else { +#if LV_USE_FT_CACHE_MANAGER == 0 + FT_Size size; + FT_Error error = FT_New_Size(face, &size); + if (error) { + goto Fail; + } + FT_Activate_Size(size); + FT_Reference_Face(face); +#else + face_info = (lv_face_info_t *)face->generic.data; + face_info->cnt++; +#endif + } + FT_Set_Pixel_Sizes(face, 0, info->weight); + + dsc->face = face; + dsc->size = face->size; + dsc->weight = info->weight; + dsc->style = info->style; + lv_font_t *font = dsc->font; + font->user_data = dsc; + font->get_glyph_dsc = get_glyph_dsc_cb; + font->get_glyph_bitmap = get_glyph_bitmap_cb; + font->line_height = (dsc->face->size->metrics.height >> 6); + font->base_line = -(dsc->face->size->metrics.descender >> 6); + font->subpx = LV_FONT_SUBPX_NONE; + font->underline_position = dsc->face->underline_position; + font->underline_thickness = dsc->face->underline_thickness; + font->dsc = NULL; + info->font = font; + return true; + +Fail: + lv_mem_free(dsc->font); + lv_mem_free(dsc); + return false; +} + +void lv_ft_font_destroy(lv_font_t* font) +{ + if (font == NULL) { + return; + } + + lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->user_data); + if (dsc) { +#if LV_USE_FT_CACHE_MANAGER == 0 + FT_Done_Size(dsc->size); + FT_Done_Face(dsc->face); +#else + lv_face_info_t *face_info = (lv_face_info_t *)dsc->face->generic.data; + face_info->cnt--; + if(face_info->cnt == 0){ + FTC_Manager_RemoveFaceID(cache_manager, (FTC_FaceID)dsc->face); + } +#endif + lv_mem_free(dsc->font); + lv_mem_free(dsc); + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ +static void face_generic_finalizer(void* object) +{ + FT_Face face = (FT_Face)object; + face_remove_from_list(face); + if(face->generic.data){ + lv_face_info_t *face_info = (lv_face_info_t *)face->generic.data; + lv_mem_free(face_info); + } + LV_LOG_INFO("face finalizer(%p)\n", face); +} + +static FT_Face face_find_in_list(lv_ft_info_t *info) +{ + lv_face_info_t *face_info; + FT_Face *pface = _lv_ll_get_head(&face_control.face_ll); + while(pface) { + face_info = (lv_face_info_t *)(*pface)->generic.data; + if (strcmp(face_info->name, info->name) == 0) { + return *pface; + } + pface = _lv_ll_get_next(&face_control.face_ll, pface); + } + + return NULL; +} + +static void face_add_to_list(FT_Face face) +{ + FT_Face *pface; + pface = (FT_Face *)_lv_ll_ins_tail(&face_control.face_ll); + *pface = face; + face_control.cnt++; +} + +static void face_remove_from_list(FT_Face face) +{ + FT_Face *pface = _lv_ll_get_head(&face_control.face_ll); + while(pface) { + if (*pface == face) { + _lv_ll_remove(&face_control.face_ll, pface); + lv_mem_free(pface); + face_control.cnt--; + break; + } + pface = _lv_ll_get_next(&face_control.face_ll, pface); + } +} + +#if LV_USE_FT_CACHE_MANAGER + +static FT_Error font_face_requester(FTC_FaceID face_id, + FT_Library library_is,FT_Pointer req_data,FT_Face* aface) +{ + LV_UNUSED(library_is); + LV_UNUSED(req_data); + *aface = face_id; + return FT_Err_Ok; +} + +static bool get_glyph_dsc_cb_cache(const lv_font_t * font, + lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) +{ + LV_UNUSED(unicode_letter_next); + if(unicode_letter < 0x20) { + dsc_out->adv_w = 0; + dsc_out->box_h = 0; + dsc_out->box_w = 0; + dsc_out->ofs_x = 0; + dsc_out->ofs_y = 0; + dsc_out->bpp = 0; + return true; + } + + lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->user_data); + FT_Face face = dsc->face; + + static FTC_ImageTypeRec desc_sbit_type; + desc_sbit_type.face_id = (FTC_FaceID)face; + desc_sbit_type.flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL; + desc_sbit_type.height = dsc->weight; + desc_sbit_type.width = dsc->weight; + FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap); + FT_UInt glyph_index = FTC_CMapCache_Lookup(cmap_cache, (FTC_FaceID)face, charmap_index, unicode_letter); + FT_Error error = FTC_SBitCache_Lookup(sbit_cache, &desc_sbit_type, glyph_index, &sbit, NULL); + + dsc_out->adv_w = sbit->xadvance; + dsc_out->box_h = sbit->height; /*Height of the bitmap in [px]*/ + dsc_out->box_w = sbit->width; /*Width of the bitmap in [px]*/ + dsc_out->ofs_x = sbit->left; /*X offset of the bitmap in [pf]*/ + dsc_out->ofs_y = sbit->top - sbit->height; /*Y offset of the bitmap measured from the as line*/ + dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/ + + return true; +} + +static const uint8_t * get_glyph_bitmap_cb_cache(const lv_font_t * font, uint32_t unicode_letter) +{ + LV_UNUSED(font); + LV_UNUSED(unicode_letter); + return (const uint8_t *)sbit->buffer; +} + +#else/* LV_USE_FT_CACHE_MANAGER */ +// extern void berry_log_C(const char * berry_buf, ...); + +static bool get_glyph_dsc_cb_nocache(const lv_font_t * font, + lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) +{ + // berry_log_C(">> get_glyph_dsc_cb_nocache %i %i", unicode_letter, unicode_letter_next); + LV_UNUSED(unicode_letter_next); + if(unicode_letter < 0x20) { + dsc_out->adv_w = 0; + dsc_out->box_h = 0; + dsc_out->box_w = 0; + dsc_out->ofs_x = 0; + dsc_out->ofs_y = 0; + dsc_out->bpp = 0; + return true; + } + + FT_Error error; + FT_Face face; + lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->user_data); + face = dsc->face; + + FT_UInt glyph_index = FT_Get_Char_Index( face, unicode_letter ); + + if (face->size != dsc->size) { + // berry_log_C(">> FT_Activate_Size %i", dsc->size); + FT_Activate_Size(dsc->size); + } + + error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT ); + // berry_log_C(">> after FT_Load_Glyph error = %i", error); + if (error){ + return false; + } + + error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL); + // berry_log_C(">> after FT_Render_Glyph error = %i", error); + if (error){ + return false; + } + + dsc_out->adv_w = (face->glyph->metrics.horiAdvance >> 6); + dsc_out->box_h = face->glyph->bitmap.rows; /*Height of the bitmap in [px]*/ + dsc_out->box_w = face->glyph->bitmap.width; /*Width of the bitmap in [px]*/ + dsc_out->ofs_x = face->glyph->bitmap_left; /*X offset of the bitmap in [pf]*/ + dsc_out->ofs_y = face->glyph->bitmap_top - face->glyph->bitmap.rows; /*Y offset of the bitmap measured from the as line*/ + dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/ + + // berry_log_C("+++ adv_w %i, h %i, w %i, x %i, y %i", dsc_out->adv_w, dsc_out->box_h, dsc_out->box_w, dsc_out->ofs_x, dsc_out->ofs_y); + + return true; +} + +static const uint8_t * get_glyph_bitmap_cb_nocache(const lv_font_t * font, uint32_t unicode_letter) +{ + LV_UNUSED(unicode_letter); + lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->user_data); + FT_Face face = dsc->face; + return (const uint8_t *)(face->glyph->bitmap.buffer); +} + +#endif/* LV_USE_FT_CACHE_MANAGER */ + +static bool get_glyph_dsc_cb(const lv_font_t * font, + lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) +{ +// #if LV_USE_FT_CACHE_MANAGER +// return get_glyph_dsc_cb_cache(font, dsc_out, unicode_letter, unicode_letter_next); +// #else +// return get_glyph_dsc_cb_nocache(font, dsc_out, unicode_letter, unicode_letter_next); +// #endif + static FT_glyph_dsc_request request; + static FT_glyph_dsc_response response; + + request.font = font; + request.dsc_out = dsc_out; + request.unicode_letter = unicode_letter; + request.unicode_letter_next = unicode_letter_next; + xQueueSendToBack(FTRequestQueue, &request, portMAX_DELAY); + if (xQueueReceive(FTResponseQueue, &response, portMAX_DELAY)) { + return response; + } else { + return false; // should never happen + } +} + +static const uint8_t * get_glyph_bitmap_cb(const lv_font_t * font, uint32_t unicode_letter) +{ +#if LV_USE_FT_CACHE_MANAGER + return get_glyph_bitmap_cb_cache(font, unicode_letter); +#else + return get_glyph_bitmap_cb_nocache(font, unicode_letter); +#endif +} + +void FT_loop_task(void *pvParameters) { + (void) pvParameters; + + while (1) { + FT_glyph_dsc_request request; + FT_glyph_dsc_response response; + + if (xQueueReceive(FTRequestQueue, &request, portMAX_DELAY)) { + #if LV_USE_FT_CACHE_MANAGER + response = get_glyph_dsc_cb_cache(request.font, request.dsc_out, request.unicode_letter, request.unicode_letter_next); + #else + response = get_glyph_dsc_cb_nocache(request.font, request.dsc_out, request.unicode_letter, request.unicode_letter_next); + #endif + xQueueSendToBack(FTResponseQueue, &response, portMAX_DELAY); // send back response + } + } +} + +#endif \ No newline at end of file diff --git a/lib/lv_lib_freetype/lv_freetype.h b/lib/lv_lib_freetype/lv_freetype.h new file mode 100644 index 00000000..1b419b99 --- /dev/null +++ b/lib/lv_lib_freetype/lv_freetype.h @@ -0,0 +1,110 @@ +/** + * @file lv_freetype.h + * + */ +#ifndef _LV_FONT_TTF_H +#define _LV_FONT_TTF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +// #include "lvgl/lvgl.h" // TODO +#include "lvgl.h" +#include "ft2build.h" +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_CACHE_H +#include FT_SIZES_H + +/********************* + * DEFINES + *********************/ +#ifndef LV_USE_FT_CACHE_MANAGER +#define LV_USE_FT_CACHE_MANAGER 0 +#endif + +#define LV_USE_FT_STACK_SIZE 24*1024 // FreeType consumes a large amount of stack + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + uint16_t cnt; + char* name; +} lv_face_info_t; + +typedef struct { + uint16_t num; + uint16_t cnt; + lv_ll_t face_ll; +} lv_faces_control_t; + +typedef enum { + FT_FONT_STYLE_NORMAL = 0, + FT_FONT_STYLE_ITALIC = 1 << 0, + FT_FONT_STYLE_BOLD = 1 << 1 +} LV_FT_FONT_STYLE; + +typedef struct { + const char* name; /* The name of the font file */ + lv_font_t* font; /* point to lvgl font */ + uint16_t weight; /* font size */ + uint16_t style; /* font style */ +} lv_ft_info_t; + +typedef struct { + FT_Face face; + FT_Size size; + lv_font_t* font; + uint16_t style; + uint16_t weight; +} lv_font_fmt_freetype_dsc_t; + +typedef lv_font_fmt_freetype_dsc_t lv_font_fmt_ft_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * init freetype library + * @param max_faces Maximum number of opened FT_Face objects managed by this cache instance. Use 0 for defaults. + * @param max_sizes Maximum number of opened FT_Size objects managed by this cache instance. Use 0 for defaults. + * @param max_bytes Maximum number of bytes to use for cached data nodes. Use 0 for defaults. + * Note that this value does not account for managed FT_Face and FT_Size objects. + * @return true on success, otherwise false. + */ +bool lv_freetype_init(FT_UInt max_faces, FT_UInt max_sizes, FT_ULong max_bytes); + +/** + * Destroy freetype library + */ +void lv_freetype_destroy(void); + +/** + * Creates a font with info parameter specified. + * @param info See lv_ft_info_t for details. + * when success, lv_ft_info_t->font point to the font you created. + * @return true on success, otherwise false. + */ +bool lv_ft_font_init(lv_ft_info_t *info); + +/** + * Destroy a font that has been created. + * @param font pointer to font. + */ +void lv_ft_font_destroy(lv_font_t* font); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/lib/lv_lib_freetype/lv_fs_freetype.c b/lib/lv_lib_freetype/lv_fs_freetype.c new file mode 100644 index 00000000..967195ff --- /dev/null +++ b/lib/lv_lib_freetype/lv_fs_freetype.c @@ -0,0 +1,134 @@ +/** + * @file lv_fs_freetype.c + * + */ + +/********************* + * INCLUDES + *********************/ +#includeBased on the previous work of the following open source developers.
includes parts from the Adafruit_GFX libraryCopyright© 2012 Adafruit Industries. " - "All rights reservedBSD License
"); - httpMessage += F("Based on the previous work of the following open source developers.
includes parts from the + Adafruit_GFX libraryCopyright© 2012 Adafruit Industries. " "All rights reservedBSD + License
"); httpMessage += F("LVGL Memory: ");
- Parser::format_bytes(mem_mon.total_size, size_buf, sizeof(size_buf));
- httpMessage += size_buf;
- httpMessage += F("
LVGL Free: ");
- Parser::format_bytes(mem_mon.free_size, size_buf, sizeof(size_buf));
- httpMessage += size_buf;
- httpMessage += F("
LVGL Fragmentation: ");
- httpMessage += mem_mon.frag_pct;
-
- // httpMessage += F("
LCD Model: ")) + String(LV_HASP_HOR_RES_MAX) + " x " +
- // String(LV_HASP_VER_RES_MAX); httpMessage += F("
LCD Version: ")) +
- // String(lcdVersion);
- httpMessage += F("
LCD Active Page: "); - httpMessage += String(haspPages.get()); - - // Wifi Stats -#if HASP_USE_WIFI > 0 - httpMessage += F("
SSID: "); - httpMessage += String(WiFi.SSID()); - httpMessage += F("Signal Strength: "); - - int8_t rssi = WiFi.RSSI(); - httpMessage += String(rssi); - httpMessage += F("dBm ("); - - if(rssi >= -50) { - httpMessage += F("Excellent)"); - } else if(rssi >= -60) { - httpMessage += F("Good)"); - } else if(rssi >= -70) { - httpMessage += F("Fair)"); - } else if(rssi >= -80) { - httpMessage += F("Weak)"); - } else { - httpMessage += F("Very Bad)"); - } -#if defined(STM32F4xx) - byte mac[6]; - WiFi.macAddress(mac); - char macAddress[16]; - snprintf_P(macAddress, sizeof(macAddress), PSTR("%02x%02x%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], - mac[5]); - httpMessage += F("IP Address: "); - httpMessage += String(WiFi.localIP()); - httpMessage += F("Gateway: "); - httpMessage += String(WiFi.gatewayIP()); - httpMessage += F("MAC Address: "); - httpMessage += String(macAddress); -#else - httpMessage += F("IP Address: "); - httpMessage += String(WiFi.localIP().toString()); - httpMessage += F("Gateway: "); - httpMessage += String(WiFi.gatewayIP().toString()); - httpMessage += F("DNS Server: "); - httpMessage += String(WiFi.dnsIP().toString()); - httpMessage += F("MAC Address: "); - httpMessage += String(WiFi.macAddress()); -#endif -#endif -#if HASP_USE_ETHERNET > 0 -#if defined(ARDUINO_ARCH_ESP32) - httpMessage += F("
Ethernet: "); - httpMessage += String(ETH.linkSpeed()); - httpMessage += F(" Mbps"); - if(ETH.fullDuplex()) { - httpMessage += F(" " D_INFO_FULL_DUPLEX); - } - httpMessage += F("IP Address: "); - httpMessage += String(ETH.localIP().toString()); - httpMessage += F("Gateway: "); - httpMessage += String(ETH.gatewayIP().toString()); - httpMessage += F("DNS Server: "); - httpMessage += String(ETH.dnsIP().toString()); - httpMessage += F("MAC Address: "); - httpMessage += String(ETH.macAddress()); -#endif -#endif - -// Mqtt Stats -#if HASP_USE_MQTT > 0 - httpMessage += F("
MQTT Status: ");
- if(mqttIsConnected()) { // Check MQTT connection
- httpMessage += F("Connected");
- } else {
- httpMessage += F("Disconnected, return code: ");
- // +String(mqttClient.returnCode());
- }
- httpMessage += F("
MQTT ClientID: ");
-
- {
- char mqttClientId[64];
- String mac = halGetMacAddress(3, "");
- mac.toLowerCase();
- snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("%s-%s"), haspDevice.get_hostname(), mac.c_str());
- httpMessage += mqttClientId;
- }
-
-#endif // MQTT
-
- // ESP Stats
- httpMessage += F("
MCU Model: ");
- httpMessage += haspDevice.get_chip_model();
- httpMessage += F("
CPU Frequency: ");
- httpMessage += String(haspDevice.get_cpu_frequency());
- httpMessage += F("MHz");
-
-#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266)
- httpMessage += F("
Flash Chip Size: ");
- Parser::format_bytes(ESP.getFlashChipSize(), size_buf, sizeof(size_buf));
- httpMessage += size_buf;
-
- httpMessage += F("Program Size Used: ");
- Parser::format_bytes(ESP.getSketchSize(), size_buf, sizeof(size_buf));
- httpMessage += size_buf;
-
- httpMessage += F("
Program Size Free: ");
- Parser::format_bytes(ESP.getFreeSketchSpace(), size_buf, sizeof(size_buf));
- httpMessage += size_buf;
-#endif
-
- //#if defined(ARDUINO_ARCH_ESP32)
- // httpMessage += F("
ESP SDK version: ");
- // httpMessage += String(ESP.getSdkVersion());
- //#else
- httpMessage += F("
Core version: ");
- httpMessage += haspDevice.get_core_version();
- //#endif
- httpMessage += F("
Last Reset: ");
- // httpMessage += halGetResetInfo();
-
- httpMessage += FPSTR(MAIN_MENU_BUTTON);
-
- webSendHeader(haspDevice.get_hostname(), httpMessage.length(), false);
- webServer.sendContent(httpMessage);
- }
- webSendFooter();
-}
-*/
-
/* String urldecode(String str)
{
String encodedString = "";
@@ -913,9 +707,10 @@ static int handleFileRead(String path)
if(path.endsWith("/")) {
path += F("index.htm");
}
-
+
String style_css = F("/style.css");
- bool is_style_css = (path == style_css);
+ String script_js = F("/script.js");
+ bool is_cached = (path == style_css) || (path == script_js);
String pathWithGz = path + F(".gz");
if(HASP_FS.exists(pathWithGz) || HASP_FS.exists(path)) {
@@ -948,8 +743,8 @@ static int handleFileRead(String path)
} else {
- // Only styles.css can be cached
- if(is_style_css) webSendCacheHeader(file.size(), 3600);
+ // script.js and styles.css can be cached
+ if(is_cached) webSendCacheHeader(file.size(), 3600);
// Stream other files directly from filesystem
webServer.streamFile(file, contentType);
@@ -963,7 +758,7 @@ static int handleFileRead(String path)
if(path == F("/edit.htm")) {
size_t size = EDIT_HTM_GZ_END - EDIT_HTM_GZ_START;
webServer.sendHeader(F("Content-Encoding"), F("gzip"));
- return webSendCached(200, PSTR("text/html"), (const char*)EDIT_HTM_GZ_START, size); // OK
+ return webSendCached(200, PSTR("text/html"), (const char*)EDIT_HTM_GZ_START, size);
}
#endif
@@ -971,7 +766,15 @@ static int handleFileRead(String path)
if(path == style_css) {
size_t size = STYLE_CSS_GZ_END - STYLE_CSS_GZ_START;
webServer.sendHeader(F("Content-Encoding"), F("gzip"));
- return webSendCached(200, PSTR("text/css"), (const char*)STYLE_CSS_GZ_START, size); // OK
+ return webSendCached(200, PSTR("text/css"), (const char*)STYLE_CSS_GZ_START, size);
+ }
+#endif
+
+#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_IDF_TARGET_ESP32)
+ if(path == script_js) {
+ size_t size = SCRIPT_JS_GZ_END - SCRIPT_JS_GZ_START;
+ webServer.sendHeader(F("Content-Encoding"), F("gzip"));
+ return webSendCached(200, PSTR("text/javascript"), (const char*)SCRIPT_JS_GZ_START, size);
}
#endif
@@ -1243,8 +1046,9 @@ static void webHandleMqttConfig()
// Broker
httpMessage += F("
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.
THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " + "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR " + "PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, " + "DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN " + "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Based on the previous work of the following open source developers:
" + "Copyright© 2019 Allen Derusha allen@derusha.orgMIT License
" + "Copyright© 2021 LVGL KftMIT License
" + "Copyright© 2020-2021 Francis Van RoieMIT License
" + "Copyright© 2020 Bodmer (https://github.com/Bodmer) All rights " + "reserved.FreeBSD License
" + "includes parts from the Adafruit_GFX libraryCopyright© 2012 Adafruit Industries. All " + "rights reservedBSD License
" + "Copyright© 2014-2021 Benoit BLANCHONMIT License
" + "Copyright© 2008-2015 Nicholas O'LearyMIT License
" + "Copyright© 2017,2018 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, dhylands, " + "Josha blemasle, mfalkviddMIT License
" + "Copyright© Project NayukiMIT License
" + "Copyright© 2018 Brian T. ParkMIT License
';}"; webSendCached(200, PSTR("text/javascript"), javascript.c_str(), javascript.length()); } +*/ //////////////////////////////////////////////////////////////////////////////////////////////////// static inline void webStartConfigPortal() @@ -2390,7 +2245,7 @@ void httpSetup() // Shared pages between STA and AP webServer.on(F("/about"), webHandleAbout); webServer.on(F("/vars.css"), webSendCssVars); - webServer.on(F("/js"), webSendJavascript); + // webServer.on(F("/js"), webSendJavascript); webServer.onNotFound(httpHandleNotFound); #if HASP_USE_WIFI > 0 @@ -2519,8 +2374,8 @@ bool httpGetConfig(const JsonObject& settings) if(http_config.port != settings[FPSTR(FP_CONFIG_PORT)].as