diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 3f8ea833..55fe197d 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -21,23 +21,21 @@ jobs:
matrix:
environment:
- out: adafruit
- env: "huzzah32-featherwing-24 -e huzzah32-featherwing-35"
+ env: "huzzah32-featherwing-24 -e huzzah32-featherwing-35 -e huzzah32-featherwing-24-v2 -e huzzah32-featherwing-35-v2 -e huzzah32-v2-featherwing-24-v2 -e huzzah32-v2-featherwing-35-v2"
- out: az-touch
env: "az-touch-mod-esp32_ili9341_4MB -e az-touch-mod-esp32_ili9341_8MB"
- env: d1-mini-esp32_ili9341
out: d1-mini-esp32
- - env: d1-r32-waveshare_ili9486
- out: d1-r32-espduino32
- - env: d1-r32-unoshield_ili9341_adc
- out: d1-r32-espduino32
- - env: d1-r32-unoshield_ili9486_adc
- out: d1-r32-espduino32
+ - out: d1-r32-espduino32
+ env: "d1-r32-waveshare_ili9486 -e d1-r32-unoshield_ili9341_adc -e d1-r32-unoshield_ili9486_adc"
- out: dustinwatts
env: "freetouchdeck_4MB -e freetouchdeck_8MB -e esp32-touchdown"
- out: elecrow
env: "esp32-terminal-rgb_16MB -e esp32-terminal-spi_16MB"
- out: globalsecurity
env: gs-t3e_16MB
+ - out: guition
+ env: esp32-s3-4848s040_16MB
- out: lanbon
env: lanbon_l8
- out: lilygo-ttgo
@@ -53,7 +51,7 @@ jobs:
- out: seeed-studios
env: "sensecap-indicator-d1_8MB"
- out: sunton
- env: "esp32-2432s028r_4MB -e esp32-3248s035c_4MB -e esp32-3248s035r_4MB -e sunton-4827s043c_16MB -e sunton-8048s043c_16MB -e sunton-8048s050c_16MB -e sunton-8048s070c_16MB"
+ env: "esp32-2432s028r_4MB -e esp32-2432s028r-ili9342_4MB -e esp32-2432s032c_4MB -e esp32-3248s035c_4MB -e esp32-3248s035r_4MB -e sunton-4827s043c_16MB -e sunton-8048s043c_16MB -e sunton-8048s050c_16MB -e sunton-8048s070c_16MB"
- out: waveshare
env: "esp32-one_ili9486 -e esp32-one_st7796"
- out: wireless-tag
@@ -62,29 +60,32 @@ jobs:
env: yeacreate-nscreen32
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: "true"
- name: Cache pip
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
+ - name: Install Setuptools
+ run: |
+ pip install --upgrade setuptools
- name: Enable ESP32 platforms from platformio_override-template.ini
run: |
sed 's/; user_setups\/esp32/user_setups\/esp32/g' platformio_override-template.ini > platformio_override.ini
@@ -97,7 +98,7 @@ jobs:
- name: Run PlatformIO
run: pio run -e ${{ matrix.environment.env }}
- name: Upload output file
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ matrix.environment.out }}
path: build_output/firmware/*.bin
@@ -127,23 +128,23 @@ jobs:
linux_build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: "true"
- name: Cache pip
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install PlatformIO
@@ -153,7 +154,7 @@ jobs:
- 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
+ mkdir -p .pio/libdeps/linux_sdl/paho/src
- name: Install SDL2 library
run: |
sudo apt-get update
@@ -167,10 +168,10 @@ jobs:
- 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
+ mkdir -p .pio/libdeps/linux_sdl/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
+ run: pio run -e linux_sdl
diff --git a/.github/workflows/build_linux.yaml b/.github/workflows/build_linux.yaml
index a4baea49..cd92d6be 100644
--- a/.github/workflows/build_linux.yaml
+++ b/.github/workflows/build_linux.yaml
@@ -11,21 +11,21 @@ jobs:
fail-fast: false
matrix:
environments:
- - linux_sdl_64bits
+ - linux_sdl
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
submodules: 'true'
- name: Cache pip
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
@@ -43,7 +43,7 @@ jobs:
- 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
+ mkdir -p .pio/libdeps/linux_sdl/paho/src
- name: Install SDL2 library
run: |
sudo apt-get update
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b47c2d78..ed1ce258 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -12,16 +12,16 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Cache pip
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
@@ -39,7 +39,7 @@ jobs:
- 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
+ mkdir -p .pio/libdeps/linux_sdl/paho/src
- name: Install SDL2 library
run: |
sudo apt-get update
@@ -63,7 +63,7 @@ jobs:
- name: Run PlatformIO
run: pio run -e esp32-touchdown -e freetouchdeck_4MB -e freetouchdeck_8MB
- name: Run PlatformIO
- run: pio run -e huzzah32-featherwing-24 -e huzzah32-featherwing-35
+ run: pio run -e huzzah32-featherwing-24 -e huzzah32-featherwing-35 -e huzzah32-featherwing-24-v2 -e huzzah32-featherwing-35-v2 -e huzzah32-v2-featherwing-24-v2 -e huzzah32-v2-featherwing-35-v2
- name: Run PlatformIO
run: pio run -e lanbon_l8
- name: Run PlatformIO
@@ -71,7 +71,7 @@ jobs:
- name: Run PlatformIO
run: pio run -e m5stack-core2
- name: Upload output file
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: openHASP firmware.zip
path: build_output/firmware/*.bin
diff --git a/.gitmodules b/.gitmodules
index 90d1c1d0..c1197372 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,4 @@
[submodule "lib/freetype"]
path = lib/freetype
url = https://github.com/fvanroie/freetype
-
\ No newline at end of file
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6c213e8..23bfac23 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
- Firmware files include the bitmapped font sizes 12, 16, 24 and 32pt
- Use embedded TrueType font for other font sizes (PSram highly recommended)
- Add glyphs from Cyrillic, Latin-2, Greek and Viernamese character sets to default fonts
+- Add 12 new MDI icons
### Web UI
- Update Web UI to petite-vue app
@@ -35,6 +36,7 @@
- Add service start/stop ftp
- Add configuration for NTP servers and timezone
- Add support system scripts executed when the idle level is changed
+- Add support for WireGuard (thanks @perexg)
### Devices
- Add Elecrow ESP32-Terminal 3.5" SPI and RGB
@@ -45,6 +47,7 @@
- Add Sunton ESP32-2432S028R ESP32-3248S035C ESP32-3248S035R
- Add support for Wireless-Tag WT32-SC01 Plus and WT32S3-86V
- Deprecate support for WT-86-32-3ZW1 with ESP32-S2
+- Fade backlight on ESP32 devices (thanks @presslab-us)
## Bug fixes
- Fix for first touch not working properly
@@ -56,7 +59,7 @@
- Add support for ESP32-S3 and ESP32-C3 devices
- Deprecation of support for ESP32-S2 devices due to lack of sRAM
-Updated libraries to ArduinoJson 6.21.3, ArduinoStreamUtils 1.7.3, AceButton 1.10.1, TFT_eSPI 2.5.0, LovyanGFX 1.1.8 and SimpleFTPServer 2.1.5
+Updated libraries to Arduino_GFX v1.4.0, ArduinoJson 6.21.5, ArduinoStreamUtils 1.8.0, AceButton 1.10.1, TFT_eSPI 2.5.34, LovyanGFX 1.1.12 and SimpleFTPServer 2.1.5
## v0.6.3
@@ -166,23 +169,23 @@ Updated libraries to AceButton 1.9.1 and ArduinoJson 6.18.5
- Run `/online.cmd` or `/offline.cmd` script when the wifi status changed
### Objects
-- Add new *[line](https://openhasp.haswitchplate.com/0.6.1/design/objects/#line)* object
-- Add `val` to *[btnmatrix](https://openhasp.haswitchplate.com/0.6.1/design/objects/#button-matrix)* when `one_select` is set
-- Cache up to 20 *[images](https://openhasp.haswitchplate.com/0.6.1/design/objects/#image)* in PSram when available
-- Improve precision on the *[linemeter](https://openhasp.haswitchplate.com/0.6.1/design/objects/#line-meter)* scales
-- Fix *[dropdown](https://openhasp.haswitchplate.com/0.6.1/design/objects/#dropdown-list)* redraw bug
+- Add new *[line](https://www.openhasp.com/0.6.1/design/objects/#line)* object
+- Add `val` to *[btnmatrix](https://www.openhasp.com/0.6.1/design/objects/#button-matrix)* when `one_select` is set
+- Cache up to 20 *[images](https://www.openhasp.com/0.6.1/design/objects/#image)* in PSram when available
+- Improve precision on the *[linemeter](https://www.openhasp.com/0.6.1/design/objects/#line-meter)* scales
+- Fix *[dropdown](https://www.openhasp.com/0.6.1/design/objects/#dropdown-list)* redraw bug
### Devices
-- Fix [L8-HD dimmer](https://openhasp.haswitchplate.com/0.6.1/devices/lanbon-l8/) not responding correctly to mqtt after a reboot
-- Add [M5Stack Core2](https://openhasp.haswitchplate.com/0.6.1/devices/m5stack-core2/) backlight dimming
-- Add [Yeacreate Nscreen32](https://openhasp.haswitchplate.com/0.6.1/devices/yeacreate-nscreen32/)
-- Add [Makerfabs ESP32 TFT Touch](https://openhasp.haswitchplate.com/0.6.1/devices/makerfabs-tft-touch/) Capacitive
+- Fix [L8-HD dimmer](https://www.openhasp.com/0.6.1/devices/lanbon-l8/) not responding correctly to mqtt after a reboot
+- Add [M5Stack Core2](https://www.openhasp.com/0.6.1/devices/m5stack-core2/) backlight dimming
+- Add [Yeacreate Nscreen32](https://www.openhasp.com/0.6.1/devices/yeacreate-nscreen32/)
+- Add [Makerfabs ESP32 TFT Touch](https://www.openhasp.com/0.6.1/devices/makerfabs-tft-touch/) Capacitive
### Fonts
-- [Additional characters](https://openhasp.haswitchplate.com/0.6.1/design/fonts/#ascii): `²` (squared) and `³` (cubed)
-- [Additional icons](https://openhasp.haswitchplate.com/0.6.1/design/fonts/#built-in-icons): recycle-variant and additional weather icons
-- Use latin1 as default charset on [WT32-SC01](https://openhasp.haswitchplate.com/0.6.1/devices/wt32-sc01/)
-- Add [Greek font](https://openhasp.haswitchplate.com/0.6.1/design/fonts/#greek)
+- [Additional characters](https://www.openhasp.com/0.6.1/design/fonts/#ascii): `²` (squared) and `³` (cubed)
+- [Additional icons](https://www.openhasp.com/0.6.1/design/fonts/#built-in-icons): recycle-variant and additional weather icons
+- Use latin1 as default charset on [WT32-SC01](https://www.openhasp.com/0.6.1/devices/wt32-sc01/)
+- Add [Greek font](https://www.openhasp.com/0.6.1/design/fonts/#greek)
### Compiling
- Allow custom bootlogo
@@ -250,7 +253,7 @@ Updated libraries to lvgl 7.11.0, ArduinoJson 6.18.0 and TFT_eSPI 2.3.70
## v0.5.0
-Name changed to openHASP - https://openhasp.haswitchplate.com/
+Name changed to openHASP - https://www.openhasp.com/
> When using HomeAssistant also update the [openHASP Custom Component](https://github.com/HASwitchPlate/openHASP-custom-component/releases/tag/0.5.0)
- Switch built-in icons from FontAwesome to MaterialDesign icons #139
@@ -261,7 +264,7 @@ Name changed to openHASP - https://openhasp.haswitchplate.com/
- Add `back`, `prev`, `next` attributes to pages #114
- JSON Serialize text in payloads containing text attributes #140
- Add az-touch-mod-esp32_ili9341 config and allow for TFT_BACKLIGHT_ON set to LOW #131
-- Add [FreeTouchDeck](https://openhasp.haswitchplate.com/0.5/#devices/freetouchdeck/) and [ESP32-Touchdown](https://openhasp.haswitchplate.com/0.5/#devices/esp32-touchdown/) configs
+- Add [FreeTouchDeck](https://www.openhasp.com/0.5/#devices/freetouchdeck/) and [ESP32-Touchdown](https://www.openhasp.com/0.5/#devices/esp32-touchdown/) configs
- Add roller `mode` `infinite` attribute
- Add btnmatrix `toggle` and `one_check` attributes
- Rework all event handlers to reduce update events and prevent race condition #119 *(events have changed!)*
@@ -289,7 +292,7 @@ Changes:
- Remove HA auto-discovery in favor of the HA Custom Component
- Add `clearpage all` command option
- Add local page navigation and transitions
-- Add [scale properties](https://openhasp.haswitchplate.com/0.5/#styling/#scale)
+- Add [scale properties](https://www.openhasp.com/0.5/#styling/#scale)
- Add `config/gpio` command
- Allow for timezone setting in user_config_override.h (thanks @arovak)
- Start localizations for NL, HU and RO (thanks @nagyrobi)
diff --git a/LICENSE b/LICENSE
index c212742b..85f9577f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2019-2023 Francis Van Roie
+Copyright (c) 2019-2024 Francis Van Roie
Copyright (c) 2018-2019 Allen Derusha allen@derusha.org
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/data/cert/x509_crt_bundle.bin b/data/cert/x509_crt_bundle.bin
index 77d8ea3e..c4c74b89 100644
Binary files a/data/cert/x509_crt_bundle.bin and b/data/cert/x509_crt_bundle.bin differ
diff --git a/data/da_DK.json b/data/da_DK.json
index fb67c5d9..6e48f802 100644
--- a/data/da_DK.json
+++ b/data/da_DK.json
@@ -85,6 +85,15 @@
"btn": "WiFi Indstillinger",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "MQTT Indstillinger",
"btn": "MQTT Indstillinger",
diff --git a/data/de_DE.json b/data/de_DE.json
index d3f99e9e..0c494a69 100644
--- a/data/de_DE.json
+++ b/data/de_DE.json
@@ -85,6 +85,15 @@
"btn": "WiFi-Einstellungen",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "MQTT-Einstellungen",
"btn": "MQTT-Einstellungen",
diff --git a/data/edit.htm b/data/edit.htm
index 5811afc4..ea1228a3 100644
--- a/data/edit.htm
+++ b/data/edit.htm
@@ -1 +1 @@
-
openHASP File Editor- New File
- Upload Files
- Edit
- Preview
- Download
- Delete
\ No newline at end of file
+openHASP File Editor- New File
- Upload Files
- Edit
- Preview
- Download
- Delete
\ No newline at end of file
diff --git a/data/en.json b/data/en.json
index 0bfe12d4..248e4adc 100644
--- a/data/en.json
+++ b/data/en.json
@@ -1 +1 @@
-{"en":{"language":"English","home":{"title":"Main Menu","btn":"Main Menu","nav":"Home"},"save":"Save Settings","user":"Username","pass":"Password","hasp":{"title":"HASP Design","btn":"HASP Design","theme":"UI Theme","color1":"Primary color","color2":"Secondary color","pages":"Start Layout","font":"Default Font","startpage":"Startup Page","startdim":"Startup Dim"},"screenshot":{"title":"Screenshot","btn":"Screenshot","nav":"Screenshot","prev":"Prev Page","next":"Next Page","refresh":"Refresh"},"info":{"title":"Information","btn":"Information","nav":"Information"},"config":{"title":"Configuration","btn":"Configuration","nav":"Settings"},"ota":{"title":"Firmware Update","btn":"Firmware Update","nav":"Firmware","submit":"Update Firmware","file":"Firmware File","url":"Firmware URL","redirect":"Follow Redirects","never":"Never","strict":"Strict","always":"Always"},"editor":{"title":"File Editor","btn":"File Editor","nav":"File Editor"},"reset":{"title":"Factory Reset","btn":"Factory Reset","warning":"Warning","message":"This process will reset all settings to the default values. The internal flash will be erased and the device is restarted. You may need to connect to the WiFi AP displayed on the panel to reconfigure the device before accessing it again.","fileloss":"ALL FILES WILL BE LOST!"},"reboot":{"title":"Rebooting...","btn":"Restart","nav":"Reboot","message":"The device is rebooting."},"about":{"credits":"Based on the previous work of the following open source developers:","copyright":"Copyright ","rights":"All rights reserved.","clause1":"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:","clause2":"The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.","clause3":"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.","mit":"MIT License","bsd":"BSD License","freebsd":"FreeBSD License","apache2":"Apache2 License"},"wifi":{"title":"Wifi Settings","btn":"Wifi Settings","ssid":"SSID"},"mqtt":{"title":"MQTT Settings","btn":"MQTT Settings","name":"Hostname","group":"Groupname","host":"Broker","port":"Port","node_t":"Node Topic","group_t":"Group Topic","broadcast_t":"Broadcast Topic","hass_t":"HA LWT Topic"},"http":{"title":"HTTP Settings","btn":"HTTP Settings"},"ftp":{"title":"FTP Settings","btn":"FTP Settings","port":"FTP Port","pasv":"Passive Port"},"gui":{"title":"Display Settings","btn":"Display Settings","antiburn":"Antiburn","calibrate":"Calibrate"},"gpio":"GPIO Settings","debug":{"title":"Debug Settings","btn":"Debug Settings","baud":"Baudrate","tele":"Tele Period","ansi":"Use ANSI codes","host":"Syslog Server","port":"Syslog Port","ietf":"IETF (RFC 5424)","bsd":"BSD (RFC 3164)","log":"Facility"},"time":{"title":"Time Settings","btn":"Time Settings","region":"Region","zone":"Timezone","tz":"Timezone","ntp":"NTP Servers"},"region":{"etc":"Etcetera ","continents":"Continents ","af":"Africa ","as":"Asia ","au":"Australia ","aq":"Antarctica ","eu":"Europe ","na":"North America ","sa":"South America ","islands":"Islands ","at":"Atlantic Ocean ","in":"Indian Ocean ","pa":"Pacific Ocean "}}}
\ No newline at end of file
+{"en":{"language":"English","home":{"title":"Main Menu","btn":"Main Menu","nav":"Home"},"save":"Save Settings","user":"Username","pass":"Password","hasp":{"title":"HASP Design","btn":"HASP Design","theme":"UI Theme","color1":"Primary color","color2":"Secondary color","pages":"Start Layout","font":"Default Font","startpage":"Startup Page","startdim":"Startup Dim"},"screenshot":{"title":"Screenshot","btn":"Screenshot","nav":"Screenshot","prev":"Prev Page","next":"Next Page","refresh":"Refresh"},"info":{"title":"Information","btn":"Information","nav":"Information"},"config":{"title":"Configuration","btn":"Configuration","nav":"Settings"},"ota":{"title":"Firmware Update","btn":"Firmware Update","nav":"Firmware","submit":"Update Firmware","file":"Firmware File","url":"Firmware URL","redirect":"Follow Redirects","never":"Never","strict":"Strict","always":"Always"},"editor":{"title":"File Editor","btn":"File Editor","nav":"File Editor"},"reset":{"title":"Factory Reset","btn":"Factory Reset","warning":"Warning","message":"This process will reset all settings to the default values. The internal flash will be erased and the device is restarted. You may need to connect to the WiFi AP displayed on the panel to reconfigure the device before accessing it again.","fileloss":"ALL FILES WILL BE LOST!"},"reboot":{"title":"Rebooting...","btn":"Restart","nav":"Reboot","message":"The device is rebooting."},"about":{"credits":"Based on the previous work of the following open source developers:","copyright":"Copyright ","rights":"All rights reserved.","clause1":"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:","clause2":"The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.","clause3":"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.","mit":"MIT License","bsd":"BSD License","freebsd":"FreeBSD License","apache2":"Apache2 License"},"wifi":{"title":"Wifi Settings","btn":"Wifi Settings","ssid":"SSID"},"wg":{"title":"WireGuard Settings","btn":"WireGuard Settings","vpnip":"VPN IP","privkey":"Private Key","host":"Remote IP","port":"Remote Port","pubkey":"Remote Public Key"},"mqtt":{"title":"MQTT Settings","btn":"MQTT Settings","name":"Hostname","group":"Groupname","host":"Broker","port":"Port","node_t":"Node Topic","group_t":"Group Topic","broadcast_t":"Broadcast Topic","hass_t":"HA LWT Topic"},"http":{"title":"HTTP Settings","btn":"HTTP Settings"},"ftp":{"title":"FTP Settings","btn":"FTP Settings","port":"FTP Port","pasv":"Passive Port"},"gui":{"title":"Display Settings","btn":"Display Settings","antiburn":"Antiburn","calibrate":"Calibrate"},"gpio":"GPIO Settings","debug":{"title":"Debug Settings","btn":"Debug Settings","baud":"Baudrate","tele":"Tele Period","ansi":"Use ANSI codes","host":"Syslog Server","port":"Syslog Port","ietf":"IETF (RFC 5424)","bsd":"BSD (RFC 3164)","log":"Facility"},"time":{"title":"Time Settings","btn":"Time Settings","region":"Region","zone":"Timezone","tz":"Timezone","ntp":"NTP Servers"},"region":{"etc":"Etcetera ","continents":"Continents ","af":"Africa ","as":"Asia ","au":"Australia ","aq":"Antarctica ","eu":"Europe ","na":"North America ","sa":"South America ","islands":"Islands ","at":"Atlantic Ocean ","in":"Indian Ocean ","pa":"Pacific Ocean "}}}
\ No newline at end of file
diff --git a/data/es_ES.json b/data/es_ES.json
index ba317b90..fa1292a2 100644
--- a/data/es_ES.json
+++ b/data/es_ES.json
@@ -85,6 +85,15 @@
"btn": "Ajustes Wifi",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "Ajustes MQTT",
"btn": "Ajustes MQTT",
diff --git a/data/fr_FR.json b/data/fr_FR.json
index a6deaa8b..7247c2f6 100644
--- a/data/fr_FR.json
+++ b/data/fr_FR.json
@@ -85,6 +85,15 @@
"btn": "Paramètres WiFi",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "Paramètres MQTT",
"btn": "Paramètres MQTT",
diff --git a/data/hu_HU.json b/data/hu_HU.json
index 7700a9f9..16a2e736 100644
--- a/data/hu_HU.json
+++ b/data/hu_HU.json
@@ -85,6 +85,15 @@
"btn": "WiFi beállítások",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "MQTT beállítások",
"btn": "MQTT beállítások",
diff --git a/data/main.js b/data/main.js
index a74ef0c9..989d9086 100644
--- a/data/main.js
+++ b/data/main.js
@@ -1 +1 @@
-import{createApp,reactive,createI18n}from"/static/petite-vue.hasp.js?COMMIT_HASH";const languages=[{code:"en",name:"English"},{code:"nl",name:"Nederlands"},{code:"fr",name:"Français"}];var locations={af:["Abidjan","Algiers","Bissau","Cairo","Casablanca","El_Aaiun","Johannesburg","Juba","Khartoum","Lagos","Maputo","Monrovia","Nairobi","Ndjamena","Sao_Tome","Tripoli","Tunis","Windhoek","Cape_Verde","Mauritius"],eu:["Ceuta","Danmarkshavn","Nuuk","Scoresbysund","Thule","Anadyr","Barnaul","Chita","Irkutsk","Kamchatka","Khandyga","Krasnoyarsk","Magadan","Novokuznetsk","Novosibirsk","Omsk","Sakhalin","Srednekolymsk","Tomsk","Ust-Nera","Vladivostok","Yakutsk","Yekaterinburg","Azores","Canary","Faroe","Madeira","Andorra","Astrakhan","Athens","Belgrade","Berlin","Brussels","Bucharest","Budapest","Chisinau","Dublin","Gibraltar","Helsinki","Istanbul","Kaliningrad","Kirov","Kyiv","Lisbon","London","Madrid","Malta","Minsk","Moscow","Paris","Prague","Riga","Rome","Samara","Saratov","Sofia","Tallinn","Tirane","Ulyanovsk","Vienna","Vilnius","Volgograd","Warsaw","Zurich"],as:["Almaty","Amman","Aqtau","Aqtobe","Ashgabat","Atyrau","Baghdad","Baku","Bangkok","Beirut","Bishkek","Choibalsan","Colombo","Damascus","Dhaka","Dili","Dubai","Dushanbe","Famagusta","Gaza","Hebron","Ho_Chi_Minh","Hong_Kong","Hovd","Jakarta","Jayapura","Jerusalem","Kabul","Karachi","Kathmandu","Kolkata","Kuching","Macau","Makassar","Manila","Nicosia","Oral","Pontianak","Pyongyang","Qatar","Qostanay","Qyzylorda","Riyadh","Samarkand","Seoul","Shanghai","Singapore","Taipei","Tashkent","Tbilisi","Tehran","Thimphu","Tokyo","Ulaanbaatar","Urumqi","Yangon","Yerevan","Chagos","Maldives"],au:["Perth","Eucla","Adelaide","Broken_Hill","Darwin","Brisbane","Hobart","Lindeman","Melbourne","Sydney","Lord_Howe"],na:["Adak","Anchorage","Bahia_Banderas","Barbados","Belize","Boise","Cambridge_Bay","Cancun","Chicago","Chihuahua","Ciudad_Juarez","Costa_Rica","Dawson","Dawson_Creek","Denver","Detroit","Edmonton","El_Salvador","Fort_Nelson","Glace_Bay","Goose_Bay","Grand_Turk","Guatemala","Halifax","Havana","Hermosillo","Indiana/Indianapolis","Indiana/Knox","Indiana/Marengo","Indiana/Petersburg","Indiana/Tell_City","Indiana/Vevay","Indiana/Vincennes","Indiana/Winamac","Inuvik","Iqaluit","Jamaica","Juneau","Kentucky/Louisville","Kentucky/Monticello","Los_Angeles","Managua","Martinique","Matamoros","Mazatlan","Menominee","Merida","Metlakatla","Mexico_City","Miquelon","Moncton","Monterrey","New_York","Nome","North_Dakota/Beulah","North_Dakota/Center","North_Dakota/New_Salem","Ojinaga","Panama","Phoenix","Port-au-Prince","Puerto_Rico","Rankin_Inlet","Regina","Resolute","Santo_Domingo","Sitka","St_Johns","Swift_Current","Tegucigalpa","Tijuana","Toronto","Vancouver","Whitehorse","Winnipeg","Yakutat","Yellowknife","Bermuda","Honolulu"],sa:["Araguaina","Argentina/Buenos_Aires","Argentina/Catamarca","Argentina/Cordoba","Argentina/Jujuy","Argentina/La_Rioja","Argentina/Mendoza","Argentina/Rio_Gallegos","Argentina/Salta","Argentina/San_Juan","Argentina/San_Luis","Argentina/Tucuman","Argentina/Ushuaia","Asuncion","Bahia","Belem","Boa_Vista","Bogota","Campo_Grande","Caracas","Cayenne","Cuiaba","Eirunepe","Fortaleza","Guayaquil","Guyana","La_Paz","Lima","Maceio","Manaus","Montevideo","Noronha","Paramaribo","Porto_Velho","Punta_Arenas","Recife","Rio_Branco","Santarem","Santiago","Sao_Paulo","Palmer","South_Georgia","Stanley","Easter","Galapagos"],at:["Cape_Verde","Canary","Faroe","Madeira","Azores","Bermuda","South_Georgia","Stanley"],in:["Mauritius","Maldives","Chagos"],pa:["Palau","Guam","Port_Moresby","Bougainville","Efate","Guadalcanal","Kosrae","Norfolk","Noumea","Auckland","Fiji","Kwajalein","Nauru","Tarawa","Chatham","Apia","Fakaofo","Kanton","Tongatapu","Kiritimati","Pitcairn","Gambier","Marquesas","Rarotonga","Tahiti","Niue","Pago_Pago","Honolulu","Easter","Galapagos"],aq:["Troll","Mawson","Davis","Casey","Rothera","Macquarie","Palmer"],etc:["Greenwich","Universal","Zulu","GMT-14","GMT-13","GMT-12","GMT-11","GMT-10","GMT-9","GMT-8","GMT-7","GMT-6","GMT-5","GMT-4","GMT-3","GMT-2","GMT-1","GMT","GMT+1","GMT+2","GMT+3","GMT+4","GMT+5","GMT+6","GMT+7","GMT+8","GMT+9","GMT+10","GMT+11","GMT+12","UCT","UTC"]};const regions={etc:"Etc",af:"Africa",as:"Asia",au:"Australia",aq:"Antarctica",eu:"Europe",na:"America",sa:"America",at:"Atlantic",in:"Indian",pa:"Pacific"},licenseData=[],licenseApp=[{t:"Petite Vue",y:2021,a:"Yuxi (Evan) You",l:"mit"},{t:"Petite Vue I18n Lite",y:2021,a:"Front Labs",l:"mit"},{t:"Ace Editor",y:2010,a:"Ajax.org B.V.",r:1,l:"bsd"},{t:"MaterialDesign Icons",y:2022,a:"Google",l:"apache2"}];function Credits(a){return{$template:"#credit-template",model:a}}function RegionItem(a,o,e){return{$template:"#region-template",model:a,region:o,i18n:e,list(e){if(a[e]&&o[e]){for(var n="etc"===e?a[e]:a[e].sort(),t=[],i=0;ie.t(a).toString().replace(/_/g," ")}}fetch("/static/en.json?COMMIT_HASH").then((a=>a.json())).then((a=>{const o=reactive(createI18n({locale:"en",fallbackLocale:"en",messages:{en:a.en}}));createApp({i18n:o,languages:languages,RegionItem:RegionItem,regions:regions,locations:locations,licenseData:licenseData,licenseApp:licenseApp,Credits:Credits,hostname:null,title:null,config:{hasp:null,wifi:null,mqtt:null,http:null,gui:null,gpio:null,debug:null,time:null,ota:null},info:null,files:null,show:null,t(a){return this.i18n.t(a)},fetchConfig(a){fetch("/api/config/"+a+"/").then((a=>a.json())).then((o=>{this.config[a]=o,this.show=a,document.title=a}))},submitConfig(){let a=this.show;fetch("/api/config/"+a+"/",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(this.config[a])}).then((a=>a.json())).then((o=>{this.config[a]=o,window.history.pushState({},"","/config/"),window.dispatchEvent(new Event("popstate"))}))},submitOldConfig(a){fetch("/api/config/"+a+"/",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(this.config[a])}).then((a=>a.json())).then((a=>{window.location.href="/config"}))},fetchLang(a){fetch("/static/"+a+".json?COMMIT_HASH").then((a=>a.json())).then((o=>{let e=o[a]?o[a]:{};this.i18n.setLocaleMessage(a,e),this.i18n.changeLocale(a),console.log(a)}))},fetchInfo(){fetch("/api/info/").then((a=>a.json())).then((a=>{this.info=a,this.show="info",document.title="Info"}))},fetchAbout(){fetch("/api/credits/").then((a=>a.json())).then((a=>{this.licenseData=a,this.show="about",document.title="About"}))},showPage(a){console.log("showPage "+a),this.show=a,document.title=a,""!=a&&(a+="/")},showInfo(){console.log("showInfo"),this.fetchInfo(),document.title="Info"},showConfig(a){console.log("showConfig "+a),this.fetchConfig(a),document.title=a},showEditor(){console.log("showEditor"),fetch("/api/files/").then((a=>a.json())).then((a=>{this.files=a,this.show="edit";var o=document.getElementsByClassName("container__editor")[0];o&&(o.style.display="flex"),document.title="Editor"}))},handleLocation(a,o){const e={"/":()=>{this.showPage("")},"/hasp.htm":()=>{this.showPage("")},"/config/":()=>{this.showPage("config")},"/config/hasp/":()=>{this.showConfig("hasp")},"/config/wifi/":()=>{this.showConfig("wifi")},"/config/http/":()=>{this.showConfig("http")},"/config/mqtt/":()=>{this.showConfig("mqtt")},"/config/gui/":()=>{this.showConfig("gui")},"/config/ftp/":()=>{this.showConfig("ftp")},"/config/time/":()=>{this.showConfig("time")},"/config/debug/":()=>{this.showConfig("debug")},"/config/reset/":()=>{this.showPage("reset")},"/firmware/":()=>{this.showConfig("ota")},"/info/":()=>{this.showInfo()},"/screenshot/":()=>{this.showPage("screenshot")},"/about/":()=>{this.fetchAbout()},"/edit/":()=>{this.showEditor()},"/edit":()=>{},"/static/editor.htm":()=>{},"/reboot/":()=>{this.showPage("reboot")}};"function"==typeof e[a]?(console.log("Location: "+a),e[a]()):"/"!==a.slice(-1)&&"function"==typeof e[a+"/"]?(console.log("Location: "+a),e[a+"/"]()):(console.log("Not found: "+a),e["/"]);const n=document.getElementsByClassName("container__editor")[0];n&&(n.style.display=a.includes("/edit")?"flex":"none"),window.scrollTo({top:o})},mounted(){let a=decodeURIComponent(document.cookie).split(";");for(let o=0;o{const o=window.location.pathname;console.log("Popstate: "+o),console.log(a);var e=a.state,n=0;e&&(n=e.scrollTop),this.handleLocation(o,n)};const o=window.location.pathname;this.handleLocation(o,0),console.log("App Mounted")},route(a){console.log("Routing..."),a=a||window.event,console.log(a.target),a.preventDefault();const o=a.currentTarget.href||a.target.parentNode.href,e=new URL(o).pathname;if(window.location.pathname!=e){console.log("Push Route: "+e);var n={path:window.location.href||a.target.href,scrollTop:document.body.scrollTop};window.history.replaceState(n,"",document.location.pathname),n={path:window.location.href,scrollTop:0},window.history.pushState(n,"",e),window.dispatchEvent(new Event("popstate"))}},goto(a){if(console.log("Goto..."),window.location.pathname!=a){console.log("Push Route: "+a);var o={path:window.location.href,scrollTop:document.body.scrollTop};window.history.replaceState(o,"",document.location.pathname),o={path:window.location.href,scrollTop:0},window.history.pushState(o,"",a),window.dispatchEvent(new Event("popstate"))}},ref(a){},aref(a){setTimeout((function(){}),1e3*a)},upd(a){var o=(new Date).getTime();document.getElementById("bmp").src="/screenshot?a="+a+"&q="+o}}).directive("t",(({el:a,get:e,effect:n})=>n((()=>a.textContent=o.t(e()))))).directive("ts",(({el:a,get:e,effect:n})=>n((()=>a.textContent=o.t(e()).replace(/_/g," "))))).mount(),console.log("JS Loaded...")}));
\ No newline at end of file
+import{createApp,reactive,createI18n}from"/static/petite-vue.hasp.js?COMMIT_HASH";const languages=[{code:"en",name:"English"},{code:"nl",name:"Nederlands"},{code:"fr",name:"Français"}];var locations={af:["Abidjan","Algiers","Bissau","Cairo","Casablanca","El_Aaiun","Johannesburg","Juba","Khartoum","Lagos","Maputo","Monrovia","Nairobi","Ndjamena","Sao_Tome","Tripoli","Tunis","Windhoek","Cape_Verde","Mauritius"],eu:["Ceuta","Danmarkshavn","Nuuk","Scoresbysund","Thule","Anadyr","Barnaul","Chita","Irkutsk","Kamchatka","Khandyga","Krasnoyarsk","Magadan","Novokuznetsk","Novosibirsk","Omsk","Sakhalin","Srednekolymsk","Tomsk","Ust-Nera","Vladivostok","Yakutsk","Yekaterinburg","Azores","Canary","Faroe","Madeira","Andorra","Astrakhan","Athens","Belgrade","Berlin","Brussels","Bucharest","Budapest","Chisinau","Dublin","Gibraltar","Helsinki","Istanbul","Kaliningrad","Kirov","Kyiv","Lisbon","London","Madrid","Malta","Minsk","Moscow","Paris","Prague","Riga","Rome","Samara","Saratov","Sofia","Tallinn","Tirane","Ulyanovsk","Vienna","Vilnius","Volgograd","Warsaw","Zurich"],as:["Almaty","Amman","Aqtau","Aqtobe","Ashgabat","Atyrau","Baghdad","Baku","Bangkok","Beirut","Bishkek","Choibalsan","Colombo","Damascus","Dhaka","Dili","Dubai","Dushanbe","Famagusta","Gaza","Hebron","Ho_Chi_Minh","Hong_Kong","Hovd","Jakarta","Jayapura","Jerusalem","Kabul","Karachi","Kathmandu","Kolkata","Kuching","Macau","Makassar","Manila","Nicosia","Oral","Pontianak","Pyongyang","Qatar","Qostanay","Qyzylorda","Riyadh","Samarkand","Seoul","Shanghai","Singapore","Taipei","Tashkent","Tbilisi","Tehran","Thimphu","Tokyo","Ulaanbaatar","Urumqi","Yangon","Yerevan","Chagos","Maldives"],au:["Perth","Eucla","Adelaide","Broken_Hill","Darwin","Brisbane","Hobart","Lindeman","Melbourne","Sydney","Lord_Howe"],na:["Adak","Anchorage","Bahia_Banderas","Barbados","Belize","Boise","Cambridge_Bay","Cancun","Chicago","Chihuahua","Ciudad_Juarez","Costa_Rica","Dawson","Dawson_Creek","Denver","Detroit","Edmonton","El_Salvador","Fort_Nelson","Glace_Bay","Goose_Bay","Grand_Turk","Guatemala","Halifax","Havana","Hermosillo","Indiana/Indianapolis","Indiana/Knox","Indiana/Marengo","Indiana/Petersburg","Indiana/Tell_City","Indiana/Vevay","Indiana/Vincennes","Indiana/Winamac","Inuvik","Iqaluit","Jamaica","Juneau","Kentucky/Louisville","Kentucky/Monticello","Los_Angeles","Managua","Martinique","Matamoros","Mazatlan","Menominee","Merida","Metlakatla","Mexico_City","Miquelon","Moncton","Monterrey","New_York","Nome","North_Dakota/Beulah","North_Dakota/Center","North_Dakota/New_Salem","Ojinaga","Panama","Phoenix","Port-au-Prince","Puerto_Rico","Rankin_Inlet","Regina","Resolute","Santo_Domingo","Sitka","St_Johns","Swift_Current","Tegucigalpa","Tijuana","Toronto","Vancouver","Whitehorse","Winnipeg","Yakutat","Yellowknife","Bermuda","Honolulu"],sa:["Araguaina","Argentina/Buenos_Aires","Argentina/Catamarca","Argentina/Cordoba","Argentina/Jujuy","Argentina/La_Rioja","Argentina/Mendoza","Argentina/Rio_Gallegos","Argentina/Salta","Argentina/San_Juan","Argentina/San_Luis","Argentina/Tucuman","Argentina/Ushuaia","Asuncion","Bahia","Belem","Boa_Vista","Bogota","Campo_Grande","Caracas","Cayenne","Cuiaba","Eirunepe","Fortaleza","Guayaquil","Guyana","La_Paz","Lima","Maceio","Manaus","Montevideo","Noronha","Paramaribo","Porto_Velho","Punta_Arenas","Recife","Rio_Branco","Santarem","Santiago","Sao_Paulo","Palmer","South_Georgia","Stanley","Easter","Galapagos"],at:["Cape_Verde","Canary","Faroe","Madeira","Azores","Bermuda","South_Georgia","Stanley"],in:["Mauritius","Maldives","Chagos"],pa:["Palau","Guam","Port_Moresby","Bougainville","Efate","Guadalcanal","Kosrae","Norfolk","Noumea","Auckland","Fiji","Kwajalein","Nauru","Tarawa","Chatham","Apia","Fakaofo","Kanton","Tongatapu","Kiritimati","Pitcairn","Gambier","Marquesas","Rarotonga","Tahiti","Niue","Pago_Pago","Honolulu","Easter","Galapagos"],aq:["Troll","Mawson","Davis","Casey","Rothera","Macquarie","Palmer"],etc:["Greenwich","Universal","Zulu","GMT-14","GMT-13","GMT-12","GMT-11","GMT-10","GMT-9","GMT-8","GMT-7","GMT-6","GMT-5","GMT-4","GMT-3","GMT-2","GMT-1","GMT","GMT+1","GMT+2","GMT+3","GMT+4","GMT+5","GMT+6","GMT+7","GMT+8","GMT+9","GMT+10","GMT+11","GMT+12","UCT","UTC"]};const regions={etc:"Etc",af:"Africa",as:"Asia",au:"Australia",aq:"Antarctica",eu:"Europe",na:"America",sa:"America",at:"Atlantic",in:"Indian",pa:"Pacific"},licenseData=[],licenseApp=[{t:"Petite Vue",y:2021,a:"Yuxi (Evan) You",l:"mit"},{t:"Petite Vue I18n Lite",y:2021,a:"Front Labs",l:"mit"},{t:"Ace Editor",y:2010,a:"Ajax.org B.V.",r:1,l:"bsd"},{t:"MaterialDesign Icons",y:2022,a:"Google",l:"apache2"}];function Credits(a){return{$template:"#credit-template",model:a}}function RegionItem(a,o,e){return{$template:"#region-template",model:a,region:o,i18n:e,list(e){if(a[e]&&o[e]){for(var n="etc"===e?a[e]:a[e].sort(),t=[],i=0;ie.t(a).toString().replace(/_/g," ")}}fetch("/static/en.json?COMMIT_HASH").then((a=>a.json())).then((a=>{const o=reactive(createI18n({locale:"en",fallbackLocale:"en",messages:{en:a.en}}));createApp({i18n:o,languages:languages,RegionItem:RegionItem,regions:regions,locations:locations,licenseData:licenseData,licenseApp:licenseApp,Credits:Credits,hostname:null,title:null,config:{hasp:null,wifi:null,wg:null,mqtt:null,http:null,gui:null,gpio:null,debug:null,time:null,ota:null},info:null,files:null,show:null,t(a){return this.i18n.t(a)},fetchConfig(a){fetch("/api/config/"+a+"/").then((a=>a.json())).then((o=>{this.config[a]=o,this.show=a,document.title=a}))},submitConfig(){let a=this.show;fetch("/api/config/"+a+"/",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(this.config[a])}).then((a=>a.json())).then((o=>{this.config[a]=o,window.history.pushState({},"","/config/"),window.dispatchEvent(new Event("popstate"))}))},submitOldConfig(a){fetch("/api/config/"+a+"/",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(this.config[a])}).then((a=>a.json())).then((a=>{window.location.href="/config"}))},fetchLang(a){fetch("/static/"+a+".json?COMMIT_HASH").then((a=>a.json())).then((o=>{let e=o[a]?o[a]:{};this.i18n.setLocaleMessage(a,e),this.i18n.changeLocale(a),console.log(a)}))},fetchInfo(){fetch("/api/info/").then((a=>a.json())).then((a=>{this.info=a,this.show="info",document.title="Info"}))},fetchAbout(){fetch("/api/credits/").then((a=>a.json())).then((a=>{this.licenseData=a,this.show="about",document.title="About"}))},showPage(a){console.log("showPage "+a),this.show=a,document.title=a,""!=a&&(a+="/")},showInfo(){console.log("showInfo"),this.fetchInfo(),document.title="Info"},showConfig(a){console.log("showConfig "+a),this.fetchConfig(a),document.title=a},showEditor(){console.log("showEditor"),fetch("/api/files/").then((a=>a.json())).then((a=>{this.files=a,this.show="edit";var o=document.getElementsByClassName("container__editor")[0];o&&(o.style.display="flex"),document.title="Editor"}))},handleLocation(a,o){const e={"/":()=>{this.showPage("")},"/hasp.htm":()=>{this.showPage("")},"/config/":()=>{this.showPage("config")},"/config/hasp/":()=>{this.showConfig("hasp")},"/config/wifi/":()=>{this.showConfig("wifi")},"/config/wg/":()=>{this.showConfig("wg")},"/config/http/":()=>{this.showConfig("http")},"/config/mqtt/":()=>{this.showConfig("mqtt")},"/config/gui/":()=>{this.showConfig("gui")},"/config/ftp/":()=>{this.showConfig("ftp")},"/config/time/":()=>{this.showConfig("time")},"/config/debug/":()=>{this.showConfig("debug")},"/config/reset/":()=>{this.showPage("reset")},"/firmware/":()=>{this.showConfig("ota")},"/info/":()=>{this.showInfo()},"/screenshot/":()=>{this.showPage("screenshot")},"/about/":()=>{this.fetchAbout()},"/edit/":()=>{this.showEditor()},"/edit":()=>{},"/static/editor.htm":()=>{},"/reboot/":()=>{this.showPage("reboot")}};"function"==typeof e[a]?(console.log("Location: "+a),e[a]()):"/"!==a.slice(-1)&&"function"==typeof e[a+"/"]?(console.log("Location: "+a),e[a+"/"]()):(console.log("Not found: "+a),e["/"]);const n=document.getElementsByClassName("container__editor")[0];n&&(n.style.display=a.includes("/edit")?"flex":"none"),window.scrollTo({top:o})},mounted(){let a=decodeURIComponent(document.cookie).split(";");for(let o=0;o{const o=window.location.pathname;console.log("Popstate: "+o),console.log(a);var e=a.state,n=0;e&&(n=e.scrollTop),this.handleLocation(o,n)};const o=window.location.pathname;this.handleLocation(o,0),console.log("App Mounted")},route(a){console.log("Routing..."),a=a||window.event,console.log(a.target),a.preventDefault();const o=a.currentTarget.href||a.target.parentNode.href,e=new URL(o).pathname;if(window.location.pathname!=e){console.log("Push Route: "+e);var n={path:window.location.href||a.target.href,scrollTop:document.body.scrollTop};window.history.replaceState(n,"",document.location.pathname),n={path:window.location.href,scrollTop:0},window.history.pushState(n,"",e),window.dispatchEvent(new Event("popstate"))}},goto(a){if(console.log("Goto..."),window.location.pathname!=a){console.log("Push Route: "+a);var o={path:window.location.href,scrollTop:document.body.scrollTop};window.history.replaceState(o,"",document.location.pathname),o={path:window.location.href,scrollTop:0},window.history.pushState(o,"",a),window.dispatchEvent(new Event("popstate"))}},ref(a){},aref(a){setTimeout((function(){}),1e3*a)},upd(a){var o=(new Date).getTime();document.getElementById("bmp").src="/screenshot?a="+a+"&q="+o}}).directive("t",(({el:a,get:e,effect:n})=>n((()=>a.textContent=o.t(e()))))).directive("ts",(({el:a,get:e,effect:n})=>n((()=>a.textContent=o.t(e()).replace(/_/g," "))))).mount(),console.log("JS Loaded...")}));
\ No newline at end of file
diff --git a/data/nl_NL.json b/data/nl_NL.json
index 918de554..e99c54ed 100644
--- a/data/nl_NL.json
+++ b/data/nl_NL.json
@@ -85,6 +85,15 @@
"btn": "Wifi Instellingen",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "MQTT Instellingen",
"btn": "MQTT Instellingen",
diff --git a/data/pt_BR.json b/data/pt_BR.json
index 458b9ba5..2717d9ae 100644
--- a/data/pt_BR.json
+++ b/data/pt_BR.json
@@ -85,6 +85,15 @@
"btn": "Configurar Wifi",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "Configurar MQTT",
"btn": "Configurar MQTT",
diff --git a/data/pt_PT.json b/data/pt_PT.json
index a92b91a5..64f447e7 100644
--- a/data/pt_PT.json
+++ b/data/pt_PT.json
@@ -85,6 +85,15 @@
"btn": "Configurar Wifi",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "Configurar MQTT",
"btn": "Configurar MQTT",
diff --git a/data/ro_RO.json b/data/ro_RO.json
index 6c4269b8..bd92c3b8 100644
--- a/data/ro_RO.json
+++ b/data/ro_RO.json
@@ -85,6 +85,15 @@
"btn": "Setări WiFi",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "Setări MQTT",
"btn": "Setări MQTT",
diff --git a/data/script.js b/data/script.js
index f38d076c..baca1bb2 100644
--- a/data/script.js
+++ b/data/script.js
@@ -1 +1 @@
-var ctx_el;function _(e){return document.getElementById(e)}function hidectx(){_("ctx").style.display="none",ctx_el&&ctx_el.classList.remove("selitem"),ctx_el=void 0}function doesFontExist(e){var t=document.createElement("canvas"),n=t.getContext("2d"),o="abcdefghijklmnopqrstuvwxyz0123456789";n.font="72px monospace";var a=n.measureText(o).width;return n.font="72px '"+e+"', monospace",t=null,n.measureText(o).width!=a}function createEditor(e,t,n,o,a){function i(e){let t=/(?:\.([^.]+))?$/.exec(e)[1];if(void 0!==typeof t)switch(t){case"htm":case"html":return"html";case"js":return"javascript";case"cmd":case"json":case"jsonl":return"json";case"css":case"svg":case"xml":return t}return"plain_text"}void 0===n&&(n=i(t)),void 0===a&&(a="text/"+n);["basePath","modePath","themePath"].forEach((e=>{ace.config.set(e,"https://cdnjs.cloudflare.com/ajax/libs/ace/1.24.2")}));var c=ace.edit(e,{useWorker:!1,wrap:!0,indentedSoftWrap:!1,showPrintMargin:!1,highlightGutterLine:!0,useSoftTabs:!0,tabSize:2});c.setFontSize(parseFloat(getComputedStyle(document.documentElement).fontSize)),c.setReadOnly(!0),c.getSession().setUndoManager(new ace.UndoManager),void 0===o&&(o=window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"monokai":"textmate");var s=_("save"),l=_("undo"),r=_("redo"),d=_("cut"),m=_("copy"),u=_("paste"),p=_("font"),f=_("fontsize"),g="none"!==_(e).display;f.value=parseFloat(c.getFontSize()).toFixed(1),p.onchange=function(){c.setOption("fontFamily","'"+p.value+"',monospace")},f.onchange=function(){var e=parseFloat(f.value);!isNaN(e)&&e>=9&&e<=40&&c.setFontSize(e),f.value=parseFloat(c.getFontSize()).toFixed(1)};function h(){let e=!g||c.session.getSelection().isEmpty();d.disabled=e,m.disabled=e}function y(){let e=c.session.getUndoManager();s.disabled=!g||e.isClean(),l.disabled=!g||!e.hasUndo(),r.disabled=!g||!e.hasRedo()}function v(){if(void 0===t)return;const e=function(e){var t=e.getValue();try{var n=JSON.parse(t);return JSON.stringify(n)}catch(e){return t+""}}(c),n=new FormData;n.append("data",new Blob([e],{type:a}),t),fetch("/edit",{method:"POST",body:n}).then((e=>e.ok?e.text().then((e=>{console.log("Save OK /edit "+e)})):e.text().then((e=>{throw console.log("Save FAIL /edit"),new Error(e)})))).then((e=>{console.log(e),generateToast({message:"Saved "+t,background:"#ddd",color:"#000"})})).catch((e=>{console.warn("AbortError"===e.name?"Promise Aborted":"Promise Rejected"),alert(e)})).finally((()=>{y()}))}function x(){var e=c.getCopyText();if(window.clipboardData&&window.clipboardData.setData)return window.clipboardData.setData("Text",e);if(document.queryCommandSupported&&document.queryCommandSupported("copy")){c.focus();try{return document.execCommand("copy")}catch(t){return console.warn("Copy to clipboard failed.",t),prompt("Copy to clipboard: Ctrl+C, Enter",e)}}}function w(e){_("name").innerHTML=e;fetch(e).then((t=>t.ok?(console.log("OK "+e),t.text()):t.text().then((e=>{throw console.log("ERROR "+url),new Error(e)})))).then((e=>{try{var t=JSON.parse(e);c.setValue(JSON.stringify(t,null,4)),console.log("parse json OK")}catch(t){c.setValue(e),console.log("parse json FAIL")}null!==_("editor")&&(_("editor").style.display="block"),null!==_("preview")&&(_("preview").style.display="none"),g=!0,c.setReadOnly(!1),c.focus(),y()})).catch((e=>{console.log(e),alert(e),c.setReadOnly(!0)})).finally((()=>{c.resize(!0),c.scrollToLine(1,!0,!0,(function(){})),c.gotoLine(1,0,!0),c.clearSelection(),c.session.getUndoManager().reset()}))}return["Courier New","Monaco","Lucida Console","Monospace","ui-monospace","Roboto Mono","Inconsolata","IBM Plex Mono","Space Mono","PT Mono","Ubuntu Mono","Nanum Gothic Coding","Cousine","Fira Mono","Share Tech Mono","Courier Prime","Anonymous Pro","Cutive Mono","Overpass Mono","Fira Code","VT323","DM Mono","Oxygen Mono","Nova Mono","B612 Mono","Spline Sans Mono","Noto Sans Mono","Major Mono Display","Azeret Mono","Red Hat Mono","Syne Mono","Xanh Mono"].sort().forEach((function(e,t){if(doesFontExist(e)){var n=document.createElement("option");n.text=e,p.add(n)}})),null!==s&&null!==l&&null!==r&&c.on("input",y),c.session.selection.on("changeCursor",h),s.onclick=v,l.onclick=e=>{c.undo()&&c.focus()},r.onclick=e=>{c.redo()&&c.focus()},d.onclick=e=>{x()&&c.execCommand("cut")},m.onclick=e=>{x()&&c.execCommand("copy")},u.onclick=function(){try{navigator.clipboard.readText().then((e=>{c.execCommand("paste",e)})).catch((e=>{u.disabled=!0}))}catch{u.disabled=!0}},c.loadUrl=(e,o)=>{n=i(t=e+o),a="text/"+n,"plain"!==n&&c.getSession().setMode("ace/mode/"+n),w(e+o)},c.hide=()=>{g=!1,y(),h(),_("editor").style.display="none"},"plain"!==n&&c.getSession().setMode("ace/mode/"+n),c.setTheme("ace/theme/"+o),c.$blockScrolling=1/0,c.commands.addCommand({name:"save",bindKey:{win:"Ctrl-S",mac:"Command-S"},exec:v,readOnly:!1}),c.commands.addCommand({name:"undo",bindKey:{win:"Ctrl-Z",mac:"Command-Z"},exec:function(){c.undo()}}),c.commands.addCommand({name:"redo",bindKey:{win:"Ctrl-Y",mac:"Command-Y"},exec:function(){c.redo()}}),void 0!==t&&w(t),c.resize(),c}function uploadFileAsync(e,t,n,o,a,i){fetchData("/edit","POST",e).then((e=>{generateToast({message:"Upload "+n+"/"+o+" "+t+" done.",background:"#ddd",color:"#000"}),n==o&&listFiles(a,i)}))}function doUpload(e,t){const n=_("upload"),o=n.files.length;if(0!==o)for(let a=0;a=0}function isText(e){if(isFolder(e))return!1;var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"txt":case"cmd":case"json":case"jsonl":case"htm":case"html":case"js":case"c":case"cpp":case"css":case"svg":case"xml":return!0}return!1}function isImage(e){if(isFolder(e))return!1;var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"bmp":case"png":case"jpg":case"gif":case"svg":return!0}return!1}function isAudio(e){if(isFolder(e))return!1;var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"wav":case"mp3":case"aac":case"m4a":case"wma":return!0}return!1}function icon(e){if(isFolder(e))return"dir";if(isImage(e))return"image";if(isAudio(e))return"audio";var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"cmd":case"css":case"json":case"jsonl":case"ttf":return t;case"zip":case"gz":return"zip";case"html":case"htm":return"html"}return"file"}function preview(e,t){if(isImage(e)){let n=t+e.name;const o=_("preview");o.innerHTML='
',o.style.display="block",ace.edit("editor").hide(),_("name").innerHTML=n}}function edit(e,t){isText(e)&&(ace.edit("editor").loadUrl(t,e.name),_("preview").style.display="none")}function url(e,t){console.log("click "+t+e.name),isImage(e)?preview(e,t):isText(e)&&edit(e,t)}async function fetchData(e,t,n,o){await fetch(e,{method:t,body:n}).then((n=>n.ok?(console.log(t+" OK "+e),n.text()):n.text().then((n=>{throw console.log(t+" FAIL "+e),new Error(n)})))).then((e=>{o&&o.remove(),console.log(e)})).catch((e=>{console.warn("AbortError"===e.name?"Promise Aborted":"Promise Rejected"),alert(e)})).finally((()=>{}))}function download(e,t){console.log("download "+t+e.name),document.getElementById("download-frame").src=t+e.name+"?download=true"}function remove(e,t,n){let o=t+e.name;isFolder(e)&&(o+="/"),console.log("remove "+o);const a=new FormData;a.append("path",o),fetchData("/edit","DELETE",a,n)}function create(e,t,n){var o=window.prompt("Create File in "+e,"");if(null==o||""==o||o.includes("/"))return;const a=new FormData;a.append("path",e+o),fetchData("/edit","PUT",a),fetch("/api/files/").then((e=>e.json())).then((o=>{t&&t.remove(),listFiles(n,e),console.log(o)}))}function upload(e,t){_("upload").onchange=()=>{doUpload(e,t)},_("upload").click()}function ctx(e,t,n,o){e.preventDefault(),ctx_el=o;let a,i=isFolder(t),c=_("ctx");c.style.display="block",a=c.getElementsByTagName("li")[0],a.onclick=i?function(){hidectx(),create(n+t.name+"/",o.children.item(1),o)}:function(){hidectx(),create(n,o.parentNode,o.parentNode.parentNode)},a.style.display=i?"block":"none",a=c.getElementsByTagName("li")[1],i&&(a.onclick=function(){hidectx(),upload(o,n+t.name+"/")}),a.style.display=i?"block":"none",a=c.getElementsByTagName("li")[2],a.onclick=function(){edit(t,n),hidectx()},a.style.display=isText(t)?"block":"none",a=c.getElementsByTagName("li")[3],a.onclick=function(){preview(t,n),hidectx()},a.style.display=isImage(t)?"block":"none",a=c.getElementsByTagName("li")[4],a.onclick=function(){download(t,n),hidectx()},a.style.display=i?"none":"block",a=c.getElementsByTagName("li")[5],a.onclick=function(){remove(t,n,o),hidectx()},a.style.display=n?"block":"none";var s=document.body.scrollTop?document.body.scrollTop:document.documentElement.scrollTop,l=document.body.scrollLeft?document.body.scrollLeft:document.documentElement.scrollLeft,r=e.clientX+l+10,d=e.clientY+s-20,m=(c.offsetWidth,c.offsetHeight),u=document.documentElement.clientHeight;d+m>u&&(d=u-m-20),c.style.left=r+"px",c.style.top=d+"px",o&&o.classList.add("selitem")}function drag(e,t,n){let o=n+t.name;isFolder(t)&&(o+="/"),e.dataTransfer.setData("text",o),console.log("drag start "+o)}function drop(e,t){let n=e.dataTransfer.getData("text");n.startsWith(t)||(e.preventDefault(),console.log("Move "+n+" to "+t))}function listFiles(e,t){return console.log("listFiles"),fetch("/api/files/?dir="+t).then((e=>e.json())).then((n=>{if(0==n.length)return!1;let o=e.getElementsByTagName("div")[0];o&&(o.onclick=n=>{i.remove(),o.onclick=()=>{listFiles(e,t)},n.stopPropagation()});let a=e.getElementsByTagName("ul");for(let e=0;e{drag(event,e,t)},a.appendChild(s),s.innerHTML=''+o+"",isFolder(e)){let n=t+e.name+"/";s.classList.add("bold"),s.onclick=function(e){listFiles(a,n)},s.ondragover=e=>{e.preventDefault()},s.ondrop=e=>{drop(e,n)}}else(isText(e)||isImage(e)||isAudio(e))&&(s.onclick=function(n){url(e,t)});s.oncontextmenu=n=>{ctx(n,e,t,a)}}return e.scrollIntoView(),!0}))}function generateToast({message:e,background:t="#00214d",color:n="#fffffe",length:o="7000ms"}){_("toast").insertAdjacentHTML("afterbegin",`\n ${e}\n
`);const a=_("toast").firstElementChild;a.addEventListener("animationend",(()=>a.remove()))}document.addEventListener("blur",(function(){hidectx()})),document.addEventListener("DOMContentLoaded",(function(){createEditor("editor",void 0,void 0,void 0);listFiles(_("tree"),"/"),_("tree").getElementsByTagName("div")[0].oncontextmenu=e=>{ctx(e,{name:"",children:[]},"",_("tree"))},_("load").onclick=function(e){const t=new FormData;t.append("load",""),fetchData("/edit","PUT",t)},_("init").onclick=function(e){const t=new FormData;t.append("init",""),fetchData("/edit","PUT",t)},_("home").onclick=function(e){window.location.href="/"},_("page").onchange=function(e){const t=new FormData;t.append("page",_("page").value),fetchData("/edit","PUT",t)}})),document.addEventListener("DOMContentLoaded",(function(){const e=document.getElementById("dragMe"),t=e.previousElementSibling,n=e.nextElementSibling;let o=0,a=0,i=0;const c=function(a){const c=a.clientX-o,s=(a.clientY,100*(i+c)/e.parentNode.getBoundingClientRect().width);t.style.width=`${s}%`,t.style.right=t.style.width,e.style.cursor="col-resize",document.body.style.cursor="col-resize",t.style.userSelect="none",t.style.pointerEvents="none",n.style.userSelect="none",n.style.pointerEvents="none",ace.edit("editor").resize()},s=function(){e.style.removeProperty("cursor"),document.body.style.removeProperty("cursor"),t.style.removeProperty("user-select"),t.style.removeProperty("pointer-events"),n.style.removeProperty("user-select"),n.style.removeProperty("pointer-events"),document.removeEventListener("mousemove",c),document.removeEventListener("mouseup",s)};e.addEventListener("mousedown",(function(e){o=e.clientX,a=e.clientY,i=t.getBoundingClientRect().width,document.addEventListener("mousemove",c),document.addEventListener("mouseup",s)})),e.addEventListener("dblclick",(()=>{var e=t.style.visibility="hidden"===t.style.visibility;t.style.visibility=e?"unset":"hidden",t.style.position=e?"unset":"absolute",ace.edit("editor").resize()}))}));
\ No newline at end of file
+var ctx_el;function _(e){return document.getElementById(e)}function hidectx(){_("ctx").style.display="none",ctx_el&&ctx_el.classList.remove("selitem"),ctx_el=void 0}function doesFontExist(e){var t=document.createElement("canvas"),n=t.getContext("2d"),o="abcdefghijklmnopqrstuvwxyz0123456789";n.font="72px monospace";var a=n.measureText(o).width;return n.font="72px '"+e+"', monospace",t=null,n.measureText(o).width!=a}function createEditor(e,t,n,o,a){function i(e){let t=/(?:\.([^.]+))?$/.exec(e)[1];if(void 0!==typeof t)switch(t){case"htm":case"html":return"html";case"js":return"javascript";case"cmd":case"json":case"jsonl":return"json";case"css":case"svg":case"xml":return t}return"plain_text"}void 0===n&&(n=i(t)),void 0===a&&(a="text/"+n);["basePath","modePath","themePath"].forEach((e=>{ace.config.set(e,"https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.6")}));var c=ace.edit(e,{useWorker:!1,wrap:!0,indentedSoftWrap:!1,showPrintMargin:!1,highlightGutterLine:!0,useSoftTabs:!0,tabSize:2});c.setFontSize(parseFloat(getComputedStyle(document.documentElement).fontSize)),c.setReadOnly(!0),c.getSession().setUndoManager(new ace.UndoManager),void 0===o&&(o=window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"monokai":"textmate");var s=_("save"),l=_("undo"),r=_("redo"),d=_("cut"),m=_("copy"),u=_("paste"),p=_("font"),f=_("fontsize"),g="none"!==_(e).display;f.value=parseFloat(c.getFontSize()).toFixed(1),p.onchange=function(){c.setOption("fontFamily","'"+p.value+"',monospace")},f.onchange=function(){var e=parseFloat(f.value);!isNaN(e)&&e>=9&&e<=40&&c.setFontSize(e),f.value=parseFloat(c.getFontSize()).toFixed(1)};function h(){let e=!g||c.session.getSelection().isEmpty();d.disabled=e,m.disabled=e}function y(){let e=c.session.getUndoManager();s.disabled=!g||e.isClean(),l.disabled=!g||!e.hasUndo(),r.disabled=!g||!e.hasRedo()}function v(){if(void 0===t)return;const e=function(e){var t=e.getValue();try{var n=JSON.parse(t);return JSON.stringify(n)}catch(e){return t+""}}(c),n=new FormData;n.append("data",new Blob([e],{type:a}),t),fetch("/edit",{method:"POST",body:n}).then((e=>e.ok?e.text().then((e=>{console.log("Save OK /edit "+e)})):e.text().then((e=>{throw console.log("Save FAIL /edit"),new Error(e)})))).then((e=>{console.log(e),generateToast({message:"Saved "+t,background:"#ddd",color:"#000"})})).catch((e=>{console.warn("AbortError"===e.name?"Promise Aborted":"Promise Rejected"),alert(e)})).finally((()=>{y()}))}function x(){var e=c.getCopyText();if(window.clipboardData&&window.clipboardData.setData)return window.clipboardData.setData("Text",e);if(document.queryCommandSupported&&document.queryCommandSupported("copy")){c.focus();try{return document.execCommand("copy")}catch(t){return console.warn("Copy to clipboard failed.",t),prompt("Copy to clipboard: Ctrl+C, Enter",e)}}}function w(e){_("name").innerHTML=e;fetch(e).then((t=>t.ok?(console.log("OK "+e),t.text()):t.text().then((e=>{throw console.log("ERROR "+url),new Error(e)})))).then((e=>{try{var t=JSON.parse(e);c.setValue(JSON.stringify(t,null,4)),console.log("parse json OK")}catch(t){c.setValue(e),console.log("parse json FAIL")}null!==_("editor")&&(_("editor").style.display="block"),null!==_("preview")&&(_("preview").style.display="none"),g=!0,c.setReadOnly(!1),c.focus(),y()})).catch((e=>{console.log(e),alert(e),c.setReadOnly(!0)})).finally((()=>{c.resize(!0),c.scrollToLine(1,!0,!0,(function(){})),c.gotoLine(1,0,!0),c.clearSelection(),c.session.getUndoManager().reset()}))}return["Courier New","Monaco","Lucida Console","Monospace","ui-monospace","Roboto Mono","Inconsolata","IBM Plex Mono","Space Mono","PT Mono","Ubuntu Mono","Nanum Gothic Coding","Cousine","Fira Mono","Share Tech Mono","Courier Prime","Anonymous Pro","Cutive Mono","Overpass Mono","Fira Code","VT323","DM Mono","Oxygen Mono","Nova Mono","B612 Mono","Spline Sans Mono","Noto Sans Mono","Major Mono Display","Azeret Mono","Red Hat Mono","Syne Mono","Xanh Mono"].sort().forEach((function(e,t){if(doesFontExist(e)){var n=document.createElement("option");n.text=e,p.add(n)}})),null!==s&&null!==l&&null!==r&&c.on("input",y),c.session.selection.on("changeCursor",h),s.onclick=v,l.onclick=e=>{c.undo()&&c.focus()},r.onclick=e=>{c.redo()&&c.focus()},d.onclick=e=>{x()&&c.execCommand("cut")},m.onclick=e=>{x()&&c.execCommand("copy")},u.onclick=function(){try{navigator.clipboard.readText().then((e=>{c.execCommand("paste",e)})).catch((e=>{u.disabled=!0}))}catch{u.disabled=!0}},c.loadUrl=(e,o)=>{n=i(t=e+o),a="text/"+n,"plain"!==n&&c.getSession().setMode("ace/mode/"+n),w(e+o)},c.hide=()=>{g=!1,y(),h(),_("editor").style.display="none"},"plain"!==n&&c.getSession().setMode("ace/mode/"+n),c.setTheme("ace/theme/"+o),c.$blockScrolling=1/0,c.commands.addCommand({name:"save",bindKey:{win:"Ctrl-S",mac:"Command-S"},exec:v,readOnly:!1}),c.commands.addCommand({name:"undo",bindKey:{win:"Ctrl-Z",mac:"Command-Z"},exec:function(){c.undo()}}),c.commands.addCommand({name:"redo",bindKey:{win:"Ctrl-Y",mac:"Command-Y"},exec:function(){c.redo()}}),void 0!==t&&w(t),c.resize(),c}function uploadFileAsync(e,t,n,o,a,i){fetchData("/edit","POST",e).then((e=>{generateToast({message:"Upload "+n+"/"+o+" "+t+" done.",background:"#ddd",color:"#000"}),n==o&&listFiles(a,i)}))}function doUpload(e,t){const n=_("upload"),o=n.files.length;if(0!==o)for(let a=0;a=0}function isText(e){if(isFolder(e))return!1;var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"txt":case"cmd":case"json":case"jsonl":case"htm":case"html":case"js":case"c":case"cpp":case"css":case"svg":case"xml":return!0}return!1}function isImage(e){if(isFolder(e))return!1;var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"bmp":case"png":case"jpg":case"gif":case"svg":return!0}return!1}function isAudio(e){if(isFolder(e))return!1;var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"wav":case"mp3":case"aac":case"m4a":case"wma":return!0}return!1}function icon(e){if(isFolder(e))return"dir";if(isImage(e))return"image";if(isAudio(e))return"audio";var t=/(?:\.([^.]+))?$/.exec(e.name)[1];if(void 0!==typeof t)switch(t){case"cmd":case"css":case"json":case"jsonl":case"ttf":return t;case"zip":case"gz":return"zip";case"html":case"htm":return"html"}return"file"}function preview(e,t){if(isImage(e)){let n=t+e.name;const o=_("preview");o.innerHTML='
',o.style.display="block",ace.edit("editor").hide(),_("name").innerHTML=n}}function edit(e,t){isText(e)&&(ace.edit("editor").loadUrl(t,e.name),_("preview").style.display="none")}function url(e,t){console.log("click "+t+e.name),isImage(e)?preview(e,t):isText(e)&&edit(e,t)}async function fetchData(e,t,n,o){await fetch(e,{method:t,body:n}).then((n=>n.ok?(console.log(t+" OK "+e),n.text()):n.text().then((n=>{throw console.log(t+" FAIL "+e),new Error(n)})))).then((e=>{o&&o.remove(),console.log(e)})).catch((e=>{console.warn("AbortError"===e.name?"Promise Aborted":"Promise Rejected"),alert(e)})).finally((()=>{}))}function download(e,t){console.log("download "+t+e.name),document.getElementById("download-frame").src=t+e.name+"?download=true"}function remove(e,t,n){let o=t+e.name;isFolder(e)&&(o+="/"),console.log("remove "+o);const a=new FormData;a.append("path",o),fetchData("/edit","DELETE",a,n)}function create(e,t,n){var o=window.prompt("Create File in "+e,"");if(null==o||""==o||o.includes("/"))return;const a=new FormData;a.append("path",e+o),fetchData("/edit","PUT",a),fetch("/api/files/").then((e=>e.json())).then((o=>{t&&t.remove(),listFiles(n,e),console.log(o)}))}function upload(e,t){_("upload").onchange=()=>{doUpload(e,t)},_("upload").click()}function ctx(e,t,n,o){e.preventDefault(),ctx_el=o;let a,i=isFolder(t),c=_("ctx");c.style.display="block",a=c.getElementsByTagName("li")[0],a.onclick=i?function(){hidectx(),create(n+t.name+"/",o.children.item(1),o)}:function(){hidectx(),create(n,o.parentNode,o.parentNode.parentNode)},a.style.display=i?"block":"none",a=c.getElementsByTagName("li")[1],i&&(a.onclick=function(){hidectx(),upload(o,n+t.name+"/")}),a.style.display=i?"block":"none",a=c.getElementsByTagName("li")[2],a.onclick=function(){edit(t,n),hidectx()},a.style.display=isText(t)?"block":"none",a=c.getElementsByTagName("li")[3],a.onclick=function(){preview(t,n),hidectx()},a.style.display=isImage(t)?"block":"none",a=c.getElementsByTagName("li")[4],a.onclick=function(){download(t,n),hidectx()},a.style.display=i?"none":"block",a=c.getElementsByTagName("li")[5],a.onclick=function(){remove(t,n,o),hidectx()},a.style.display=n?"block":"none";var s=document.body.scrollTop?document.body.scrollTop:document.documentElement.scrollTop,l=document.body.scrollLeft?document.body.scrollLeft:document.documentElement.scrollLeft,r=e.clientX+l+10,d=e.clientY+s-20,m=(c.offsetWidth,c.offsetHeight),u=document.documentElement.clientHeight;d+m>u&&(d=u-m-20),c.style.left=r+"px",c.style.top=d+"px",o&&o.classList.add("selitem")}function drag(e,t,n){let o=n+t.name;isFolder(t)&&(o+="/"),e.dataTransfer.setData("text",o),console.log("drag start "+o)}function drop(e,t){let n=e.dataTransfer.getData("text");n.startsWith(t)||(e.preventDefault(),console.log("Move "+n+" to "+t))}function listFiles(e,t){return console.log("listFiles"),fetch("/api/files/?dir="+t).then((e=>e.json())).then((n=>{if(0==n.length)return!1;let o=e.getElementsByTagName("div")[0];o&&(o.onclick=n=>{i.remove(),o.onclick=()=>{listFiles(e,t)},n.stopPropagation()});let a=e.getElementsByTagName("ul");for(let e=0;e{drag(event,e,t)},a.appendChild(s),s.innerHTML=''+o+"",isFolder(e)){let n=t+e.name+"/";s.classList.add("bold"),s.onclick=function(e){listFiles(a,n)},s.ondragover=e=>{e.preventDefault()},s.ondrop=e=>{drop(e,n)}}else(isText(e)||isImage(e)||isAudio(e))&&(s.onclick=function(n){url(e,t)});s.oncontextmenu=n=>{ctx(n,e,t,a)}}return e.scrollIntoView(),!0}))}function generateToast({message:e,background:t="#00214d",color:n="#fffffe",length:o="7000ms"}){_("toast").insertAdjacentHTML("afterbegin",`\n ${e}\n
`);const a=_("toast").firstElementChild;a.addEventListener("animationend",(()=>a.remove()))}document.addEventListener("blur",(function(){hidectx()})),document.addEventListener("DOMContentLoaded",(function(){createEditor("editor",void 0,void 0,void 0);listFiles(_("tree"),"/"),_("tree").getElementsByTagName("div")[0].oncontextmenu=e=>{ctx(e,{name:"",children:[]},"",_("tree"))},_("load").onclick=function(e){const t=new FormData;t.append("load",""),fetchData("/edit","PUT",t)},_("init").onclick=function(e){const t=new FormData;t.append("init",""),fetchData("/edit","PUT",t)},_("home").onclick=function(e){window.location.href="/"},_("page").onchange=function(e){const t=new FormData;t.append("page",_("page").value),fetchData("/edit","PUT",t)}})),document.addEventListener("DOMContentLoaded",(function(){const e=document.getElementById("dragMe"),t=e.previousElementSibling,n=e.nextElementSibling;let o=0,a=0,i=0;const c=function(a){const c=a.clientX-o,s=(a.clientY,100*(i+c)/e.parentNode.getBoundingClientRect().width);t.style.width=`${s}%`,t.style.right=t.style.width,e.style.cursor="col-resize",document.body.style.cursor="col-resize",t.style.userSelect="none",t.style.pointerEvents="none",n.style.userSelect="none",n.style.pointerEvents="none",ace.edit("editor").resize()},s=function(){e.style.removeProperty("cursor"),document.body.style.removeProperty("cursor"),t.style.removeProperty("user-select"),t.style.removeProperty("pointer-events"),n.style.removeProperty("user-select"),n.style.removeProperty("pointer-events"),document.removeEventListener("mousemove",c),document.removeEventListener("mouseup",s)};e.addEventListener("mousedown",(function(e){o=e.clientX,a=e.clientY,i=t.getBoundingClientRect().width,document.addEventListener("mousemove",c),document.addEventListener("mouseup",s)})),e.addEventListener("dblclick",(()=>{var e=t.style.visibility="hidden"===t.style.visibility;t.style.visibility=e?"unset":"hidden",t.style.position=e?"unset":"absolute",ace.edit("editor").resize()}))}));
\ No newline at end of file
diff --git a/data/zh_CN.json b/data/zh_CN.json
index 34d310c4..146e267b 100644
--- a/data/zh_CN.json
+++ b/data/zh_CN.json
@@ -85,6 +85,15 @@
"btn": "Wifi 设置",
"ssid": "SSID"
},
+ "wg": {
+ "title": "WireGuard Settings",
+ "btn": "WireGuard Settings",
+ "vpnip": "VPN IP",
+ "privkey": "Private Key",
+ "host": "Remote IP",
+ "port": "Remote Port",
+ "pubkey": "Remote Public Key"
+ },
"mqtt": {
"title": "MQTT 设置",
"btn": "MQTT 设置",
diff --git a/hal/sdl2/app_hal.c b/hal/sdl2/app_hal.c
index fd062ada..c7524836 100644
--- a/hal/sdl2/app_hal.c
+++ b/hal/sdl2/app_hal.c
@@ -1,3 +1,4 @@
+#if USE_MONITOR
#include
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
#include
@@ -53,3 +54,4 @@ void hal_loop(void)
// lv_task_handler();
// }
}
+#endif
diff --git a/include/VersionInfo.h b/include/VersionInfo.h
index 885dc775..55609e90 100644
--- a/include/VersionInfo.h
+++ b/include/VersionInfo.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/* This file is used during the build of the paho library */
diff --git a/include/espspi/Ethernet.h b/include/espspi/Ethernet.h
index b5b35acf..d8f5baf3 100644
--- a/include/espspi/Ethernet.h
+++ b/include/espspi/Ethernet.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef WIFISPI_H
diff --git a/include/hasp_conf.h b/include/hasp_conf.h
index 16a4ab23..978aa450 100644
--- a/include/hasp_conf.h
+++ b/include/hasp_conf.h
@@ -1,9 +1,13 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_CONF_H
#define HASP_CONF_H
+#if HASP_TARGET_ARDUINO
+#include "Arduino.h"
+#endif
+
#ifdef USE_CONFIG_OVERRIDE
#include "user_config_override.h"
#endif
@@ -33,6 +37,11 @@
#define HASP_USE_APP 1
+/* Validate that build target was specified */
+#if HASP_TARGET_ARDUINO + HASP_TARGET_PC != 1
+#error "Build target invalid! Set *one* of: HASP_TARGET_ARDUINO, HASP_TARGET_PC"
+#endif
+
#ifndef HASP_USE_DEBUG
#define HASP_USE_DEBUG 1
#endif
@@ -65,6 +74,14 @@
#define HASP_USE_MQTT (HASP_HAS_NETWORK)
#endif
+#ifndef HASP_USE_MQTT_ASYNC
+#define HASP_USE_MQTT_ASYNC (HASP_TARGET_PC)
+#endif
+
+#ifndef HASP_USE_WIREGUARD
+#define HASP_USE_WIREGUARD (HASP_HAS_NETWORK)
+#endif
+
#ifndef HASP_USE_BROADCAST
#define HASP_USE_BROADCAST 1
#endif
@@ -186,6 +203,46 @@
#define HASP_OBJECT_NOTATION "p%ub%u"
+#ifndef HASP_ATTRIBUTE_FAST_MEM
+#define HASP_ATTRIBUTE_FAST_MEM
+#endif
+
+#ifndef IRAM_ATTR
+#define IRAM_ATTR
+#endif
+
+#if !defined(FPSTR)
+#define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer))
+#endif
+
+#if !defined(PGM_P)
+#define PGM_P const char*
+#endif
+
+/* Workarounds for PC build */
+#if HASP_TARGET_PC
+#ifndef __FlashStringHelper
+typedef char __FlashStringHelper;
+#endif
+
+#if defined(__cplusplus) && !defined(String)
+#include
+using String = std::string;
+#endif
+
+#ifndef F
+#define F(x) (x)
+#endif
+
+#ifndef PSTR
+#define PSTR(x) x
+#endif
+
+#ifndef PROGMEM
+#define PROGMEM
+#endif
+#endif
+
/* Includes */
#ifdef WINDOWS
#include "winsock2.h"
@@ -232,6 +289,10 @@ static WiFiSpiClass WiFi;
#endif
#endif // HASP_USE_WIFI
+#if HASP_USE_WIREGUARD > 0
+#include "sys/net/hasp_wireguard.h"
+#endif
+
#if HASP_USE_ETHERNET > 0
#if defined(ARDUINO_ARCH_ESP32)
#include "sys/net/hasp_ethernet_esp32.h"
@@ -273,7 +334,7 @@ static WiFiSpiClass WiFi;
#if HASP_USE_MQTT > 0
#include "mqtt/hasp_mqtt.h"
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
#define HASP_USE_PAHO
#else
#define HASP_USE_ESP_MQTT
@@ -318,52 +379,27 @@ static WiFiSpiClass WiFi;
#include "sys/svc/hasp_slave.h"
#endif
-#ifndef HASP_ATTRIBUTE_FAST_MEM
-#define HASP_ATTRIBUTE_FAST_MEM
-#endif
-
-#ifndef IRAM_ATTR
-#define IRAM_ATTR
-#endif
-
-#ifndef FPSTR
-#define FPSTR(pstr_pointer) (reinterpret_cast(pstr_pointer))
-#endif
-
-#ifndef PGM_P
-#define PGM_P const char*
-#endif
-
-#if defined(WINDOWS) || defined(POSIX)
-#ifndef __FlashStringHelper
-#define __FlashStringHelper char
-#endif
-
-#ifndef F
-#define F(x) (x)
-#endif
-
-#ifndef PSTR
-#define PSTR(x) x
-#endif
-
-#ifndef PROGMEM
-#define PROGMEM
-#endif
-#endif
-
#if defined(WINDOWS)
#include
#define delay Sleep
#endif
+
#if defined(POSIX)
+#ifdef USE_MONITOR
#define delay SDL_Delay
+#else
+#define delay msleep
#endif
-#if defined(WINDOWS) || defined(POSIX)
+#endif
+
+#if HASP_TARGET_PC
#include
#include
#include
+
+#if USE_MONITOR
#include
+#endif
#define snprintf_P snprintf
#define memcpy_P memcpy
@@ -372,7 +408,13 @@ static WiFiSpiClass WiFi;
#define strcpy_P strcpy
#define strstr_P strstr
#define halRestartMcu()
+#if USE_MONITOR
#define millis SDL_GetTicks
+#elif defined(WINDOWS)
+#define millis Win32Millis
+#elif defined(POSIX)
+#define millis PosixMillis
+#endif
#define DEC 10
#define HEX 16
diff --git a/include/hasp_macro.h b/include/hasp_macro.h
index f1f937b9..44b6ed8b 100644
--- a/include/hasp_macro.h
+++ b/include/hasp_macro.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_MACRO_H
@@ -12,15 +12,15 @@
#include "user_config_override.h"
#endif
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
#define HASP_RANDOM(x) rand() % x
-#elif defined(ARDUINO)
+#elif HASP_TARGET_ARDUINO
#define HASP_RANDOM(x) random(x)
#else
#define HASP_RANDOM(x) random() % x
#endif
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
#define LOG_OUTPUT(x, ...) printf(__VA_ARGS__)
#else
diff --git a/include/hasp_mem.h b/include/hasp_mem.h
index 7b5223c8..31d0705e 100644
--- a/include/hasp_mem.h
+++ b/include/hasp_mem.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_MEM_H
diff --git a/include/lv_conf_v7.h b/include/lv_conf_v7.h
index 0b094c3f..e2adf67e 100644
--- a/include/lv_conf_v7.h
+++ b/include/lv_conf_v7.h
@@ -227,7 +227,9 @@ typedef void* lv_fs_drv_user_data_t;
//# define LV_FS_IF_SPIFFS '\0' // no internal esp Flash
#endif
#endif /*LV_USE_FS_IF*/
+#if HASP_TARGET_ARDUINO
#define LV_FS_PC_PATH "/littlefs"
+#endif
#endif
diff --git a/include/lv_drv_conf.h b/include/lv_drv_conf.h
index cb5bd603..3afc0d92 100644
--- a/include/lv_drv_conf.h
+++ b/include/lv_drv_conf.h
@@ -125,7 +125,11 @@
#define USE_WINDOWS 0
#endif
-#if USE_WINDOWS
+#ifndef USE_WIN32DRV
+#define USE_WINDOWS 0
+#endif
+
+#if USE_WINDOWS || USE_WIN32DRV
#define WINDOW_HOR_RES 480
#define WINDOW_VER_RES 320
#endif
diff --git a/include/lv_symbol_mdi_def.h b/include/lv_symbol_mdi_def.h
index 23c8e3e6..9ee037a5 100644
--- a/include/lv_symbol_mdi_def.h
+++ b/include/lv_symbol_mdi_def.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef LV_SYMBOL_MDI_DEF_H
diff --git a/include/stm32f4/hal_conf_custom.h b/include/stm32f4/hal_conf_custom.h
index c6d8ba32..193ca5a1 100644
--- a/include/stm32f4/hal_conf_custom.h
+++ b/include/stm32f4/hal_conf_custom.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/* Include the normal default core configuration */
diff --git a/include/user_config_override-template.h b/include/user_config_override-template.h
index 83f4e3a3..2d6c97c7 100644
--- a/include/user_config_override-template.h
+++ b/include/user_config_override-template.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/***************************************************
diff --git a/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RGB_Display_mod.h b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RGB_Display_mod.h
index 982da439..ae343534 100644
--- a/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RGB_Display_mod.h
+++ b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RGB_Display_mod.h
@@ -11,6 +11,125 @@
#include "Arduino_GFX.h"
#include "Arduino_RGBPanel_mod.h"
+static const uint8_t st7701_4848S040_init_operations[] = {
+ BEGIN_WRITE,
+ WRITE_COMMAND_8, 0xFF,
+ WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10,
+
+ WRITE_C8_D16, 0xC0, 0x3B, 0x00,
+ WRITE_C8_D16, 0xC1, 0x0D, 0x02,
+ WRITE_C8_D16, 0xC2, 0x31, 0x05,
+ WRITE_C8_D8, 0xCD, 0x00,//0x08
+
+ WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control
+ WRITE_BYTES, 16,
+ 0x00, 0x11, 0x18, 0x0E,
+ 0x11, 0x06, 0x07, 0x08,
+ 0x07, 0x22, 0x04, 0x12,
+ 0x0F, 0xAA, 0x31, 0x18,
+
+ WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control
+ WRITE_BYTES, 16,
+ 0x00, 0x11, 0x19, 0x0E,
+ 0x12, 0x07, 0x08, 0x08,
+ 0x08, 0x22, 0x04, 0x11,
+ 0x11, 0xA9, 0x32, 0x18,
+
+ // PAGE1
+ WRITE_COMMAND_8, 0xFF,
+ WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11,
+
+ WRITE_C8_D8, 0xB0, 0x60, // Vop=4.7375v
+ WRITE_C8_D8, 0xB1, 0x32, // VCOM=32
+ WRITE_C8_D8, 0xB2, 0x07, // VGH=15v
+ WRITE_C8_D8, 0xB3, 0x80,
+ WRITE_C8_D8, 0xB5, 0x49, // VGL=-10.17v
+ WRITE_C8_D8, 0xB7, 0x85,
+ WRITE_C8_D8, 0xB8, 0x21, // AVDD=6.6 & AVCL=-4.6
+ WRITE_C8_D8, 0xC1, 0x78,
+ WRITE_C8_D8, 0xC2, 0x78,
+
+ WRITE_COMMAND_8, 0xE0,
+ WRITE_BYTES, 3, 0x00, 0x1B, 0x02,
+
+ WRITE_COMMAND_8, 0xE1,
+ WRITE_BYTES, 11,
+ 0x08, 0xA0, 0x00, 0x00,
+ 0x07, 0xA0, 0x00, 0x00,
+ 0x00, 0x44, 0x44,
+
+ WRITE_COMMAND_8, 0xE2,
+ WRITE_BYTES, 12,
+ 0x11, 0x11, 0x44, 0x44,
+ 0xED, 0xA0, 0x00, 0x00,
+ 0xEC, 0xA0, 0x00, 0x00,
+
+ WRITE_COMMAND_8, 0xE3,
+ WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11,
+
+ WRITE_C8_D16, 0xE4, 0x44, 0x44,
+
+ WRITE_COMMAND_8, 0xE5,
+ WRITE_BYTES, 16,
+ 0x0A, 0xE9, 0xD8, 0xA0,
+ 0x0C, 0xEB, 0xD8, 0xA0,
+ 0x0E, 0xED, 0xD8, 0xA0,
+ 0x10, 0xEF, 0xD8, 0xA0,
+
+ WRITE_COMMAND_8, 0xE6,
+ WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11,
+
+ WRITE_C8_D16, 0xE7, 0x44, 0x44,
+
+ WRITE_COMMAND_8, 0xE8,
+ WRITE_BYTES, 16,
+ 0x09, 0xE8, 0xD8, 0xA0,
+ 0x0B, 0xEA, 0xD8, 0xA0,
+ 0x0D, 0xEC, 0xD8, 0xA0,
+ 0x0F, 0xEE, 0xD8, 0xA0,
+
+ WRITE_COMMAND_8, 0xEB,
+ WRITE_BYTES, 7,
+ 0x02, 0x00, 0xE4, 0xE4,
+ 0x88, 0x00, 0x40,
+
+ WRITE_C8_D16, 0xEC, 0x3C, 0x00,
+
+ WRITE_COMMAND_8, 0xED,
+ WRITE_BYTES, 16,
+ 0xAB, 0x89, 0x76, 0x54,
+ 0x02, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x20,
+ 0x45, 0x67, 0x98, 0xBA,
+
+ //-----------VAP & VAN---------------
+ WRITE_COMMAND_8, 0xFF,
+ WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13,
+
+ WRITE_C8_D8, 0xE5, 0xE4,
+
+ WRITE_COMMAND_8, 0xFF,
+ WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00,
+
+ WRITE_COMMAND_8, 0x21, // 0x20 normal, 0x21 IPS
+ WRITE_C8_D8, 0x3A, 0x60, // 0x70 RGB888, 0x60 RGB666, 0x50 RGB565
+
+ //WRITE_COMMAND_8, 0x21,0X00,
+ //END_WRITE,
+
+ WRITE_COMMAND_8, 0x11, // Sleep Out
+ END_WRITE,
+
+ DELAY, 120,
+
+ BEGIN_WRITE,
+ WRITE_COMMAND_8, 0x29, // Display On
+ END_WRITE,
+
+ BEGIN_WRITE,
+ WRITE_COMMAND_8, 0x20, // Invert display
+ END_WRITE
+};
static const uint8_t st7701_sensecap_indicator_init_operations[] = {
BEGIN_WRITE,
diff --git a/lib/WireGuard-ESP32/.gitignore b/lib/WireGuard-ESP32/.gitignore
new file mode 100644
index 00000000..c07a74de
--- /dev/null
+++ b/lib/WireGuard-ESP32/.gitignore
@@ -0,0 +1 @@
+build.sh
\ No newline at end of file
diff --git a/lib/WireGuard-ESP32/LICENSE b/lib/WireGuard-ESP32/LICENSE
new file mode 100644
index 00000000..3856ceb1
--- /dev/null
+++ b/lib/WireGuard-ESP32/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2021 Kenta Ida (fuga@fugafuga.org)
+Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+* Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ its contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Author: Daniel Hope
+
diff --git a/lib/WireGuard-ESP32/README.md b/lib/WireGuard-ESP32/README.md
new file mode 100644
index 00000000..25424faa
--- /dev/null
+++ b/lib/WireGuard-ESP32/README.md
@@ -0,0 +1,57 @@
+# WireGuard Implementation for ESP32 Arduino
+
+This is an implementation of the [WireGuard®](https://www.wireguard.com/) for ESP32 Arduino.
+
+Almost all of this code is based on the [WireGuard Implementation for lwIP](https://github.com/smartalock/wireguard-lwip), but some potion of the code is adjusted to build with ESP32 Arduino.
+
+## How to use
+
+1. Include `WireGuard-ESP32.h` at the early part of the sketch.
+
+```c++
+#include
+```
+
+2. Define the instance of the `WireGuard` class at module level.
+
+```c++
+static WireGuard wg;
+```
+
+3. Connect to WiFi AP by using `WiFi` class.
+
+```c++
+WiFi.begin(ssid, password);
+while( !WiFi.isConnected() ) {
+ delay(1000);
+}
+```
+
+4. Sync the system time via NTP.
+
+```c++
+configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com");
+```
+
+5. Start the WireGuard interface.
+
+```c++
+wg.begin(
+ local_ip, // IP address of the local interface
+ private_key, // Private key of the local interface
+ endpoint_address, // Address of the endpoint peer.
+ public_key, // Public key of the endpoint peer.
+ endpoint_port); // Port pf the endpoint peer.
+```
+
+You can see an example sketch `uptime_post.ino`, which connects SORACOM Arc WireGuard endpoint and post uptime to SORACOM Harvest via WireGuard connection.
+
+## License
+
+The original WireGuard implementation for lwIP is licensed under BSD 3 clause license so the code in this repository also licensed under the same license.
+
+Original license is below:
+
+The code is copyrighted under BSD 3 clause Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+
+See LICENSE for details
diff --git a/lib/WireGuard-ESP32/library.properties b/lib/WireGuard-ESP32/library.properties
new file mode 100644
index 00000000..d51576d6
--- /dev/null
+++ b/lib/WireGuard-ESP32/library.properties
@@ -0,0 +1,10 @@
+name=WireGuard-ESP32
+version=0.1.5
+author=Kenta Ida
+maintainer=Kenta Ida
+sentence=WireGuard implementation for Arduino ESP32
+paragraph=
+category=Communication
+url=https://github.com/ciniml/WireGuard-ESP32-Arduino
+includes=WireGuard-ESP32.h
+architectures=esp32,Inkplate
diff --git a/lib/WireGuard-ESP32/src/WireGuard-ESP32.h b/lib/WireGuard-ESP32/src/WireGuard-ESP32.h
new file mode 100644
index 00000000..b30c884a
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/WireGuard-ESP32.h
@@ -0,0 +1,17 @@
+/*
+ * WireGuard implementation for ESP32 Arduino by Kenta Ida (fuga@fugafuga.org)
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#pragma once
+#include
+
+class WireGuard
+{
+private:
+ bool _is_initialized = false;
+public:
+ bool begin(const IPAddress& localIP, const IPAddress& Subnet, const IPAddress& Gateway, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort);
+ bool begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort);
+ void end();
+ bool is_initialized() const { return this->_is_initialized; }
+};
diff --git a/lib/WireGuard-ESP32/src/WireGuard.cpp b/lib/WireGuard-ESP32/src/WireGuard.cpp
new file mode 100644
index 00000000..ce69650e
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/WireGuard.cpp
@@ -0,0 +1,147 @@
+/*
+ * WireGuard implementation for ESP32 Arduino by Kenta Ida (fuga@fugafuga.org)
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "WireGuard-ESP32.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+
+#include "lwip/err.h"
+#include "lwip/sys.h"
+#include "lwip/ip.h"
+#include "lwip/netdb.h"
+
+#include "esp32-hal-log.h"
+
+extern "C" {
+#include "wireguardif.h"
+#include "wireguard-platform.h"
+}
+
+// Wireguard instance
+static struct netif wg_netif_struct = {0};
+static struct netif *wg_netif = NULL;
+static struct netif *previous_default_netif = NULL;
+static uint8_t wireguard_peer_index = WIREGUARDIF_INVALID_INDEX;
+
+#define TAG "[WireGuard] "
+
+bool WireGuard::begin(const IPAddress& localIP, const IPAddress& Subnet, const IPAddress& Gateway, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) {
+ struct wireguardif_init_data wg;
+ struct wireguardif_peer peer;
+ ip_addr_t ipaddr = IPADDR4_INIT(static_cast(localIP));
+ ip_addr_t netmask = IPADDR4_INIT(static_cast(Subnet));
+ ip_addr_t gateway = IPADDR4_INIT(static_cast(Gateway));
+
+ assert(privateKey != NULL);
+ assert(remotePeerAddress != NULL);
+ assert(remotePeerPublicKey != NULL);
+ assert(remotePeerPort != 0);
+
+ // Setup the WireGuard device structure
+ wg.private_key = privateKey;
+ wg.listen_port = remotePeerPort;
+
+ wg.bind_netif = NULL;
+
+ // Initialise the first WireGuard peer structure
+ wireguardif_peer_init(&peer);
+ // If we know the endpoint's address can add here
+ bool success_get_endpoint_ip = false;
+ for(int retry = 0; retry < 5; retry++) {
+ ip_addr_t endpoint_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0);
+ struct addrinfo *res = NULL;
+ struct addrinfo hint;
+ memset(&hint, 0, sizeof(hint));
+ memset(&endpoint_ip, 0, sizeof(endpoint_ip));
+ if( lwip_getaddrinfo(remotePeerAddress, NULL, &hint, &res) != 0 ) {
+ vTaskDelay(pdMS_TO_TICKS(2000));
+ continue;
+ }
+ success_get_endpoint_ip = true;
+ struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
+ inet_addr_to_ip4addr(ip_2_ip4(&endpoint_ip), &addr4);
+ lwip_freeaddrinfo(res);
+
+ peer.endpoint_ip = endpoint_ip;
+ log_i(TAG "%s is %3d.%3d.%3d.%3d"
+ , remotePeerAddress
+ , (endpoint_ip.u_addr.ip4.addr >> 0) & 0xff
+ , (endpoint_ip.u_addr.ip4.addr >> 8) & 0xff
+ , (endpoint_ip.u_addr.ip4.addr >> 16) & 0xff
+ , (endpoint_ip.u_addr.ip4.addr >> 24) & 0xff
+ );
+ break;
+ }
+ if( !success_get_endpoint_ip ) {
+ log_e(TAG "failed to get endpoint ip.");
+ return false;
+ }
+ // Register the new WireGuard network interface with lwIP
+ wg_netif = netif_add(&wg_netif_struct, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gateway), &wg, &wireguardif_init, &ip_input);
+ if( wg_netif == nullptr ) {
+ log_e(TAG "failed to initialize WG netif.");
+ return false;
+ }
+ // Mark the interface as administratively up, link up flag is set automatically when peer connects
+ netif_set_up(wg_netif);
+
+ peer.public_key = remotePeerPublicKey;
+ peer.preshared_key = NULL;
+ // Allow all IPs through tunnel
+ {
+ ip_addr_t allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0);
+ peer.allowed_ip = allowed_ip;
+ ip_addr_t allowed_mask = IPADDR4_INIT_BYTES(0, 0, 0, 0);
+ peer.allowed_mask = allowed_mask;
+ }
+
+ peer.endport_port = remotePeerPort;
+
+ // Initialize the platform
+ wireguard_platform_init();
+ // Register the new WireGuard peer with the netwok interface
+ wireguardif_add_peer(wg_netif, &peer, &wireguard_peer_index);
+ if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) {
+ // Start outbound connection to peer
+ log_i(TAG "connecting wireguard...");
+ wireguardif_connect(wg_netif, wireguard_peer_index);
+ // Save the current default interface for restoring when shutting down the WG interface.
+ previous_default_netif = netif_default;
+ // Set default interface to WG device.
+ netif_set_default(wg_netif);
+ }
+
+ this->_is_initialized = true;
+ return true;
+}
+
+bool WireGuard::begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) {
+ // Maintain compatiblity with old begin
+ auto subnet = IPAddress(255,255,255,255);
+ auto gateway = IPAddress(0,0,0,0);
+ return WireGuard::begin(localIP, subnet, gateway, privateKey, remotePeerAddress, remotePeerPublicKey, remotePeerPort);
+}
+
+void WireGuard::end() {
+ if( !this->_is_initialized ) return;
+
+ // Restore the default interface.
+ netif_set_default(previous_default_netif);
+ previous_default_netif = nullptr;
+ // Disconnect the WG interface.
+ wireguardif_disconnect(wg_netif, wireguard_peer_index);
+ // Remove peer from the WG interface
+ wireguardif_remove_peer(wg_netif, wireguard_peer_index);
+ wireguard_peer_index = WIREGUARDIF_INVALID_INDEX;
+ // Shutdown the wireguard interface.
+ wireguardif_shutdown(wg_netif);
+ // Remove the WG interface;
+ netif_remove(wg_netif);
+ wg_netif = nullptr;
+
+ this->_is_initialized = false;
+}
\ No newline at end of file
diff --git a/lib/WireGuard-ESP32/src/crypto.c b/lib/WireGuard-ESP32/src/crypto.c
new file mode 100644
index 00000000..3597b86b
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto.c
@@ -0,0 +1,23 @@
+#include "crypto.h"
+
+#include
+#include
+#include
+
+void crypto_zero(void *dest, size_t len) {
+ volatile uint8_t *p = (uint8_t *)dest;
+ while (len--) {
+ *p++ = 0;
+ }
+}
+
+bool crypto_equal(const void *a, const void *b, size_t size) {
+ uint8_t neq = 0;
+ while (size > 0) {
+ neq |= *(uint8_t *)a ^ *(uint8_t *)b;
+ a += 1;
+ b += 1;
+ size -= 1;
+ }
+ return (neq) ? false : true;
+}
diff --git a/lib/WireGuard-ESP32/src/crypto.h b/lib/WireGuard-ESP32/src/crypto.h
new file mode 100644
index 00000000..c5d640d5
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto.h
@@ -0,0 +1,102 @@
+#ifndef _CRYPTO_H_
+#define _CRYPTO_H_
+
+#include
+#include
+#include
+
+// BLAKE2S IMPLEMENTATION
+#include "crypto/refc/blake2s.h"
+#define wireguard_blake2s_ctx blake2s_ctx
+#define wireguard_blake2s_init(ctx,outlen,key,keylen) blake2s_init(ctx,outlen,key,keylen)
+#define wireguard_blake2s_update(ctx,in,inlen) blake2s_update(ctx,in,inlen)
+#define wireguard_blake2s_final(ctx,out) blake2s_final(ctx,out)
+#define wireguard_blake2s(out,outlen,key,keylen,in,inlen) blake2s(out,outlen,key,keylen,in,inlen)
+
+// X25519 IMPLEMENTATION
+#include "crypto/refc/x25519.h"
+#define wireguard_x25519(a,b,c) x25519(a,b,c,1)
+
+// CHACHA20POLY1305 IMPLEMENTATION
+#include "crypto/refc/chacha20poly1305.h"
+#define wireguard_aead_encrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key)
+#define wireguard_aead_decrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key)
+#define wireguard_xaead_encrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key)
+#define wireguard_xaead_decrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key)
+
+
+// Endian / unaligned helper macros
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((uint8_t)(v) & U8C(0xFF))
+#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF))
+
+#define U8TO32_LITTLE(p) \
+ (((uint32_t)((p)[0]) ) | \
+ ((uint32_t)((p)[1]) << 8) | \
+ ((uint32_t)((p)[2]) << 16) | \
+ ((uint32_t)((p)[3]) << 24))
+
+#define U8TO64_LITTLE(p) \
+ (((uint64_t)((p)[0]) ) | \
+ ((uint64_t)((p)[1]) << 8) | \
+ ((uint64_t)((p)[2]) << 16) | \
+ ((uint64_t)((p)[3]) << 24) | \
+ ((uint64_t)((p)[4]) << 32) | \
+ ((uint64_t)((p)[5]) << 40) | \
+ ((uint64_t)((p)[6]) << 48) | \
+ ((uint64_t)((p)[7]) << 56))
+
+#define U16TO8_BIG(p, v) \
+ do { \
+ (p)[1] = U8V((v) ); \
+ (p)[0] = U8V((v) >> 8); \
+ } while (0)
+
+#define U32TO8_LITTLE(p, v) \
+ do { \
+ (p)[0] = U8V((v) ); \
+ (p)[1] = U8V((v) >> 8); \
+ (p)[2] = U8V((v) >> 16); \
+ (p)[3] = U8V((v) >> 24); \
+ } while (0)
+
+#define U32TO8_BIG(p, v) \
+ do { \
+ (p)[3] = U8V((v) ); \
+ (p)[2] = U8V((v) >> 8); \
+ (p)[1] = U8V((v) >> 16); \
+ (p)[0] = U8V((v) >> 24); \
+ } while (0)
+
+#define U64TO8_LITTLE(p, v) \
+ do { \
+ (p)[0] = U8V((v) ); \
+ (p)[1] = U8V((v) >> 8); \
+ (p)[2] = U8V((v) >> 16); \
+ (p)[3] = U8V((v) >> 24); \
+ (p)[4] = U8V((v) >> 32); \
+ (p)[5] = U8V((v) >> 40); \
+ (p)[6] = U8V((v) >> 48); \
+ (p)[7] = U8V((v) >> 56); \
+} while (0)
+
+#define U64TO8_BIG(p, v) \
+ do { \
+ (p)[7] = U8V((v) ); \
+ (p)[6] = U8V((v) >> 8); \
+ (p)[5] = U8V((v) >> 16); \
+ (p)[4] = U8V((v) >> 24); \
+ (p)[3] = U8V((v) >> 32); \
+ (p)[2] = U8V((v) >> 40); \
+ (p)[1] = U8V((v) >> 48); \
+ (p)[0] = U8V((v) >> 56); \
+} while (0)
+
+
+void crypto_zero(void *dest, size_t len);
+bool crypto_equal(const void *a, const void *b, size_t size);
+
+#endif /* _CRYPTO_H_ */
+
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/blake2s.c b/lib/WireGuard-ESP32/src/crypto/refc/blake2s.c
new file mode 100644
index 00000000..ae5e14ca
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/blake2s.c
@@ -0,0 +1,156 @@
+// Taken from RFC7693 - https://tools.ietf.org/html/rfc7693
+
+#include "blake2s.h"
+#include "../../crypto.h"
+
+// Cyclic right rotation.
+
+#ifndef ROTR32
+#define ROTR32(x, y) (((x) >> (y)) ^ ((x) << (32 - (y))))
+#endif
+
+// Mixing function G.
+#define B2S_G(a, b, c, d, x, y) { \
+ v[a] = v[a] + v[b] + x; \
+ v[d] = ROTR32(v[d] ^ v[a], 16); \
+ v[c] = v[c] + v[d]; \
+ v[b] = ROTR32(v[b] ^ v[c], 12); \
+ v[a] = v[a] + v[b] + y; \
+ v[d] = ROTR32(v[d] ^ v[a], 8); \
+ v[c] = v[c] + v[d]; \
+ v[b] = ROTR32(v[b] ^ v[c], 7); }
+
+// Initialization Vector.
+static const uint32_t blake2s_iv[8] =
+{
+ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+ 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
+};
+
+// Compression function. "last" flag indicates last block.
+static void blake2s_compress(blake2s_ctx *ctx, int last)
+{
+ const uint8_t sigma[10][16] = {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }
+ };
+ int i;
+ uint32_t v[16], m[16];
+
+ for (i = 0; i < 8; i++) { // init work variables
+ v[i] = ctx->h[i];
+ v[i + 8] = blake2s_iv[i];
+ }
+
+ v[12] ^= ctx->t[0]; // low 32 bits of offset
+ v[13] ^= ctx->t[1]; // high 32 bits
+ if (last) // last block flag set ?
+ v[14] = ~v[14];
+ for (i = 0; i < 16; i++) // get little-endian words
+ m[i] = U8TO32_LITTLE(&ctx->b[4 * i]);
+
+ for (i = 0; i < 10; i++) { // ten rounds
+ B2S_G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]);
+ B2S_G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]);
+ B2S_G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]);
+ B2S_G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]);
+ B2S_G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]);
+ B2S_G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]);
+ B2S_G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]);
+ B2S_G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]);
+ }
+
+ for( i = 0; i < 8; ++i )
+ ctx->h[i] ^= v[i] ^ v[i + 8];
+}
+
+// Initialize the hashing context "ctx" with optional key "key".
+// 1 <= outlen <= 32 gives the digest size in bytes.
+// Secret key (also <= 32 bytes) is optional (keylen = 0).
+int blake2s_init(blake2s_ctx *ctx, size_t outlen,
+ const void *key, size_t keylen) // (keylen=0: no key)
+{
+ size_t i;
+
+ if (outlen == 0 || outlen > 32 || keylen > 32)
+ return -1; // illegal parameters
+
+ for (i = 0; i < 8; i++) // state, "param block"
+ ctx->h[i] = blake2s_iv[i];
+ ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen;
+
+ ctx->t[0] = 0; // input count low word
+ ctx->t[1] = 0; // input count high word
+ ctx->c = 0; // pointer within buffer
+ ctx->outlen = outlen;
+
+ for (i = keylen; i < 64; i++) // zero input block
+ ctx->b[i] = 0;
+ if (keylen > 0) {
+ blake2s_update(ctx, key, keylen);
+ ctx->c = 64; // at the end
+ }
+
+ return 0;
+}
+
+// Add "inlen" bytes from "in" into the hash.
+void blake2s_update(blake2s_ctx *ctx,
+ const void *in, size_t inlen) // data bytes
+{
+ size_t i;
+
+ for (i = 0; i < inlen; i++) {
+ if (ctx->c == 64) { // buffer full ?
+ ctx->t[0] += ctx->c; // add counters
+ if (ctx->t[0] < ctx->c) // carry overflow ?
+ ctx->t[1]++; // high word
+ blake2s_compress(ctx, 0); // compress (not last)
+ ctx->c = 0; // counter to zero
+ }
+ ctx->b[ctx->c++] = ((const uint8_t *) in)[i];
+ }
+}
+
+// Generate the message digest (size given in init).
+// Result placed in "out".
+void blake2s_final(blake2s_ctx *ctx, void *out)
+{
+ size_t i;
+
+ ctx->t[0] += ctx->c; // mark last block offset
+ if (ctx->t[0] < ctx->c) // carry overflow
+ ctx->t[1]++; // high word
+
+ while (ctx->c < 64) // fill up with zeros
+ ctx->b[ctx->c++] = 0;
+ blake2s_compress(ctx, 1); // final block flag = 1
+
+ // little endian convert and store
+ for (i = 0; i < ctx->outlen; i++) {
+ ((uint8_t *) out)[i] =
+ (ctx->h[i >> 2] >> (8 * (i & 3))) & 0xFF;
+ }
+}
+
+// Convenience function for all-in-one computation.
+int blake2s(void *out, size_t outlen,
+ const void *key, size_t keylen,
+ const void *in, size_t inlen)
+{
+ blake2s_ctx ctx;
+ if (blake2s_init(&ctx, outlen, key, keylen))
+ return -1;
+ blake2s_update(&ctx, in, inlen);
+ blake2s_final(&ctx, out);
+
+ return 0;
+}
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/blake2s.h b/lib/WireGuard-ESP32/src/crypto/refc/blake2s.h
new file mode 100644
index 00000000..4b056467
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/blake2s.h
@@ -0,0 +1,39 @@
+// Taken from RFC7693 - https://tools.ietf.org/html/rfc7693
+// BLAKE2s Hashing Context and API Prototypes
+#ifndef _BLAKE2S_H
+#define _BLAKE2S_H
+
+#define BLAKE2S_BLOCK_SIZE 64
+
+#include
+#include
+
+// state context
+typedef struct {
+ uint8_t b[64]; // input buffer
+ uint32_t h[8]; // chained state
+ uint32_t t[2]; // total number of bytes
+ size_t c; // pointer for b[]
+ size_t outlen; // digest size
+} blake2s_ctx;
+
+// Initialize the hashing context "ctx" with optional key "key".
+// 1 <= outlen <= 32 gives the digest size in bytes.
+// Secret key (also <= 32 bytes) is optional (keylen = 0).
+int blake2s_init(blake2s_ctx *ctx, size_t outlen,
+ const void *key, size_t keylen); // secret key
+
+// Add "inlen" bytes from "in" into the hash.
+void blake2s_update(blake2s_ctx *ctx, // context
+ const void *in, size_t inlen); // data to be hashed
+
+// Generate the message digest (size given in init).
+// Result placed in "out".
+void blake2s_final(blake2s_ctx *ctx, void *out);
+
+// All-in-one convenience function.
+int blake2s(void *out, size_t outlen, // return buffer for digest
+ const void *key, size_t keylen, // optional secret key
+ const void *in, size_t inlen); // data to be hashed
+
+#endif
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20.c b/lib/WireGuard-ESP32/src/crypto/refc/chacha20.c
new file mode 100644
index 00000000..52c4dd6e
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/chacha20.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+// RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard
+// https://tools.ietf.org/html/rfc7539
+// Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain)
+// HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
+
+#include "chacha20.h"
+
+#include
+#include
+#include "../../crypto.h"
+
+// 2.3. The ChaCha20 Block Function
+// The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+static const uint32_t CHACHA20_CONSTANT_1 = 0x61707865;
+static const uint32_t CHACHA20_CONSTANT_2 = 0x3320646e;
+static const uint32_t CHACHA20_CONSTANT_3 = 0x79622d32;
+static const uint32_t CHACHA20_CONSTANT_4 = 0x6b206574;
+
+#define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+// 2.1. The ChaCha Quarter Round
+// 1. a += b; d ^= a; d <<<= 16;
+// 2. c += d; b ^= c; b <<<= 12;
+// 3. a += b; d ^= a; d <<<= 8;
+// 4. c += d; b ^= c; b <<<= 7;
+
+#define QUARTERROUND(a, b, c, d) \
+ a += b; d ^= a; d = ROTL32(d, 16); \
+ c += d; b ^= c; b = ROTL32(b, 12); \
+ a += b; d ^= a; d = ROTL32(d, 8); \
+ c += d; b ^= c; b = ROTL32(b, 7)
+
+static inline void INNER_BLOCK(uint32_t *block) {
+ QUARTERROUND(block[0], block[4], block[ 8], block[12]); // column 0
+ QUARTERROUND(block[1], block[5], block[ 9], block[13]); // column 1
+ QUARTERROUND(block[2], block[6], block[10], block[14]); // column 2
+ QUARTERROUND(block[3], block[7], block[11], block[15]); // column 3
+ QUARTERROUND(block[0], block[5], block[10], block[15]); // diagonal 1
+ QUARTERROUND(block[1], block[6], block[11], block[12]); // diagonal 2
+ QUARTERROUND(block[2], block[7], block[ 8], block[13]); // diagonal 3
+ QUARTERROUND(block[3], block[4], block[ 9], block[14]); // diagonal 4
+}
+
+#define TWENTY_ROUNDS(x) ( \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x), \
+ INNER_BLOCK(x) \
+)
+
+// 2.3. The ChaCha20 Block Function
+// chacha20_block(key, counter, nonce):
+// state = constants | key | counter | nonce
+// working_state = state
+// for i=1 upto 10
+// inner_block(working_state)
+// end
+// state += working_state
+// return serialize(state)
+// end
+static void chacha20_block(struct chacha20_ctx *ctx, uint8_t *stream) {
+ uint32_t working_state[16];
+ int i;
+
+ for (i = 0; i < 16; ++i) {
+ working_state[i] = ctx->state[i];
+ }
+
+ TWENTY_ROUNDS(working_state);
+
+ for (i = 0; i < 16; ++i) {
+ U32TO8_LITTLE(stream + (4 * i), PLUS(working_state[i], ctx->state[i]));
+ }
+}
+
+void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len) {
+ uint8_t output[CHACHA20_BLOCK_SIZE];
+ int i;
+
+ if (len) {
+ for (;;) {
+ chacha20_block(ctx, output);
+ // Word 12 is a block counter
+ ctx->state[12] = PLUSONE(ctx->state[12]);
+ if (len <= 64) {
+ for (i = 0;i < len;++i) {
+ out[i] = in[i] ^ output[i];
+ }
+ return;
+ }
+ for (i = 0;i < 64;++i) {
+ out[i] = in[i] ^ output[i];
+ }
+ len -= 64;
+ out += 64;
+ in += 64;
+ }
+ }
+}
+
+
+// 2.3. The ChaCha20 Block Function
+// The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+// The next eight words (4-11) are taken from the 256-bit key by reading the bytes in little-endian order, in 4-byte chunks.
+// Word 12 is a block counter. Since each block is 64-byte, a 32-bit word is enough for 256 gigabytes of data.
+// Words 13-15 are a nonce, which should not be repeated for the same key.
+// For wireguard: "nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter." where counter comes from the Wireguard layer and is separate from the block counter in word 12
+void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce) {
+ ctx->state[0] = CHACHA20_CONSTANT_1;
+ ctx->state[1] = CHACHA20_CONSTANT_2;
+ ctx->state[2] = CHACHA20_CONSTANT_3;
+ ctx->state[3] = CHACHA20_CONSTANT_4;
+ ctx->state[4] = U8TO32_LITTLE(key + 0);
+ ctx->state[5] = U8TO32_LITTLE(key + 4);
+ ctx->state[6] = U8TO32_LITTLE(key + 8);
+ ctx->state[7] = U8TO32_LITTLE(key + 12);
+ ctx->state[8] = U8TO32_LITTLE(key + 16);
+ ctx->state[9] = U8TO32_LITTLE(key + 20);
+ ctx->state[10] = U8TO32_LITTLE(key + 24);
+ ctx->state[11] = U8TO32_LITTLE(key + 28);
+ ctx->state[12] = 0;
+ ctx->state[13] = 0;
+ ctx->state[14] = nonce & 0xFFFFFFFF;
+ ctx->state[15] = nonce >> 32;
+}
+
+// 2.2. HChaCha20
+// HChaCha20 is initialized the same way as the ChaCha cipher, except that HChaCha20 uses a 128-bit nonce and has no counter.
+// After initialization, proceed through the ChaCha rounds as usual.
+// Once the 20 ChaCha rounds have been completed, the first 128 bits and last 128 bits of the ChaCha state (both little-endian) are concatenated, and this 256-bit subkey is returned.
+void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key) {
+ uint32_t state[16];
+ state[0] = CHACHA20_CONSTANT_1;
+ state[1] = CHACHA20_CONSTANT_2;
+ state[2] = CHACHA20_CONSTANT_3;
+ state[3] = CHACHA20_CONSTANT_4;
+ state[4] = U8TO32_LITTLE(key + 0);
+ state[5] = U8TO32_LITTLE(key + 4);
+ state[6] = U8TO32_LITTLE(key + 8);
+ state[7] = U8TO32_LITTLE(key + 12);
+ state[8] = U8TO32_LITTLE(key + 16);
+ state[9] = U8TO32_LITTLE(key + 20);
+ state[10] = U8TO32_LITTLE(key + 24);
+ state[11] = U8TO32_LITTLE(key + 28);
+ state[12] = U8TO32_LITTLE(nonce + 0);
+ state[13] = U8TO32_LITTLE(nonce + 4);
+ state[14] = U8TO32_LITTLE(nonce + 8);
+ state[15] = U8TO32_LITTLE(nonce + 12);
+
+ TWENTY_ROUNDS(state);
+
+ // Concatenate first/last 128 bits into 256bit output (as little endian)
+ U32TO8_LITTLE(out + 0, state[0]);
+ U32TO8_LITTLE(out + 4, state[1]);
+ U32TO8_LITTLE(out + 8, state[2]);
+ U32TO8_LITTLE(out + 12, state[3]);
+ U32TO8_LITTLE(out + 16, state[12]);
+ U32TO8_LITTLE(out + 20, state[13]);
+ U32TO8_LITTLE(out + 24, state[14]);
+ U32TO8_LITTLE(out + 28, state[15]);
+}
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20.h b/lib/WireGuard-ESP32/src/crypto/refc/chacha20.h
new file mode 100644
index 00000000..aaa80222
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/chacha20.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+// RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard
+// https://tools.ietf.org/html/rfc7539
+// Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain)
+// HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
+#ifndef _CHACHA20_H_
+#define _CHACHA20_H_
+
+#include
+
+#define CHACHA20_BLOCK_SIZE (64)
+#define CHACHA20_KEY_SIZE (32)
+
+struct chacha20_ctx {
+ uint32_t state[16];
+};
+
+void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce);
+void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len);
+void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key);
+
+#endif /* _CHACHA20_H_ */
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.c b/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.c
new file mode 100644
index 00000000..972e8b1c
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+// AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539
+// AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
+#include "chacha20poly1305.h"
+#include "chacha20.h"
+#include "poly1305-donna.h"
+
+#include
+#include
+#include "../../crypto.h"
+
+#define POLY1305_KEY_SIZE 32
+#define POLY1305_MAC_SIZE 16
+
+static const uint8_t zero[CHACHA20_BLOCK_SIZE] = { 0 };
+
+// 2.6. Generating the Poly1305 Key Using ChaCha20
+static void generate_poly1305_key(struct poly1305_context *poly1305_state, struct chacha20_ctx *chacha20_state, const uint8_t *key, uint64_t nonce) {
+ uint8_t block[POLY1305_KEY_SIZE] = {0};
+
+ // The method is to call the block function with the following parameters:
+ // - The 256-bit session integrity key is used as the ChaCha20 key.
+ // - The block counter is set to zero.
+ // - The protocol will specify a 96-bit or 64-bit nonce
+ chacha20_init(chacha20_state, key, nonce);
+
+ // We take the first 256 bits or the serialized state, and use those as the one-time Poly1305 key
+ chacha20(chacha20_state, block, block, sizeof(block));
+
+ poly1305_init(poly1305_state, block);
+
+ crypto_zero(&block, sizeof(block));
+}
+
+// 2.8. AEAD Construction (Encryption)
+void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) {
+ struct poly1305_context poly1305_state;
+ struct chacha20_ctx chacha20_state;
+ uint8_t block[8];
+ size_t padded_len;
+
+ // First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6.
+ generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce);
+
+ // Next, the ChaCha20 encryption function is called to encrypt the plaintext, using the same key and nonce, and with the initial counter set to 1.
+ chacha20(&chacha20_state, dst, src, src_len);
+
+ // Finally, the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following:
+ // - The AAD
+ poly1305_update(&poly1305_state, ad, ad_len);
+ // - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16
+ padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
+ poly1305_update(&poly1305_state, zero, padded_len - ad_len);
+ // - The ciphertext
+ poly1305_update(&poly1305_state, dst, src_len);
+ // - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16.
+ padded_len = (src_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
+ poly1305_update(&poly1305_state, zero, padded_len - src_len);
+ // - The length of the additional data in octets (as a 64-bit little-endian integer)
+ U64TO8_LITTLE(block, (uint64_t)ad_len);
+ poly1305_update(&poly1305_state, block, sizeof(block));
+ // - The length of the ciphertext in octets (as a 64-bit little-endian integer).
+ U64TO8_LITTLE(block, (uint64_t)src_len);
+ poly1305_update(&poly1305_state, block, sizeof(block));
+
+ // The output from the AEAD is twofold:
+ // - A ciphertext of the same length as the plaintext. (above, output of chacha20 into dst)
+ // - A 128-bit tag, which is the output of the Poly1305 function. (append to dst)
+ poly1305_finish(&poly1305_state, dst + src_len);
+
+ // Make sure we leave nothing sensitive on the stack
+ crypto_zero(&chacha20_state, sizeof(chacha20_state));
+ crypto_zero(&block, sizeof(block));
+}
+
+// 2.8. AEAD Construction (Decryption)
+bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) {
+ struct poly1305_context poly1305_state;
+ struct chacha20_ctx chacha20_state;
+ uint8_t block[8];
+ uint8_t mac[POLY1305_MAC_SIZE];
+ size_t padded_len;
+ int dst_len;
+ bool result = false;
+
+ // Decryption is similar [to encryption] with the following differences:
+ // - The roles of ciphertext and plaintext are reversed, so the ChaCha20 encryption function is applied to the ciphertext, producing the plaintext.
+ // - The Poly1305 function is still run on the AAD and the ciphertext, not the plaintext.
+ // - The calculated tag is bitwise compared to the received tag. The message is authenticated if and only if the tags match.
+
+ if (src_len >= POLY1305_MAC_SIZE) {
+ dst_len = src_len - POLY1305_MAC_SIZE;
+
+ // First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6.
+ generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce);
+
+ // Calculate the MAC before attempting decryption
+
+ // the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following:
+ // - The AAD
+ poly1305_update(&poly1305_state, ad, ad_len);
+ // - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16
+ padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
+ poly1305_update(&poly1305_state, zero, padded_len - ad_len);
+ // - The ciphertext (note the Poly1305 function is still run on the AAD and the ciphertext, not the plaintext)
+ poly1305_update(&poly1305_state, src, dst_len);
+ // - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16.
+ padded_len = (dst_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
+ poly1305_update(&poly1305_state, zero, padded_len - dst_len);
+ // - The length of the additional data in octets (as a 64-bit little-endian integer)
+ U64TO8_LITTLE(block, (uint64_t)ad_len);
+ poly1305_update(&poly1305_state, block, sizeof(block));
+ // - The length of the ciphertext in octets (as a 64-bit little-endian integer).
+ U64TO8_LITTLE(block, (uint64_t)dst_len);
+ poly1305_update(&poly1305_state, block, sizeof(block));
+
+ // The output from the AEAD is twofold:
+ // - A plaintext of the same length as the ciphertext. (below, output of chacha20 into dst)
+ // - A 128-bit tag, which is the output of the Poly1305 function. (into mac for checking against passed mac)
+ poly1305_finish(&poly1305_state, mac);
+
+
+ if (crypto_equal(mac, src + dst_len, POLY1305_MAC_SIZE)) {
+ // mac is correct - do the decryption
+ // Next, the ChaCha20 encryption function is called to decrypt the ciphertext, using the same key and nonce, and with the initial counter set to 1.
+ chacha20(&chacha20_state, dst, src, dst_len);
+ result = true;
+ }
+ }
+ return result;
+}
+
+// AEAD_XChaCha20_Poly1305
+// XChaCha20-Poly1305 is a variant of the ChaCha20-Poly1305 AEAD construction as defined in [RFC7539] that uses a 192-bit nonce instead of a 96-bit nonce.
+// The algorithm for XChaCha20-Poly1305 is as follows:
+// 1. Calculate a subkey from the first 16 bytes of the nonce and the key, using HChaCha20 (Section 2.2).
+// 2. Use the subkey and remaining 8 bytes of the nonce (prefixed with 4 NUL bytes) with AEAD_CHACHA20_POLY1305 from [RFC7539] as normal. The definition for XChaCha20 is given in Section 2.3.
+void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) {
+ uint8_t subkey[CHACHA20_KEY_SIZE];
+ uint64_t new_nonce;
+
+ new_nonce = U8TO64_LITTLE(nonce + 16);
+
+ hchacha20(subkey, nonce, key);
+ chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey);
+
+ crypto_zero(subkey, sizeof(subkey));
+}
+
+bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) {
+ uint8_t subkey[CHACHA20_KEY_SIZE];
+ uint64_t new_nonce;
+ bool result;
+
+ new_nonce = U8TO64_LITTLE(nonce + 16);
+
+ hchacha20(subkey, nonce, key);
+ result = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey);
+
+ crypto_zero(subkey, sizeof(subkey));
+ return result;
+}
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.h b/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.h
new file mode 100644
index 00000000..83fab072
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/chacha20poly1305.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+#ifndef _CHACHA20POLY1305_H_
+#define _CHACHA20POLY1305_H_
+
+#include
+#include
+#include
+
+// Aead(key, counter, plain text, auth text) ChaCha20Poly1305 AEAD, as specified in RFC7539 [17], with its nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter.
+// AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539
+void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key);
+bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key);
+
+// Xaead(key, nonce, plain text, auth text) XChaCha20Poly1305 AEAD, with a 24-byte random nonce, instantiated using HChaCha20 [6] and ChaCha20Poly1305.
+// AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
+void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key);
+bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key);
+
+#endif /* _CHACHA20POLY1305_H_ */
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna-32.h b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna-32.h
new file mode 100644
index 00000000..dbcec774
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna-32.h
@@ -0,0 +1,220 @@
+// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT
+/*
+ poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition
+*/
+
+#if defined(_MSC_VER)
+ #define POLY1305_NOINLINE __declspec(noinline)
+#elif defined(__GNUC__)
+ #define POLY1305_NOINLINE __attribute__((noinline))
+#else
+ #define POLY1305_NOINLINE
+#endif
+
+#define poly1305_block_size 16
+
+/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */
+typedef struct poly1305_state_internal_t {
+ unsigned long r[5];
+ unsigned long h[5];
+ unsigned long pad[4];
+ size_t leftover;
+ unsigned char buffer[poly1305_block_size];
+ unsigned char final;
+} poly1305_state_internal_t;
+
+/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
+static unsigned long
+U8TO32(const unsigned char *p) {
+ return
+ (((unsigned long)(p[0] & 0xff) ) |
+ ((unsigned long)(p[1] & 0xff) << 8) |
+ ((unsigned long)(p[2] & 0xff) << 16) |
+ ((unsigned long)(p[3] & 0xff) << 24));
+}
+
+/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
+static void
+U32TO8(unsigned char *p, unsigned long v) {
+ p[0] = (v ) & 0xff;
+ p[1] = (v >> 8) & 0xff;
+ p[2] = (v >> 16) & 0xff;
+ p[3] = (v >> 24) & 0xff;
+}
+
+void
+poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff;
+ st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03;
+ st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff;
+ st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff;
+ st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
+
+ /* h = 0 */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+ st->h[3] = 0;
+ st->h[4] = 0;
+
+ /* save pad for later */
+ st->pad[0] = U8TO32(&key[16]);
+ st->pad[1] = U8TO32(&key[20]);
+ st->pad[2] = U8TO32(&key[24]);
+ st->pad[3] = U8TO32(&key[28]);
+
+ st->leftover = 0;
+ st->final = 0;
+}
+
+static void
+poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
+ const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */
+ unsigned long r0,r1,r2,r3,r4;
+ unsigned long s1,s2,s3,s4;
+ unsigned long h0,h1,h2,h3,h4;
+ unsigned long long d0,d1,d2,d3,d4;
+ unsigned long c;
+
+ r0 = st->r[0];
+ r1 = st->r[1];
+ r2 = st->r[2];
+ r3 = st->r[3];
+ r4 = st->r[4];
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+ h3 = st->h[3];
+ h4 = st->h[4];
+
+ while (bytes >= poly1305_block_size) {
+ /* h += m[i] */
+ h0 += (U8TO32(m+ 0) ) & 0x3ffffff;
+ h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff;
+ h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff;
+ h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff;
+ h4 += (U8TO32(m+12) >> 8) | hibit;
+
+ /* h *= r */
+ d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1);
+ d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2);
+ d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3);
+ d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4);
+ d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0);
+
+ /* (partial) h %= p */
+ c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff;
+ d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff;
+ d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff;
+ d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff;
+ d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff;
+ h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff;
+ h1 += c;
+
+ m += poly1305_block_size;
+ bytes -= poly1305_block_size;
+ }
+
+ st->h[0] = h0;
+ st->h[1] = h1;
+ st->h[2] = h2;
+ st->h[3] = h3;
+ st->h[4] = h4;
+}
+
+POLY1305_NOINLINE void
+poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ unsigned long h0,h1,h2,h3,h4,c;
+ unsigned long g0,g1,g2,g3,g4;
+ unsigned long long f;
+ unsigned long mask;
+
+ /* process the remaining block */
+ if (st->leftover) {
+ size_t i = st->leftover;
+ st->buffer[i++] = 1;
+ for (; i < poly1305_block_size; i++)
+ st->buffer[i] = 0;
+ st->final = 1;
+ poly1305_blocks(st, st->buffer, poly1305_block_size);
+ }
+
+ /* fully carry h */
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+ h3 = st->h[3];
+ h4 = st->h[4];
+
+ c = h1 >> 26; h1 = h1 & 0x3ffffff;
+ h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
+ h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
+ h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
+ h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += c;
+
+ /* compute h + -p */
+ g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;
+ g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;
+ g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;
+ g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;
+ g4 = h4 + c - (1UL << 26);
+
+ /* select h if h < p, or h + -p if h >= p */
+ mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
+ g0 &= mask;
+ g1 &= mask;
+ g2 &= mask;
+ g3 &= mask;
+ g4 &= mask;
+ mask = ~mask;
+ h0 = (h0 & mask) | g0;
+ h1 = (h1 & mask) | g1;
+ h2 = (h2 & mask) | g2;
+ h3 = (h3 & mask) | g3;
+ h4 = (h4 & mask) | g4;
+
+ /* h = h % (2^128) */
+ h0 = ((h0 ) | (h1 << 26)) & 0xffffffff;
+ h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
+ h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+ h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
+
+ /* mac = (h + pad) % (2^128) */
+ f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f;
+ f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f;
+ f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f;
+ f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f;
+
+ U32TO8(mac + 0, h0);
+ U32TO8(mac + 4, h1);
+ U32TO8(mac + 8, h2);
+ U32TO8(mac + 12, h3);
+
+ /* zero out the state */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+ st->h[3] = 0;
+ st->h[4] = 0;
+ st->r[0] = 0;
+ st->r[1] = 0;
+ st->r[2] = 0;
+ st->r[3] = 0;
+ st->r[4] = 0;
+ st->pad[0] = 0;
+ st->pad[1] = 0;
+ st->pad[2] = 0;
+ st->pad[3] = 0;
+}
+
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.c b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.c
new file mode 100644
index 00000000..31ad7c59
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.c
@@ -0,0 +1,41 @@
+// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT
+
+#include "poly1305-donna.h"
+#include "poly1305-donna-32.h"
+
+void
+poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ size_t i;
+
+ /* handle leftover */
+ if (st->leftover) {
+ size_t want = (poly1305_block_size - st->leftover);
+ if (want > bytes)
+ want = bytes;
+ for (i = 0; i < want; i++)
+ st->buffer[st->leftover + i] = m[i];
+ bytes -= want;
+ m += want;
+ st->leftover += want;
+ if (st->leftover < poly1305_block_size)
+ return;
+ poly1305_blocks(st, st->buffer, poly1305_block_size);
+ st->leftover = 0;
+ }
+
+ /* process full blocks */
+ if (bytes >= poly1305_block_size) {
+ size_t want = (bytes & ~(poly1305_block_size - 1));
+ poly1305_blocks(st, m, want);
+ m += want;
+ bytes -= want;
+ }
+
+ /* store leftover */
+ if (bytes) {
+ for (i = 0; i < bytes; i++)
+ st->buffer[st->leftover + i] = m[i];
+ st->leftover += bytes;
+ }
+}
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.h b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.h
new file mode 100644
index 00000000..955bca99
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/poly1305-donna.h
@@ -0,0 +1,16 @@
+// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT
+#ifndef POLY1305_DONNA_H
+#define POLY1305_DONNA_H
+
+#include
+
+typedef struct poly1305_context {
+ size_t aligner;
+ unsigned char opaque[136];
+} poly1305_context;
+
+void poly1305_init(poly1305_context *ctx, const unsigned char key[32]);
+void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes);
+void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]);
+
+#endif /* POLY1305_DONNA_H */
diff --git a/lib/WireGuard-ESP32/src/crypto/refc/x25519-license.txt b/lib/WireGuard-ESP32/src/crypto/refc/x25519-license.txt
new file mode 100644
index 00000000..81e48621
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/x25519-license.txt
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2016 Cryptography Research, Inc.
+
+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/WireGuard-ESP32/src/crypto/refc/x25519.c b/lib/WireGuard-ESP32/src/crypto/refc/x25519.c
new file mode 100644
index 00000000..3b5ebe36
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/crypto/refc/x25519.c
@@ -0,0 +1,448 @@
+// Taken from https://sourceforge.net/p/strobe (MIT Licence)
+/**
+ * @cond internal
+ * @file x25519.c
+ * @copyright
+ * Copyright (c) 2015-2016 Cryptography Research, Inc. \n
+ * Released under the MIT License. See LICENSE.txt for license information.
+ * @author Mike Hamburg
+ * @brief Key exchange and signatures based on X25519.
+ */
+#include
+#include "x25519.h"
+//#include "strobe.h"
+//#include "strobe_config.h"
+// STROBE header replacement
+#include
+#define X25519_WBITS 32
+#define X25519_SUPPORT_SIGN 0
+#define X25519_MEMCPY_PARAMS 1
+#define X25519_USE_POWER_CHAIN 1
+#if BYTE_ORDER == LITTLE_ENDIAN
+static inline uint32_t eswap_letoh_32(uint32_t w) { return w; }
+#else
+#error "Fix eswap() on non-little-endian machine"
+#endif
+
+#if X25519_WBITS == 64
+ typedef uint64_t limb_t;
+ typedef __uint128_t dlimb_t;
+ typedef __int128_t sdlimb_t;
+ #define eswap_limb eswap_letoh_64
+ #define LIMB(x) x##ull
+#elif X25519_WBITS == 32
+ typedef uint32_t limb_t;
+ typedef uint64_t dlimb_t;
+ typedef int64_t sdlimb_t;
+ #define eswap_limb eswap_letoh_32
+ #define LIMB(x) (uint32_t)(x##ull),(uint32_t)((x##ull)>>32)
+#else
+ #error "Need to know X25519_WBITS"
+#endif
+
+#define NLIMBS (256/X25519_WBITS)
+typedef limb_t fe[NLIMBS];
+
+#if X25519_SUPPORT_SIGN
+typedef limb_t scalar_t[NLIMBS];
+static const limb_t MONTGOMERY_FACTOR = (limb_t)0xd2b51da312547e1bull;
+static const scalar_t sc_p = {
+ LIMB(0x5812631a5cf5d3ed), LIMB(0x14def9dea2f79cd6),
+ LIMB(0x0000000000000000), LIMB(0x1000000000000000)
+}, sc_r2 = {
+ LIMB(0xa40611e3449c0f01), LIMB(0xd00e1ba768859347),
+ LIMB(0xceec73d217f5be65), LIMB(0x0399411b7c309a3d)
+};
+#endif
+
+static inline limb_t umaal(
+ limb_t *carry, limb_t acc, limb_t mand, limb_t mier
+) {
+ dlimb_t tmp = (dlimb_t) mand * mier + acc + *carry;
+ *carry = tmp >> X25519_WBITS;
+ return tmp;
+}
+
+/* These functions are implemented in terms of umaal on ARM */
+static inline limb_t adc(limb_t *carry, limb_t acc, limb_t mand) {
+ dlimb_t total = (dlimb_t)*carry + acc + mand;
+ *carry = total>>X25519_WBITS;
+ return total;
+}
+
+static inline limb_t adc0(limb_t *carry, limb_t acc) {
+ dlimb_t total = (dlimb_t)*carry + acc;
+ *carry = total>>X25519_WBITS;
+ return total;
+}
+
+/* Precondition: carry is small.
+ * Invariant: result of propagate is < 2^255 + 1 word
+ * In particular, always less than 2p.
+ * Also, output x >= min(x,19)
+ */
+static void propagate(fe x, limb_t over) {
+ unsigned i;
+ over = x[NLIMBS-1]>>(X25519_WBITS-1) | over<<1;
+ x[NLIMBS-1] &= ~((limb_t)1<<(X25519_WBITS-1));
+
+ limb_t carry = over * 19;
+ for (i=0; i>= X25519_WBITS;
+ }
+ propagate(out,1+carry);
+}
+
+static void __attribute__((unused))
+swapin(limb_t *x, const uint8_t *in) {
+ memcpy(x,in,sizeof(fe));
+ unsigned i;
+ for (i=0; i>= X25519_WBITS;
+ }
+ return ((dlimb_t)res - 1) >> X25519_WBITS;
+}
+
+static const limb_t a24[1]={121665};
+
+static void ladder_part1(fe xs[5]) {
+ limb_t *x2 = xs[0], *z2=xs[1],*x3=xs[2],*z3=xs[3],*t1=xs[4];
+ add(t1,x2,z2); // t1 = A
+ sub(z2,x2,z2); // z2 = B
+ add(x2,x3,z3); // x2 = C
+ sub(z3,x3,z3); // z3 = D
+ mul1(z3,t1); // z3 = DA
+ mul1(x2,z2); // x3 = BC
+ add(x3,z3,x2); // x3 = DA+CB
+ sub(z3,z3,x2); // z3 = DA-CB
+ sqr1(t1); // t1 = AA
+ sqr1(z2); // z2 = BB
+ sub(x2,t1,z2); // x2 = E = AA-BB
+ mul(z2,x2,a24,sizeof(a24)/sizeof(a24[0])); // z2 = E*a24
+ add(z2,z2,t1); // z2 = E*a24 + AA
+}
+static void ladder_part2(fe xs[5], const fe x1) {
+ limb_t *x2 = xs[0], *z2=xs[1],*x3=xs[2],*z3=xs[3],*t1=xs[4];
+ sqr1(z3); // z3 = (DA-CB)^2
+ mul1(z3,x1); // z3 = x1 * (DA-CB)^2
+ sqr1(x3); // x3 = (DA+CB)^2
+ mul1(z2,x2); // z2 = AA*(E*a24+AA)
+ sub(x2,t1,x2); // x2 = BB again
+ mul1(x2,t1); // x2 = AA*BB
+}
+
+static void x25519_core(fe xs[5], const uint8_t scalar[X25519_BYTES], const uint8_t *x1, int clamp) {
+ int i;
+#if X25519_MEMCPY_PARAMS
+ fe x1i;
+ swapin(x1i,x1);
+ x1 = (const uint8_t *)x1;
+#endif
+ limb_t swap = 0;
+ limb_t *x2 = xs[0],*x3=xs[2],*z3=xs[3];
+ memset(xs,0,4*sizeof(fe));
+ x2[0] = z3[0] = 1;
+ memcpy(x3,x1,sizeof(fe));
+
+ for (i=255; i>=0; i--) {
+ uint8_t bytei = scalar[i/8];
+ if (clamp) {
+ if (i/8 == 0) {
+ bytei &= ~7;
+ } else if (i/8 == X25519_BYTES-1) {
+ bytei &= 0x7F;
+ bytei |= 0x40;
+ }
+ }
+ limb_t doswap = -(limb_t)((bytei>>(i%8)) & 1);
+ condswap(x2,x3,swap^doswap);
+ swap = doswap;
+
+ ladder_part1(xs);
+ ladder_part2(xs,(const limb_t *)x1);
+ }
+ condswap(x2,x3,swap);
+}
+
+int x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES], const uint8_t x1[X25519_BYTES], int clamp) {
+ fe xs[5];
+ x25519_core(xs,scalar,x1,clamp);
+
+ /* Precomputed inversion chain */
+ limb_t *x2 = xs[0], *z2=xs[1], *z3=xs[3];
+ int i;
+
+ limb_t *prev = z2;
+#if X25519_USE_POWER_CHAIN
+ static const struct { uint8_t a,c,n; } steps[13] = {
+ {2,1,1 },
+ {2,1,1 },
+ {4,2,3 },
+ {2,4,6 },
+ {3,1,1 },
+ {3,2,12 },
+ {4,3,25 },
+ {2,3,25 },
+ {2,4,50 },
+ {3,2,125},
+ {3,1,2 },
+ {3,1,2 },
+ {3,1,1 }
+ };
+ for (i=0; i<13; i++) {
+ int j;
+ limb_t *a = xs[steps[i].a];
+ for (j=steps[i].n; j>0; j--) {
+ sqr(a, prev);
+ prev = a;
+ }
+ mul1(a,xs[steps[i].c]);
+ }
+#else
+ /* Raise to the p-2 = 0x7f..ffeb */
+ for (i=253; i>=0; i--) {
+ sqr(z3,prev);
+ prev = z3;
+ if (i>=8 || (0xeb>>i & 1)) {
+ mul1(z3,z2);
+ }
+ }
+#endif
+
+ /* Here prev = z3 */
+ /* x2 /= z2 */
+#if X25519_MEMCPY_PARAMS
+ mul1(x2,z3);
+ int ret = canon(x2);
+ swapout(out,x2);
+#else
+ mul((limb_t *)out, x2, z3, NLIMBS);
+ int ret = canon((limb_t*)out);
+#endif
+ if (clamp) return ret;
+ else return 0;
+}
+
+const uint8_t X25519_BASE_POINT[X25519_BYTES] = {9};
+
+#if X25519_SUPPORT_VERIFY
+static limb_t x25519_verify_core(
+ fe xs[5],
+ const limb_t *other1,
+ const uint8_t other2[X25519_BYTES]
+) {
+ limb_t *z2=xs[1],*x3=xs[2],*z3=xs[3];
+#if X25519_MEMCPY_PARAMS
+ fe xo2;
+ swapin(xo2,other2);
+#else
+ const limb_t *xo2 = (const limb_t *)other2;
+#endif
+
+ memcpy(x3, other1, 2*sizeof(fe));
+
+ ladder_part1(xs);
+
+ /* Here z2 = t2^2 */
+ mul1(z2,other1);
+ mul1(z2,other1+NLIMBS);
+ mul1(z2,xo2);
+ const limb_t sixteen = 16;
+ mul (z2,z2,&sixteen,1);
+
+ mul1(z3,xo2);
+ sub(z3,z3,x3);
+ sqr1(z3);
+
+ /* check equality */
+ sub(z3,z3,z2);
+
+ /* If canon(z2) then both sides are zero.
+ * If canon(z3) then the two sides are equal.
+ *
+ * Reject sigs where both sides are zero, because
+ * that can happen if an input causes the ladder to
+ * return 0/0.
+ */
+ return canon(z2) | ~canon(z3);
+}
+
+int x25519_verify_p2 (
+ const uint8_t response[X25519_BYTES],
+ const uint8_t challenge[X25519_BYTES],
+ const uint8_t eph[X25519_BYTES],
+ const uint8_t pub[X25519_BYTES]
+) {
+ fe xs[7];
+ x25519_core(&xs[0],challenge,pub,0);
+ x25519_core(&xs[2],response,X25519_BASE_POINT,0);
+ return x25519_verify_core(&xs[2],xs[0],eph);
+}
+#endif // X25519_SUPPORT_VERIFY
+
+#if X25519_SUPPORT_SIGN
+static void sc_montmul (
+ scalar_t out,
+ const scalar_t a,
+ const scalar_t b
+) {
+ /**
+ * OK, so carry bounding. We're using a high carry, so that the
+ * inputs don't have to be reduced.
+ *
+ * First montmul: output < (M^2 + Mp)/M = M+p, subtract p, < M. This gets rid of high carry.
+ * Second montmul, by r^2 mod p < p: output < (Mp + Mp)/M = 2p, subtract p, < p, done.
+ */
+ unsigned i,j;
+ limb_t hic = 0;
+ for (i=0; i0) out[j-1] = acc;
+ }
+
+ /* Add two carry registers and high carry */
+ out[NLIMBS-1] = adc(&hic, carry, carry2);
+ }
+
+ /* Reduce */
+ sdlimb_t scarry = 0;
+ for (i=0; i>= X25519_WBITS;
+ }
+ limb_t need_add = -(scarry + hic);
+
+ limb_t carry = 0;
+ for (i=0; i
+#include "crypto.h"
+#include "lwip/sys.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "esp_system.h"
+
+static struct mbedtls_ctr_drbg_context random_context;
+static struct mbedtls_entropy_context entropy_context;
+static bool is_platform_initialized = false;
+
+static int entropy_hw_random_source( void *data, unsigned char *output, size_t len, size_t *olen ) {
+ esp_fill_random(output, len);
+ *olen = len;
+ return 0;
+}
+
+void wireguard_platform_init() {
+ if( is_platform_initialized ) return;
+
+ mbedtls_entropy_init(&entropy_context);
+ mbedtls_ctr_drbg_init(&random_context);
+ mbedtls_entropy_add_source(&entropy_context, entropy_hw_random_source, NULL, 134, MBEDTLS_ENTROPY_SOURCE_STRONG);
+ mbedtls_ctr_drbg_seed(&random_context, mbedtls_entropy_func, &entropy_context, NULL, 0);
+
+ is_platform_initialized = true;
+}
+
+void wireguard_random_bytes(void *bytes, size_t size) {
+ uint8_t *out = (uint8_t *)bytes;
+ mbedtls_ctr_drbg_random(&random_context, bytes, size);
+}
+
+uint32_t wireguard_sys_now() {
+ // Default to the LwIP system time
+ return sys_now();
+}
+
+void wireguard_tai64n_now(uint8_t *output) {
+ // See https://cr.yp.to/libtai/tai64.html
+ // 64 bit seconds from 1970 = 8 bytes
+ // 32 bit nano seconds from current second
+
+ // Get timestamp. Note that the timestamp must be synced by NTP,
+ // or at least preserved in NVS, not to go back after reset.
+ // Otherwise, the WireGuard remote peer rejects handshake.
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ uint64_t millis = (tv.tv_sec * 1000LL + (tv.tv_usec / 1000LL));
+
+ // Split into seconds offset + nanos
+ uint64_t seconds = 0x400000000000000aULL + (millis / 1000);
+ uint32_t nanos = (millis % 1000) * 1000;
+ U64TO8_BIG(output + 0, seconds);
+ U32TO8_BIG(output + 8, nanos);
+}
+
+bool wireguard_is_under_load() {
+ return false;
+}
+
diff --git a/lib/WireGuard-ESP32/src/wireguard-platform.h b/lib/WireGuard-ESP32/src/wireguard-platform.h
new file mode 100644
index 00000000..f54ec4a9
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/wireguard-platform.h
@@ -0,0 +1,71 @@
+/*
+ * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org)
+ * The original license is below:
+ *
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+#ifndef _WIREGUARD_PLATFORM_H_
+#define _WIREGUARD_PLATFORM_H_
+
+#include
+#include
+#include
+
+// Peers are allocated statically inside the device structure to avoid malloc
+#define WIREGUARD_MAX_PEERS 1
+#define WIREGUARD_MAX_SRC_IPS 2
+
+// Per device limit on accepting (valid) initiation requests - per peer
+#define MAX_INITIATIONS_PER_SECOND (2)
+
+//
+// Your platform integration needs to provide implementations of these functions
+//
+
+void wireguard_platform_init();
+
+// The number of milliseconds since system boot - for LwIP systems this could be sys_now()
+uint32_t wireguard_sys_now();
+
+// Fill the supplied buffer with random data - random data is used for generating new session keys periodically
+void wireguard_random_bytes(void *bytes, size_t size);
+
+// Get the current time in tai64n format - 8 byte seconds, 4 byte nano sub-second - see https://cr.yp.to/libtai/tai64.html for details
+// Output buffer passed is 12 bytes
+// The Wireguard implementation doesn't strictly need this to be a time, but instead an increasing value
+// The remote end of the Wireguard tunnel will use this value in handshake replay detection
+void wireguard_tai64n_now(uint8_t *output);
+
+// Is the system under load - i.e. should we generate cookie reply message in response to initiation messages
+bool wireguard_is_under_load();
+
+#endif /* _WIREGUARD_PLATFORM_H_ */
diff --git a/lib/WireGuard-ESP32/src/wireguard.c b/lib/WireGuard-ESP32/src/wireguard.c
new file mode 100644
index 00000000..ca86e9be
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/wireguard.c
@@ -0,0 +1,1129 @@
+/*
+ * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org)
+ * The original license is below:
+ *
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+#include "wireguard.h"
+
+#include
+#include
+#include
+
+#include "crypto.h"
+
+// For HMAC calculation
+#define WIREGUARD_BLAKE2S_BLOCK_SIZE (64)
+
+// 5.4 Messages
+// Constants
+static const uint8_t CONSTRUCTION[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; // The UTF-8 string literal "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s", 37 bytes of output
+static const uint8_t IDENTIFIER[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; // The UTF-8 string literal "WireGuard v1 zx2c4 Jason@zx2c4.com", 34 bytes of output
+static const uint8_t LABEL_MAC1[8] = "mac1----"; // Label-Mac1 The UTF-8 string literal "mac1----", 8 bytes of output.
+static const uint8_t LABEL_COOKIE[8] = "cookie--"; // Label-Cookie The UTF-8 string literal "cookie--", 8 bytes of output
+
+static const char *base64_lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const uint8_t zero_key[WIREGUARD_PUBLIC_KEY_LEN] = { 0 };
+
+// Calculated in wireguard_init
+static uint8_t construction_hash[WIREGUARD_HASH_LEN];
+static uint8_t identifier_hash[WIREGUARD_HASH_LEN];
+
+
+void wireguard_init() {
+ wireguard_blake2s_ctx ctx;
+ // Pre-calculate chaining key hash
+ wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0);
+ wireguard_blake2s_update(&ctx, CONSTRUCTION, sizeof(CONSTRUCTION));
+ wireguard_blake2s_final(&ctx, construction_hash);
+ // Pre-calculate initial handshake hash - uses construction_hash calculated above
+ wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0);
+ wireguard_blake2s_update(&ctx, construction_hash, sizeof(construction_hash));
+ wireguard_blake2s_update(&ctx, IDENTIFIER, sizeof(IDENTIFIER));
+ wireguard_blake2s_final(&ctx, identifier_hash);
+}
+
+struct wireguard_peer *peer_alloc(struct wireguard_device *device) {
+ struct wireguard_peer *result = NULL;
+ struct wireguard_peer *tmp;
+ int x;
+ for (x=0; x < WIREGUARD_MAX_PEERS; x++) {
+ tmp = &device->peers[x];
+ if (!tmp->valid) {
+ result = tmp;
+ break;
+ }
+ }
+ return result;
+}
+
+struct wireguard_peer *peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key) {
+ struct wireguard_peer *result = NULL;
+ struct wireguard_peer *tmp;
+ int x;
+ for (x=0; x < WIREGUARD_MAX_PEERS; x++) {
+ tmp = &device->peers[x];
+ if (tmp->valid) {
+ if (memcmp(tmp->public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN) == 0) {
+ result = tmp;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+uint8_t wireguard_peer_index(struct wireguard_device *device, struct wireguard_peer *peer) {
+ uint8_t result = 0xFF;
+ uint8_t x;
+ for (x=0; x < WIREGUARD_MAX_PEERS; x++) {
+ if (peer == &device->peers[x]) {
+ result = x;
+ break;
+ }
+ }
+ return result;
+}
+
+struct wireguard_peer *peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index) {
+ struct wireguard_peer *result = NULL;
+ if (peer_index < WIREGUARD_MAX_PEERS) {
+ if (device->peers[peer_index].valid) {
+ result = &device->peers[peer_index];
+ }
+ }
+ return result;
+}
+
+struct wireguard_peer *peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver) {
+ struct wireguard_peer *result = NULL;
+ struct wireguard_peer *tmp;
+ int x;
+ for (x=0; x < WIREGUARD_MAX_PEERS; x++) {
+ tmp = &device->peers[x];
+ if (tmp->valid) {
+ if ((tmp->curr_keypair.valid && (tmp->curr_keypair.local_index == receiver)) ||
+ (tmp->next_keypair.valid && (tmp->next_keypair.local_index == receiver)) ||
+ (tmp->prev_keypair.valid && (tmp->prev_keypair.local_index == receiver))
+ ) {
+ result = tmp;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+struct wireguard_peer *peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver) {
+ struct wireguard_peer *result = NULL;
+ struct wireguard_peer *tmp;
+ int x;
+ for (x=0; x < WIREGUARD_MAX_PEERS; x++) {
+ tmp = &device->peers[x];
+ if (tmp->valid) {
+ if (tmp->handshake.valid && tmp->handshake.initiator && (tmp->handshake.local_index == receiver)) {
+ result = tmp;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds) {
+ uint32_t diff = wireguard_sys_now() - created_millis;
+ return (diff >= (valid_seconds * 1000));
+}
+
+
+static void generate_cookie_secret(struct wireguard_device *device) {
+ wireguard_random_bytes(device->cookie_secret, WIREGUARD_HASH_LEN);
+ device->cookie_secret_millis = wireguard_sys_now();
+}
+
+static void generate_peer_cookie(struct wireguard_device *device, uint8_t *cookie, uint8_t *source_addr_port, size_t source_length) {
+ wireguard_blake2s_ctx ctx;
+
+ if (wireguard_expired(device->cookie_secret_millis, COOKIE_SECRET_MAX_AGE)) {
+ // Generate new random bytes
+ generate_cookie_secret(device);
+ }
+
+ // Mac(key, input) Keyed-Blake2s(key, input, 16), the keyed MAC variant of the BLAKE2s hash function, returning 16 bytes of output
+ wireguard_blake2s_init(&ctx, WIREGUARD_COOKIE_LEN, device->cookie_secret, WIREGUARD_HASH_LEN);
+ // 5.4.7 Under Load: Cookie Reply Message
+ // Mix in the IP address and port - have the IP layer pass this in as byte array to avoid using Lwip specific APIs in this module
+ if ((source_addr_port) && (source_length > 0)) {
+ wireguard_blake2s_update(&ctx, source_addr_port, source_length);
+ }
+ wireguard_blake2s_final(&ctx, cookie);
+}
+
+static void wireguard_mac(uint8_t *dst, const void *message, size_t len, const uint8_t *key, size_t keylen) {
+ wireguard_blake2s(dst, WIREGUARD_COOKIE_LEN, key, keylen, message, len);
+}
+
+static void wireguard_mac_key(uint8_t *key, const uint8_t *public_key, const uint8_t *label, size_t label_len) {
+ blake2s_ctx ctx;
+ blake2s_init(&ctx, WIREGUARD_SESSION_KEY_LEN, NULL, 0);
+ blake2s_update(&ctx, label, label_len);
+ blake2s_update(&ctx, public_key, WIREGUARD_PUBLIC_KEY_LEN);
+ blake2s_final(&ctx, key);
+}
+
+static void wireguard_mix_hash(uint8_t *hash, const uint8_t *src, size_t src_len) {
+ wireguard_blake2s_ctx ctx;
+ wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0);
+ wireguard_blake2s_update(&ctx, hash, WIREGUARD_HASH_LEN);
+ wireguard_blake2s_update(&ctx, src, src_len);
+ wireguard_blake2s_final(&ctx, hash);
+}
+
+static void wireguard_hmac(uint8_t *digest, const uint8_t *key, size_t key_len, const uint8_t *text, size_t text_len) {
+ // Adapted from appendix example in RFC2104 to use BLAKE2S instead of MD5 - https://tools.ietf.org/html/rfc2104
+ wireguard_blake2s_ctx ctx;
+ uint8_t k_ipad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // inner padding - key XORd with ipad
+ uint8_t k_opad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // outer padding - key XORd with opad
+
+ uint8_t tk[WIREGUARD_HASH_LEN];
+ int i;
+ // if key is longer than BLAKE2S_BLOCK_SIZE bytes reset it to key=BLAKE2S(key)
+ if (key_len > WIREGUARD_BLAKE2S_BLOCK_SIZE) {
+ wireguard_blake2s_ctx tctx;
+ wireguard_blake2s_init(&tctx, WIREGUARD_HASH_LEN, NULL, 0);
+ wireguard_blake2s_update(&tctx, key, key_len);
+ wireguard_blake2s_final(&tctx, tk);
+ key = tk;
+ key_len = WIREGUARD_HASH_LEN;
+ }
+
+ // the HMAC transform looks like:
+ // HASH(K XOR opad, HASH(K XOR ipad, text))
+ // where K is an n byte key
+ // ipad is the byte 0x36 repeated BLAKE2S_BLOCK_SIZE times
+ // opad is the byte 0x5c repeated BLAKE2S_BLOCK_SIZE times
+ // and text is the data being protected
+ memset(k_ipad, 0, sizeof(k_ipad));
+ memset(k_opad, 0, sizeof(k_opad));
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ // XOR key with ipad and opad values
+ for (i=0; i < WIREGUARD_BLAKE2S_BLOCK_SIZE; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ // perform inner HASH
+ wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 1st pass
+ wireguard_blake2s_update(&ctx, k_ipad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with inner pad
+ wireguard_blake2s_update(&ctx, text, text_len); // then text of datagram
+ wireguard_blake2s_final(&ctx, digest); // finish up 1st pass
+
+ // perform outer HASH
+ wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 2nd pass
+ wireguard_blake2s_update(&ctx, k_opad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with outer pad
+ wireguard_blake2s_update(&ctx, digest, WIREGUARD_HASH_LEN); // then results of 1st hash
+ wireguard_blake2s_final(&ctx, digest); // finish up 2nd pass
+}
+
+static void wireguard_kdf1(uint8_t *tau1, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) {
+ uint8_t tau0[WIREGUARD_HASH_LEN];
+ uint8_t output[WIREGUARD_HASH_LEN + 1];
+
+ // tau0 = Hmac(key, input)
+ wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len);
+ // tau1 := Hmac(tau0, 0x1)
+ output[0] = 1;
+ wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1);
+ memcpy(tau1, output, WIREGUARD_HASH_LEN);
+
+ // Wipe intermediates
+ crypto_zero(tau0, sizeof(tau0));
+ crypto_zero(output, sizeof(output));
+}
+
+static void wireguard_kdf2(uint8_t *tau1, uint8_t *tau2, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) {
+ uint8_t tau0[WIREGUARD_HASH_LEN];
+ uint8_t output[WIREGUARD_HASH_LEN + 1];
+
+ // tau0 = Hmac(key, input)
+ wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len);
+ // tau1 := Hmac(tau0, 0x1)
+ output[0] = 1;
+ wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1);
+ memcpy(tau1, output, WIREGUARD_HASH_LEN);
+
+ // tau2 := Hmac(tau0,tau1 || 0x2)
+ output[WIREGUARD_HASH_LEN] = 2;
+ wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1);
+ memcpy(tau2, output, WIREGUARD_HASH_LEN);
+
+ // Wipe intermediates
+ crypto_zero(tau0, sizeof(tau0));
+ crypto_zero(output, sizeof(output));
+}
+
+static void wireguard_kdf3(uint8_t *tau1, uint8_t *tau2, uint8_t *tau3, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) {
+ uint8_t tau0[WIREGUARD_HASH_LEN];
+ uint8_t output[WIREGUARD_HASH_LEN + 1];
+
+ // tau0 = Hmac(key, input)
+ wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len);
+ // tau1 := Hmac(tau0, 0x1)
+ output[0] = 1;
+ wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1);
+ memcpy(tau1, output, WIREGUARD_HASH_LEN);
+
+ // tau2 := Hmac(tau0,tau1 || 0x2)
+ output[WIREGUARD_HASH_LEN] = 2;
+ wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1);
+ memcpy(tau2, output, WIREGUARD_HASH_LEN);
+
+ // tau3 := Hmac(tau0,tau1,tau2 || 0x3)
+ output[WIREGUARD_HASH_LEN] = 3;
+ wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1);
+ memcpy(tau3, output, WIREGUARD_HASH_LEN);
+
+ // Wipe intermediates
+ crypto_zero(tau0, sizeof(tau0));
+ crypto_zero(output, sizeof(output));
+}
+
+bool wireguard_check_replay(struct wireguard_keypair *keypair, uint64_t seq) {
+ // Implementation of packet replay window - as per RFC2401
+ // Adapted from code in Appendix C at https://tools.ietf.org/html/rfc2401
+ uint32_t diff;
+ bool result = false;
+ size_t ReplayWindowSize = sizeof(keypair->replay_bitmap); // 32 bits
+
+ if (seq != 0) {
+ if (seq > keypair->replay_counter) {
+ // new larger sequence number
+ diff = seq - keypair->replay_counter;
+ if (diff < ReplayWindowSize) {
+ // In window
+ keypair->replay_bitmap <<= diff;
+ // set bit for this packet
+ keypair->replay_bitmap |= 1;
+ } else {
+ // This packet has a "way larger"
+ keypair->replay_bitmap = 1;
+ }
+ keypair->replay_counter = seq;
+ // larger is good
+ result = true;
+ } else {
+ diff = keypair->replay_counter - seq;
+ if (diff < ReplayWindowSize) {
+ if (keypair->replay_bitmap & ((uint32_t)1 << diff)) {
+ // already seen
+ } else {
+ // mark as seen
+ keypair->replay_bitmap |= ((uint32_t)1 << diff);
+ // out of order but good
+ result = true;
+ }
+ } else {
+ // too old or wrapped
+ }
+ }
+ } else {
+ // first == 0 or wrapped
+ }
+ return result;
+}
+
+struct wireguard_keypair *get_peer_keypair_for_idx(struct wireguard_peer *peer, uint32_t idx) {
+ if (peer->curr_keypair.valid && peer->curr_keypair.local_index == idx) {
+ return &peer->curr_keypair;
+ } else if (peer->next_keypair.valid && peer->next_keypair.local_index == idx) {
+ return &peer->next_keypair;
+ } else if (peer->prev_keypair.valid && peer->prev_keypair.local_index == idx) {
+ return &peer->prev_keypair;
+ }
+ return NULL;
+}
+
+static uint32_t wireguard_generate_unique_index(struct wireguard_device *device) {
+ // We need a random 32-bit number but make sure it's not already been used in the context of this device
+ uint32_t result;
+ uint8_t buf[4];
+ int x;
+ struct wireguard_peer *peer;
+ bool existing;
+ do {
+ do {
+ wireguard_random_bytes(buf, 4);
+ result = U8TO32_LITTLE(buf);
+ } while ((result == 0) || (result == 0xFFFFFFFF)); // Don't allow 0 or 0xFFFFFFFF as valid values
+
+ existing = false;
+ for (x=0; x < WIREGUARD_MAX_PEERS; x++) {
+ peer = &device->peers[x];
+ existing = (result == peer->curr_keypair.local_index) ||
+ (result == peer->prev_keypair.local_index) ||
+ (result == peer->next_keypair.local_index) ||
+ (result == peer->handshake.local_index);
+
+ }
+ } while (existing);
+
+ return result;
+}
+
+static void wireguard_clamp_private_key(uint8_t *key) {
+ key[0] &= 248;
+ key[31] = (key[31] & 127) | 64;
+}
+
+static void wireguard_generate_private_key(uint8_t *key) {
+ wireguard_random_bytes(key, WIREGUARD_PRIVATE_KEY_LEN);
+ wireguard_clamp_private_key(key);
+}
+
+static bool wireguard_generate_public_key(uint8_t *public_key, const uint8_t *private_key) {
+ static const uint8_t basepoint[WIREGUARD_PUBLIC_KEY_LEN] = { 9 };
+ bool result = false;
+ if (memcmp(private_key, zero_key, WIREGUARD_PUBLIC_KEY_LEN) != 0) {
+ result = (wireguard_x25519(public_key, private_key, basepoint) == 0);
+ }
+ return result;
+}
+
+bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1) {
+ bool result = false;
+ uint8_t calculated[WIREGUARD_COOKIE_LEN];
+ wireguard_mac(calculated, data, len, device->label_mac1_key, WIREGUARD_SESSION_KEY_LEN);
+ if (crypto_equal(calculated, mac1, WIREGUARD_COOKIE_LEN)) {
+ result = true;
+ }
+ return result;
+}
+
+bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2) {
+ bool result = false;
+ uint8_t cookie[WIREGUARD_COOKIE_LEN];
+ uint8_t calculated[WIREGUARD_COOKIE_LEN];
+
+ generate_peer_cookie(device, cookie, source_addr_port, source_length);
+
+ wireguard_mac(calculated, data, len, cookie, WIREGUARD_COOKIE_LEN);
+ if (crypto_equal(calculated, mac2, WIREGUARD_COOKIE_LEN)) {
+ result = true;
+ }
+ return result;
+}
+
+void handshake_destroy(struct wireguard_handshake *handshake) {
+ crypto_zero(handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN);
+ crypto_zero(handshake->remote_ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+ crypto_zero(handshake->hash, WIREGUARD_HASH_LEN);
+ crypto_zero(handshake->chaining_key, WIREGUARD_HASH_LEN);
+ handshake->remote_index = 0;
+ handshake->local_index = 0;
+ handshake->valid = false;
+}
+
+void keypair_destroy(struct wireguard_keypair *keypair) {
+ crypto_zero(keypair, sizeof(struct wireguard_keypair));
+ keypair->valid = false;
+}
+
+void keypair_update(struct wireguard_peer *peer, struct wireguard_keypair *received_keypair) {
+ bool key_is_next = (received_keypair == &peer->next_keypair);
+ if (key_is_next) {
+ peer->prev_keypair = peer->curr_keypair;
+ peer->curr_keypair = peer->next_keypair;
+ keypair_destroy(&peer->next_keypair);
+ }
+}
+
+static void add_new_keypair(struct wireguard_peer *peer, struct wireguard_keypair new_keypair) {
+ if (new_keypair.initiator) {
+ if (peer->next_keypair.valid) {
+ peer->prev_keypair = peer->next_keypair;
+ keypair_destroy(&peer->next_keypair);
+ } else {
+ peer->prev_keypair = peer->curr_keypair;
+ }
+ peer->curr_keypair = new_keypair;
+ } else {
+ peer->next_keypair = new_keypair;
+ keypair_destroy(&peer->prev_keypair);
+ }
+}
+
+void wireguard_start_session(struct wireguard_peer *peer, bool initiator) {
+ struct wireguard_handshake *handshake = &peer->handshake;
+ struct wireguard_keypair new_keypair;
+
+ crypto_zero(&new_keypair, sizeof(struct wireguard_keypair));
+ new_keypair.initiator = initiator;
+ new_keypair.local_index = handshake->local_index;
+ new_keypair.remote_index = handshake->remote_index;
+
+ new_keypair.keypair_millis = wireguard_sys_now();
+ new_keypair.sending_valid = true;
+ new_keypair.receiving_valid = true;
+
+ // 5.4.5 Transport Data Key Derivation
+ // (Tsendi = Trecvr, Trecvi = Tsendr) := Kdf2(Ci = Cr,E)
+ if (new_keypair.initiator) {
+ wireguard_kdf2(new_keypair.sending_key, new_keypair.receiving_key, handshake->chaining_key, NULL, 0);
+ } else {
+ wireguard_kdf2(new_keypair.receiving_key, new_keypair.sending_key, handshake->chaining_key, NULL, 0);
+ }
+
+ new_keypair.replay_bitmap = 0;
+ new_keypair.replay_counter = 0;
+
+ new_keypair.last_tx = 0;
+ new_keypair.last_rx = 0; // No packets received yet
+
+ new_keypair.valid = true;
+
+ // Eprivi = Epubi = Eprivr = Epubr = Ci = Cr := E
+ crypto_zero(handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN);
+ crypto_zero(handshake->remote_ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+ crypto_zero(handshake->hash, WIREGUARD_HASH_LEN);
+ crypto_zero(handshake->chaining_key, WIREGUARD_HASH_LEN);
+ handshake->remote_index = 0;
+ handshake->local_index = 0;
+ handshake->valid = false;
+
+ add_new_keypair(peer, new_keypair);
+}
+
+uint8_t wireguard_get_message_type(const uint8_t *data, size_t len) {
+ uint8_t result = MESSAGE_INVALID;
+ if (len >= 4) {
+ if ((data[1] == 0) && (data[2] == 0) && (data[3] == 0)) {
+ switch (data[0]) {
+ case MESSAGE_HANDSHAKE_INITIATION:
+ if (len == sizeof(struct message_handshake_initiation)) {
+ result = MESSAGE_HANDSHAKE_INITIATION;
+ }
+ break;
+ case MESSAGE_HANDSHAKE_RESPONSE:
+ if (len == sizeof(struct message_handshake_response)) {
+ result = MESSAGE_HANDSHAKE_RESPONSE;
+ }
+ break;
+ case MESSAGE_COOKIE_REPLY:
+ if (len == sizeof(struct message_cookie_reply)) {
+ result = MESSAGE_COOKIE_REPLY;
+ }
+ break;
+ case MESSAGE_TRANSPORT_DATA:
+ if (len >= sizeof(struct message_transport_data) + WIREGUARD_AUTHTAG_LEN) {
+ result = MESSAGE_TRANSPORT_DATA;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+struct wireguard_peer *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg) {
+ struct wireguard_peer *ret_peer = NULL;
+ struct wireguard_peer *peer = NULL;
+ struct wireguard_handshake *handshake;
+ uint8_t key[WIREGUARD_SESSION_KEY_LEN];
+ uint8_t chaining_key[WIREGUARD_HASH_LEN];
+ uint8_t hash[WIREGUARD_HASH_LEN];
+ uint8_t s[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t e[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t t[WIREGUARD_TAI64N_LEN];
+ uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
+ uint32_t now;
+ bool rate_limit;
+ bool replay;
+
+ // We are the responder, other end is the initiator
+
+ // Ci := Hash(Construction) (precalculated hash)
+ memcpy(chaining_key, construction_hash, WIREGUARD_HASH_LEN);
+
+ // Hi := Hash(Ci || Identifier
+ memcpy(hash, identifier_hash, WIREGUARD_HASH_LEN);
+
+ // Hi := Hash(Hi || Spubr)
+ wireguard_mix_hash(hash, device->public_key, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Ci := Kdf1(Ci, Epubi)
+ wireguard_kdf1(chaining_key, chaining_key, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.ephemeral := Epubi
+ memcpy(e, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Hi := Hash(Hi || msg.ephemeral)
+ wireguard_mix_hash(hash, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Calculate DH(Eprivi,Spubr)
+ wireguard_x25519(dh_calculation, device->private_key, e);
+ if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
+
+ // (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr))
+ wireguard_kdf2(chaining_key, key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.static := AEAD(k, 0, Spubi, Hi)
+ if (wireguard_aead_decrypt(s, msg->enc_static, sizeof(msg->enc_static), hash, WIREGUARD_HASH_LEN, 0, key)) {
+ // Hi := Hash(Hi || msg.static)
+ wireguard_mix_hash(hash, msg->enc_static, sizeof(msg->enc_static));
+
+ peer = peer_lookup_by_pubkey(device, s);
+ if (peer) {
+ handshake = &peer->handshake;
+
+ // (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr))
+ wireguard_kdf2(chaining_key, key, chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.timestamp := AEAD(k, 0, Timestamp(), Hi)
+ if (wireguard_aead_decrypt(t, msg->enc_timestamp, sizeof(msg->enc_timestamp), hash, WIREGUARD_HASH_LEN, 0, key)) {
+ // Hi := Hash(Hi || msg.timestamp)
+ wireguard_mix_hash(hash, msg->enc_timestamp, sizeof(msg->enc_timestamp));
+
+ now = wireguard_sys_now();
+
+ // Check that timestamp is increasing and we haven't had too many initiations (should only get one per peer every 5 seconds max?)
+ replay = (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) <= 0); // tai64n is big endian so we can use memcmp to compare
+ rate_limit = (peer->last_initiation_rx - now) < (1000 / MAX_INITIATIONS_PER_SECOND);
+
+ if (!replay && !rate_limit) {
+ // Success! Copy everything to peer
+ peer->last_initiation_rx = now;
+ if (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) > 0) {
+ memcpy(peer->greatest_timestamp, t, WIREGUARD_TAI64N_LEN);
+ // TODO: Need to notify if the higher layers want to persist latest timestamp/nonce somewhere
+ }
+ memcpy(handshake->remote_ephemeral, e, WIREGUARD_PUBLIC_KEY_LEN);
+ memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN);
+ memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN);
+ handshake->remote_index = msg->sender;
+ handshake->valid = true;
+ handshake->initiator = false;
+ ret_peer = peer;
+
+ } else {
+ // Ignore
+ }
+ } else {
+ // Failed to decrypt
+ }
+ } else {
+ // peer not found
+ }
+ } else {
+ // Failed to decrypt
+ }
+ } else {
+ // Bad X25519
+ }
+
+ crypto_zero(key, sizeof(key));
+ crypto_zero(hash, sizeof(hash));
+ crypto_zero(chaining_key, sizeof(chaining_key));
+ crypto_zero(dh_calculation, sizeof(dh_calculation));
+
+ return ret_peer;
+}
+
+bool wireguard_process_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *src) {
+ struct wireguard_handshake *handshake = &peer->handshake;
+
+ bool result = false;
+ uint8_t key[WIREGUARD_SESSION_KEY_LEN];
+ uint8_t hash[WIREGUARD_HASH_LEN];
+ uint8_t chaining_key[WIREGUARD_HASH_LEN];
+ uint8_t e[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t ephemeral_private[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t static_private[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN];
+ uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t tau[WIREGUARD_PUBLIC_KEY_LEN];
+
+ if (handshake->valid && handshake->initiator) {
+
+ memcpy(hash, handshake->hash, WIREGUARD_HASH_LEN);
+ memcpy(chaining_key, handshake->chaining_key, WIREGUARD_HASH_LEN);
+ memcpy(ephemeral_private, handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN);
+ memcpy(preshared_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN);
+
+ // (Eprivr, Epubr) := DH-Generate()
+ // Not required
+
+ // Cr := Kdf1(Cr,Epubr)
+ wireguard_kdf1(chaining_key, chaining_key, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.ephemeral := Epubr
+ memcpy(e, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Hr := Hash(Hr || msg.ephemeral)
+ wireguard_mix_hash(hash, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Cr := Kdf1(Cr, DH(Eprivr, Epubi))
+ // Calculate DH(Eprivr, Epubi)
+ wireguard_x25519(dh_calculation, ephemeral_private, e);
+ if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
+ wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Cr := Kdf1(Cr, DH(Eprivr, Spubi))
+ // CalculateDH(Eprivr, Spubi)
+ wireguard_x25519(dh_calculation, device->private_key, e);
+ if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
+ wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // (Cr, t, k) := Kdf3(Cr, Q)
+ wireguard_kdf3(chaining_key, tau, key, chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN);
+
+ // Hr := Hash(Hr | t)
+ wireguard_mix_hash(hash, tau, WIREGUARD_HASH_LEN);
+
+ // msg.empty := AEAD(k, 0, E, Hr)
+ if (wireguard_aead_decrypt(NULL, src->enc_empty, sizeof(src->enc_empty), hash, WIREGUARD_HASH_LEN, 0, key)) {
+ // Hr := Hash(Hr | msg.empty)
+ // Not required as discarded
+
+ //Copy details to handshake
+ memcpy(handshake->remote_ephemeral, e, WIREGUARD_HASH_LEN);
+ memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN);
+ memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN);
+ handshake->remote_index = src->sender;
+
+ result = true;
+ } else {
+ // Decrypt failed
+ }
+
+ } else {
+ // X25519 fail
+ }
+
+ } else {
+ // X25519 fail
+ }
+
+ }
+ crypto_zero(key, sizeof(key));
+ crypto_zero(hash, sizeof(hash));
+ crypto_zero(chaining_key, sizeof(chaining_key));
+ crypto_zero(ephemeral_private, sizeof(ephemeral_private));
+ crypto_zero(static_private, sizeof(static_private));
+ crypto_zero(preshared_key, sizeof(preshared_key));
+ crypto_zero(tau, sizeof(tau));
+
+ return result;
+}
+
+bool wireguard_process_cookie_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_cookie_reply *src) {
+ uint8_t cookie[WIREGUARD_COOKIE_LEN];
+ bool result = false;
+
+ if (peer->handshake_mac1_valid) {
+
+ result = wireguard_xaead_decrypt(cookie, src->enc_cookie, sizeof(src->enc_cookie), peer->handshake_mac1, WIREGUARD_COOKIE_LEN, src->nonce, peer->label_cookie_key);
+
+ if (result) {
+ // 5.4.7 Under Load: Cookie Reply Message
+ // Upon receiving this message, if it is valid, the only thing the recipient of this message should do is store the cookie along with the time at which it was received
+ memcpy(peer->cookie, cookie, WIREGUARD_COOKIE_LEN);
+ peer->cookie_millis = wireguard_sys_now();
+ peer->handshake_mac1_valid = false;
+ }
+ } else {
+ // We didn't send any initiation packet so we shouldn't be getting a cookie reply!
+ }
+ return result;
+}
+
+bool wireguard_create_handshake_initiation(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *dst) {
+ uint8_t timestamp[WIREGUARD_TAI64N_LEN];
+ uint8_t key[WIREGUARD_SESSION_KEY_LEN];
+ uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
+ bool result = false;
+
+ struct wireguard_handshake *handshake = &peer->handshake;
+
+ memset(dst, 0, sizeof(struct message_handshake_initiation));
+
+ // Ci := Hash(Construction) (precalculated hash)
+ memcpy(handshake->chaining_key, construction_hash, WIREGUARD_HASH_LEN);
+
+ // Hi := Hash(Ci || Identifier)
+ memcpy(handshake->hash, identifier_hash, WIREGUARD_HASH_LEN);
+
+ // Hi := Hash(Hi || Spubr)
+ wireguard_mix_hash(handshake->hash, peer->public_key, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // (Eprivi, Epubi) := DH-Generate()
+ wireguard_generate_private_key(handshake->ephemeral_private);
+ if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) {
+
+ // Ci := Kdf1(Ci, Epubi)
+ wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.ephemeral := Epubi
+ // Done above - public keys is calculated into dst->ephemeral
+
+ // Hi := Hash(Hi || msg.ephemeral)
+ wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Calculate DH(Eprivi,Spubr)
+ wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key);
+ if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
+
+ // (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr))
+ wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.static := AEAD(k,0,Spubi, Hi)
+ wireguard_aead_encrypt(dst->enc_static, device->public_key, WIREGUARD_PUBLIC_KEY_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key);
+
+ // Hi := Hash(Hi || msg.static)
+ wireguard_mix_hash(handshake->hash, dst->enc_static, sizeof(dst->enc_static));
+
+ // (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr))
+ // note DH(Sprivi,Spubr) is precomputed per peer
+ wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.timestamp := AEAD(k, 0, Timestamp(), Hi)
+ wireguard_tai64n_now(timestamp);
+ wireguard_aead_encrypt(dst->enc_timestamp, timestamp, WIREGUARD_TAI64N_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key);
+
+ // Hi := Hash(Hi || msg.timestamp)
+ wireguard_mix_hash(handshake->hash, dst->enc_timestamp, sizeof(dst->enc_timestamp));
+
+ dst->type = MESSAGE_HANDSHAKE_INITIATION;
+ dst->sender = wireguard_generate_unique_index(device);
+
+ handshake->valid = true;
+ handshake->initiator = true;
+ handshake->local_index = dst->sender;
+
+ result = true;
+ }
+ }
+
+ if (result) {
+ // 5.4.4 Cookie MACs
+ // msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA)
+ // The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed
+ wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_initiation)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN);
+
+ // if Lm = E or Lm ≥ 120:
+ if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) {
+ // msg.mac2 := 0
+ crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN);
+ } else {
+ // msg.mac2 := Mac(Lm, msgB)
+ wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_initiation)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN);
+
+ }
+ }
+
+ crypto_zero(key, sizeof(key));
+ crypto_zero(dh_calculation, sizeof(dh_calculation));
+ return result;
+}
+
+bool wireguard_create_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *dst) {
+ struct wireguard_handshake *handshake = &peer->handshake;
+ uint8_t key[WIREGUARD_SESSION_KEY_LEN];
+ uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t tau[WIREGUARD_HASH_LEN];
+ bool result = false;
+
+ memset(dst, 0, sizeof(struct message_handshake_response));
+
+ if (handshake->valid && !handshake->initiator) {
+
+ // (Eprivr, Epubr) := DH-Generate()
+ wireguard_generate_private_key(handshake->ephemeral_private);
+ if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) {
+
+ // Cr := Kdf1(Cr,Epubr)
+ wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // msg.ephemeral := Epubr
+ // Copied above when generated
+
+ // Hr := Hash(Hr || msg.ephemeral)
+ wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Cr := Kdf1(Cr, DH(Eprivr, Epubi))
+ // Calculate DH(Eprivi,Spubr)
+ wireguard_x25519(dh_calculation, handshake->ephemeral_private, handshake->remote_ephemeral);
+ if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
+ wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // Cr := Kdf1(Cr, DH(Eprivr, Spubi))
+ // Calculate DH(Eprivi,Spubr)
+ wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key);
+ if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
+ wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
+
+ // (Cr, t, k) := Kdf3(Cr, Q)
+ wireguard_kdf3(handshake->chaining_key, tau, key, handshake->chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN);
+
+ // Hr := Hash(Hr | t)
+ wireguard_mix_hash(handshake->hash, tau, WIREGUARD_HASH_LEN);
+
+ // msg.empty := AEAD(k, 0, E, Hr)
+ wireguard_aead_encrypt(dst->enc_empty, NULL, 0, handshake->hash, WIREGUARD_HASH_LEN, 0, key);
+
+ // Hr := Hash(Hr | msg.empty)
+ wireguard_mix_hash(handshake->hash, dst->enc_empty, sizeof(dst->enc_empty));
+
+ dst->type = MESSAGE_HANDSHAKE_RESPONSE;
+ dst->receiver = handshake->remote_index;
+ dst->sender = wireguard_generate_unique_index(device);
+ // Update handshake object too
+ handshake->local_index = dst->sender;
+
+ result = true;
+ } else {
+ // Bad x25519
+ }
+ } else {
+ // Bad x25519
+ }
+
+ } else {
+ // Failed to generate DH
+ }
+ }
+
+ if (result) {
+ // 5.4.4 Cookie MACs
+ // msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA)
+ // The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed
+ wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_response)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN);
+
+ // if Lm = E or Lm ≥ 120:
+ if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) {
+ // msg.mac2 := 0
+ crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN);
+ } else {
+ // msg.mac2 := Mac(Lm, msgB)
+ wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_response)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN);
+ }
+ }
+
+ crypto_zero(key, sizeof(key));
+ crypto_zero(dh_calculation, sizeof(dh_calculation));
+ crypto_zero(tau, sizeof(tau));
+ return result;
+}
+
+void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length) {
+ uint8_t cookie[WIREGUARD_COOKIE_LEN];
+ crypto_zero(dst, sizeof(struct message_cookie_reply));
+ dst->type = MESSAGE_COOKIE_REPLY;
+ dst->receiver = index;
+ wireguard_random_bytes(dst->nonce, COOKIE_NONCE_LEN);
+ generate_peer_cookie(device, cookie, source_addr_port, source_length);
+ wireguard_xaead_encrypt(dst->enc_cookie, cookie, WIREGUARD_COOKIE_LEN, mac1, WIREGUARD_COOKIE_LEN, dst->nonce, device->label_cookie_key);
+}
+
+bool wireguard_peer_init(struct wireguard_device *device, struct wireguard_peer *peer, const uint8_t *public_key, const uint8_t *preshared_key) {
+ // Clear out structure
+ memset(peer, 0, sizeof(struct wireguard_peer));
+
+ if (device->valid) {
+ // Copy across the public key into our peer structure
+ memcpy(peer->public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN);
+ if (preshared_key) {
+ memcpy(peer->preshared_key, preshared_key, WIREGUARD_SESSION_KEY_LEN);
+ } else {
+ crypto_zero(peer->preshared_key, WIREGUARD_SESSION_KEY_LEN);
+ }
+
+ if (wireguard_x25519(peer->public_key_dh, device->private_key, peer->public_key) == 0) {
+ // Zero out handshake
+ memset(&peer->handshake, 0, sizeof(struct wireguard_handshake));
+ peer->handshake.valid = false;
+
+ // Zero out any cookie info - we haven't received one yet
+ peer->cookie_millis = 0;
+ memset(&peer->cookie, 0, WIREGUARD_COOKIE_LEN);
+
+ // Precompute keys to deal with mac1/2 calculation
+ wireguard_mac_key(peer->label_mac1_key, peer->public_key, LABEL_MAC1, sizeof(LABEL_MAC1));
+ wireguard_mac_key(peer->label_cookie_key, peer->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE));
+
+ peer->valid = true;
+ } else {
+ crypto_zero(peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN);
+ }
+ }
+ return peer->valid;
+}
+
+bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key) {
+ // Set the private key and calculate public key from it
+ memcpy(device->private_key, private_key, WIREGUARD_PRIVATE_KEY_LEN);
+ // Ensure private key is correctly "clamped"
+ wireguard_clamp_private_key(device->private_key);
+ device->valid = wireguard_generate_public_key(device->public_key, private_key);
+ if (device->valid) {
+ generate_cookie_secret(device);
+ // 5.4.4 Cookie MACs - The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed.
+ wireguard_mac_key(device->label_mac1_key, device->public_key, LABEL_MAC1, sizeof(LABEL_MAC1));
+ // 5.4.7 Under Load: Cookie Reply Message - The value Hash(Label-Cookie || Spubm) above can be pre-computed.
+ wireguard_mac_key(device->label_cookie_key, device->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE));
+
+ } else {
+ crypto_zero(device->private_key, WIREGUARD_PRIVATE_KEY_LEN);
+ }
+ return device->valid;
+}
+
+void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, struct wireguard_keypair *keypair) {
+ wireguard_aead_encrypt(dst, src, src_len, NULL, 0, keypair->sending_counter, keypair->sending_key);
+ keypair->sending_counter++;
+}
+
+bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, struct wireguard_keypair *keypair) {
+ return wireguard_aead_decrypt(dst, src, src_len, NULL, 0, counter, keypair->receiving_key);
+}
+
+bool wireguard_base64_decode(const char *str, uint8_t *out, size_t *outlen) {
+ uint32_t accum = 0; // We accumulate upto four blocks of 6 bits into this to form 3 bytes output
+ uint8_t char_count = 0; // How many characters have we processed in this block
+ int byte_count = 3; // How many bytes are we expecting in current 4 char block
+ int len = 0; // result length in bytes
+ bool result = true;
+ uint8_t bits;
+ char c;
+ char *ptr;
+ int x;
+ size_t inlen;
+
+ if (!str) {
+ return false;
+ }
+
+ inlen = strlen(str);
+
+ for (x = 0; x < inlen; x++) {
+ c = str[x];
+ if (c == '=') {
+ // This is '=' padding at end of string - decrease the number of bytes to write
+ bits = 0;
+ byte_count--;
+ if (byte_count < 0) {
+ // Too much padding!
+ result = false;
+ break;
+ }
+ } else {
+ if (byte_count != 3) {
+ // Padding only allowed at end - this is a valid byte and we have already seen padding
+ result = false;
+ break;
+ }
+ ptr = strchr(base64_lookup, c);
+ if (ptr) {
+ bits = (uint8_t)((ptr - base64_lookup) & 0x3F);
+ } else {
+ // invalid character in input string
+ result = false;
+ break;
+ }
+ }
+
+ accum = (accum << 6) | bits;
+ char_count++;
+
+ if (char_count == 4) {
+ if (len + byte_count > *outlen) {
+ // Output buffer overflow
+ result = false;
+ break;
+ }
+ out[len++] = (uint8_t)((accum >> 16) & 0xFF);
+ if (byte_count > 1) {
+ out[len++] = (uint8_t)((accum >> 8) & 0xFF);
+ }
+ if (byte_count > 2) {
+ out[len++] = (uint8_t)(accum & 0xFF);
+ }
+ char_count = 0;
+ accum = 0;
+ }
+ }
+ if (char_count != 0) {
+ // We require padding to multiple of 3 input length - bytes are missing from output!
+ result = false;
+ }
+ *outlen = len;
+ return result;
+}
+
+bool wireguard_base64_encode(const uint8_t *in, size_t inlen, char *out, size_t *outlen) {
+ bool result = false;
+ int read_offset = 0;
+ int write_offset = 0;
+ uint8_t byte1, byte2, byte3;
+ uint32_t tmp;
+ char c;
+ size_t len = 4 * ((inlen + 2) / 3);
+ int padding = (3 - (inlen % 3));
+ if (padding > 2) padding = 0;
+ if (*outlen > len) {
+
+ while (read_offset < inlen) {
+ // Read three bytes
+ byte1 = (read_offset < inlen) ? in[read_offset++] : 0;
+ byte2 = (read_offset < inlen) ? in[read_offset++] : 0;
+ byte3 = (read_offset < inlen) ? in[read_offset++] : 0;
+ // Turn into 24 bit intermediate
+ tmp = (byte1 << 16) | (byte2 << 8) | (byte3);
+ // Write out 4 characters each representing 6 bits of input
+ out[write_offset++] = base64_lookup[(tmp >> 18) & 0x3F];
+ out[write_offset++] = base64_lookup[(tmp >> 12) & 0x3F];
+ c = (write_offset < len - padding) ? base64_lookup[(tmp >> 6) & 0x3F] : '=';
+ out[write_offset++] = c;
+ c = (write_offset < len - padding) ? base64_lookup[(tmp) & 0x3F] : '=';
+ out[write_offset++] = c;
+ }
+ out[len] = '\0';
+ *outlen = len;
+ result = true;
+ } else {
+ // Not enough data to put in base64 and null terminate
+ }
+ return result;
+}
diff --git a/lib/WireGuard-ESP32/src/wireguard.h b/lib/WireGuard-ESP32/src/wireguard.h
new file mode 100644
index 00000000..d5554926
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/wireguard.h
@@ -0,0 +1,288 @@
+/*
+ * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org)
+ * The original license is below:
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+#ifndef _WIREGUARD_H_
+#define _WIREGUARD_H_
+
+#include
+#include
+#include
+
+// Note: these are only required for definitions in device/peer for netif, udp_pcb, ip_addr_t and u16_t
+#include "lwip/netif.h"
+#include "lwip/udp.h"
+#include "lwip/ip_addr.h"
+#include "lwip/arch.h"
+
+// Platform-specific functions that need to be implemented per-platform
+#include "wireguard-platform.h"
+
+// tai64n contains 64-bit seconds and 32-bit nano offset (12 bytes)
+#define WIREGUARD_TAI64N_LEN (12)
+// Auth algorithm is chacha20pol1305 which is 128bit (16 byte) authenticator
+#define WIREGUARD_AUTHTAG_LEN (16)
+// Hash algorithm is blake2s which makes 32 byte hashes
+#define WIREGUARD_HASH_LEN (32)
+// Public key algo is curve22519 which uses 32 byte keys
+#define WIREGUARD_PUBLIC_KEY_LEN (32)
+// Public key algo is curve22519 which uses 32 byte keys
+#define WIREGUARD_PRIVATE_KEY_LEN (32)
+// Symmetric session keys are chacha20/poly1305 which uses 32 byte keys
+#define WIREGUARD_SESSION_KEY_LEN (32)
+
+// Timers / Limits
+#define WIREGUARD_COOKIE_LEN (16)
+#define COOKIE_SECRET_MAX_AGE (2 * 60)
+#define COOKIE_NONCE_LEN (24)
+
+#define REKEY_AFTER_MESSAGES (1ULL << 60)
+#define REJECT_AFTER_MESSAGES (0xFFFFFFFFFFFFFFFFULL - (1ULL << 13))
+#define REKEY_AFTER_TIME (120)
+#define REJECT_AFTER_TIME (180)
+#define REKEY_TIMEOUT (5)
+#define KEEPALIVE_TIMEOUT (10)
+
+struct wireguard_keypair {
+ bool valid;
+ bool initiator; // Did we initiate this session (send the initiation packet rather than sending the response packet)
+ uint32_t keypair_millis;
+
+ uint8_t sending_key[WIREGUARD_SESSION_KEY_LEN];
+ bool sending_valid;
+ uint64_t sending_counter;
+
+ uint8_t receiving_key[WIREGUARD_SESSION_KEY_LEN];
+ bool receiving_valid;
+
+ uint32_t last_tx;
+ uint32_t last_rx;
+
+ uint32_t replay_bitmap;
+ uint64_t replay_counter;
+
+ uint32_t local_index; // This is the index we generated for our end
+ uint32_t remote_index; // This is the index on the other end
+};
+
+struct wireguard_handshake {
+ bool valid;
+ bool initiator;
+ uint32_t local_index;
+ uint32_t remote_index;
+ uint8_t ephemeral_private[WIREGUARD_PRIVATE_KEY_LEN];
+ uint8_t remote_ephemeral[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t hash[WIREGUARD_HASH_LEN];
+ uint8_t chaining_key[WIREGUARD_HASH_LEN];
+};
+
+struct wireguard_allowed_ip {
+ bool valid;
+ ip_addr_t ip;
+ ip_addr_t mask;
+};
+
+struct wireguard_peer {
+ bool valid; // Is this peer initialised?
+ bool active; // Should we be actively trying to connect?
+
+ // This is the configured IP of the peer (endpoint)
+ ip_addr_t connect_ip;
+ u16_t connect_port;
+ // This is the latest received IP/port
+ ip_addr_t ip;
+ u16_t port;
+ // keep-alive interval in seconds, 0 is disable
+ uint16_t keepalive_interval;
+
+ struct wireguard_allowed_ip allowed_source_ips[WIREGUARD_MAX_SRC_IPS];
+
+ uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN];
+
+ // Precomputed DH(Sprivi,Spubr) with device private key, and peer public key
+ uint8_t public_key_dh[WIREGUARD_PUBLIC_KEY_LEN];
+
+ // Session keypairs
+ struct wireguard_keypair curr_keypair;
+ struct wireguard_keypair prev_keypair;
+ struct wireguard_keypair next_keypair;
+
+ // 5.1 Silence is a Virtue: The responder keeps track of the greatest timestamp received per peer
+ uint8_t greatest_timestamp[WIREGUARD_TAI64N_LEN];
+
+ // The active handshake that is happening
+ struct wireguard_handshake handshake;
+
+ // Decrypted cookie from the responder
+ uint32_t cookie_millis;
+ uint8_t cookie[WIREGUARD_COOKIE_LEN];
+
+ // The latest mac1 we sent with initiation
+ bool handshake_mac1_valid;
+ uint8_t handshake_mac1[WIREGUARD_COOKIE_LEN];
+
+ // Precomputed keys for use in mac validation
+ uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN];
+ uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN];
+
+ // The last time we received a valid initiation message
+ uint32_t last_initiation_rx;
+ // The last time we sent an initiation message to this peer
+ uint32_t last_initiation_tx;
+
+ // last_tx and last_rx of data packets
+ uint32_t last_tx;
+ uint32_t last_rx;
+
+ // We set this flag on RX/TX of packets if we think that we should initiate a new handshake
+ bool send_handshake;
+};
+
+struct wireguard_device {
+ // Maybe have a "Device private" member to abstract these?
+ struct netif *netif;
+ struct udp_pcb *udp_pcb;
+
+ struct netif *underlying_netif;
+
+ uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN];
+ uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN];
+
+ uint8_t cookie_secret[WIREGUARD_HASH_LEN];
+ uint32_t cookie_secret_millis;
+
+ // Precalculated
+ uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN];
+ uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN];
+
+ // List of peers associated with this device
+ struct wireguard_peer peers[WIREGUARD_MAX_PEERS];
+
+ bool valid;
+};
+
+#define MESSAGE_INVALID 0
+#define MESSAGE_HANDSHAKE_INITIATION 1
+#define MESSAGE_HANDSHAKE_RESPONSE 2
+#define MESSAGE_COOKIE_REPLY 3
+#define MESSAGE_TRANSPORT_DATA 4
+
+
+// 5.4.2 First Message: Initiator to Responder
+struct message_handshake_initiation {
+ uint8_t type;
+ uint8_t reserved[3];
+ uint32_t sender;
+ uint8_t ephemeral[32];
+ uint8_t enc_static[32 + WIREGUARD_AUTHTAG_LEN];
+ uint8_t enc_timestamp[WIREGUARD_TAI64N_LEN + WIREGUARD_AUTHTAG_LEN];
+ uint8_t mac1[WIREGUARD_COOKIE_LEN];
+ uint8_t mac2[WIREGUARD_COOKIE_LEN];
+} __attribute__ ((__packed__));
+
+// 5.4.3 Second Message: Responder to Initiator
+struct message_handshake_response {
+ uint8_t type;
+ uint8_t reserved[3];
+ uint32_t sender;
+ uint32_t receiver;
+ uint8_t ephemeral[32];
+ uint8_t enc_empty[0 + WIREGUARD_AUTHTAG_LEN];
+ uint8_t mac1[WIREGUARD_COOKIE_LEN];
+ uint8_t mac2[WIREGUARD_COOKIE_LEN];
+} __attribute__ ((__packed__));
+
+// 5.4.7 Under Load: Cookie Reply Message
+struct message_cookie_reply {
+ uint8_t type;
+ uint8_t reserved[3];
+ uint32_t receiver;
+ uint8_t nonce[COOKIE_NONCE_LEN];
+ uint8_t enc_cookie[WIREGUARD_COOKIE_LEN + WIREGUARD_AUTHTAG_LEN];
+} __attribute__ ((__packed__));
+
+// 5.4.6 Subsequent Messages: Transport Data Messages
+struct message_transport_data {
+ uint8_t type;
+ uint8_t reserved[3];
+ uint32_t receiver;
+ uint8_t counter[8];
+ // Followed by encrypted data
+ uint8_t enc_packet[];
+} __attribute__ ((__packed__));
+
+// Initialise the WireGuard system - need to call this before anything else
+void wireguard_init();
+bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key);
+bool wireguard_peer_init(struct wireguard_device *device, struct wireguard_peer *peer, const uint8_t *public_key, const uint8_t *preshared_key);
+
+struct wireguard_peer *peer_alloc(struct wireguard_device *device);
+uint8_t wireguard_peer_index(struct wireguard_device *device, struct wireguard_peer *peer);
+struct wireguard_peer *peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key);
+struct wireguard_peer *peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index);
+struct wireguard_peer *peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver);
+struct wireguard_peer *peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver);
+
+void wireguard_start_session(struct wireguard_peer *peer, bool initiator);
+
+void keypair_update(struct wireguard_peer *peer, struct wireguard_keypair *received_keypair);
+void keypair_destroy(struct wireguard_keypair *keypair);
+
+struct wireguard_keypair *get_peer_keypair_for_idx(struct wireguard_peer *peer, uint32_t idx);
+bool wireguard_check_replay(struct wireguard_keypair *keypair, uint64_t seq);
+
+uint8_t wireguard_get_message_type(const uint8_t *data, size_t len);
+
+struct wireguard_peer *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg);
+bool wireguard_process_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *src);
+bool wireguard_process_cookie_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_cookie_reply *src);
+
+bool wireguard_create_handshake_initiation(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *dst);
+bool wireguard_create_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *dst);
+void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length);
+
+void handshake_destroy(struct wireguard_handshake *handshake);
+
+bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1);
+bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2);
+
+bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds);
+
+void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, struct wireguard_keypair *keypair);
+bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, struct wireguard_keypair *keypair);
+
+bool wireguard_base64_decode(const char *str, uint8_t *out, size_t *outlen);
+bool wireguard_base64_encode(const uint8_t *in, size_t inlen, char *out, size_t *outlen);
+
+#endif /* _WIREGUARD_H_ */
diff --git a/lib/WireGuard-ESP32/src/wireguardif.c b/lib/WireGuard-ESP32/src/wireguardif.c
new file mode 100644
index 00000000..c8192f62
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/wireguardif.c
@@ -0,0 +1,1028 @@
+/*
+ * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org)
+ * The original license is below:
+ *
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+#include "wireguardif.h"
+
+#include
+#include
+
+#include "lwip/netif.h"
+#include "lwip/ip.h"
+#include "lwip/udp.h"
+#include "lwip/mem.h"
+#include "lwip/sys.h"
+#include "lwip/timeouts.h"
+
+#include "wireguard.h"
+#include "crypto.h"
+#include "esp_log.h"
+#include "esp_netif.h"
+
+#include "esp32-hal-log.h"
+
+#define WIREGUARDIF_TIMER_MSECS 400
+
+#define TAG "[WireGuard] "
+
+static void update_peer_addr(struct wireguard_peer *peer, const ip_addr_t *addr, u16_t port) {
+ peer->ip = *addr;
+ peer->port = port;
+}
+
+static struct wireguard_peer *peer_lookup_by_allowed_ip(struct wireguard_device *device, const ip_addr_t *ipaddr) {
+ struct wireguard_peer *result = NULL;
+ struct wireguard_peer *tmp;
+ int x;
+ int y;
+ for (x=0; (!result) && (x < WIREGUARD_MAX_PEERS); x++) {
+ tmp = &device->peers[x];
+ if (tmp->valid) {
+ for (y=0; y < WIREGUARD_MAX_SRC_IPS; y++) {
+ if ((tmp->allowed_source_ips[y].valid) && ip_addr_netcmp(ipaddr, &tmp->allowed_source_ips[y].ip, ip_2_ip4(&tmp->allowed_source_ips[y].mask))) {
+ result = tmp;
+ break;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static bool wireguardif_can_send_initiation(struct wireguard_peer *peer) {
+ return ((peer->last_initiation_tx == 0) || (wireguard_expired(peer->last_initiation_tx, REKEY_TIMEOUT)));
+}
+
+static err_t wireguardif_peer_output(struct netif *netif, struct pbuf *q, struct wireguard_peer *peer) {
+ struct wireguard_device *device = (struct wireguard_device *)netif->state;
+ // Send to last know port, not the connect port
+ //TODO: Support DSCP and ECN - lwip requires this set on PCB globally, not per packet
+ return udp_sendto_if(device->udp_pcb, q, &peer->ip, peer->port, device->underlying_netif);
+}
+
+static err_t wireguardif_device_output(struct wireguard_device *device, struct pbuf *q, const ip_addr_t *ipaddr, u16_t port) {
+ return udp_sendto_if(device->udp_pcb, q, ipaddr, port, device->underlying_netif);
+}
+
+static err_t wireguardif_output_to_peer(struct netif *netif, struct pbuf *q, const ip_addr_t *ipaddr, struct wireguard_peer *peer) {
+ // The LWIP IP layer wants to send an IP packet out over the interface - we need to encrypt and send it to the peer
+ struct message_transport_data *hdr;
+ struct pbuf *pbuf;
+ err_t result;
+ size_t unpadded_len;
+ size_t padded_len;
+ size_t header_len = 16;
+ uint8_t *dst;
+ uint32_t now;
+ struct wireguard_keypair *keypair = &peer->curr_keypair;
+
+ // Note: We may not be able to use the current keypair if we haven't received data, may need to resort to using previous keypair
+ if (keypair->valid && (!keypair->initiator) && (keypair->last_rx == 0)) {
+ keypair = &peer->prev_keypair;
+ }
+
+ if (keypair->valid && (keypair->initiator || keypair->last_rx != 0)) {
+
+ if (
+ !wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME) &&
+ (keypair->sending_counter < REJECT_AFTER_MESSAGES)
+ ) {
+
+ // Calculate the outgoing packet size - round up to next 16 bytes, add 16 bytes for header
+ if (q) {
+ // This is actual transport data
+ unpadded_len = q->tot_len;
+ } else {
+ // This is a keep-alive
+ unpadded_len = 0;
+ }
+ padded_len = (unpadded_len + 15) & 0xFFFFFFF0; // Round up to next 16 byte boundary
+
+ // The buffer needs to be allocated from "transport" pool to leave room for LwIP generated IP headers
+ // The IP packet consists of 16 byte header (struct message_transport_data), data padded upto 16 byte boundary + encrypted auth tag (16 bytes)
+ pbuf = pbuf_alloc(PBUF_TRANSPORT, header_len + padded_len + WIREGUARD_AUTHTAG_LEN, PBUF_RAM);
+ if (pbuf) {
+ log_v(TAG "preparing transport data...");
+ // Note: allocating pbuf from RAM above guarantees that the pbuf is in one section and not chained
+ // - i.e payload points to the contiguous memory region
+ memset(pbuf->payload, 0, pbuf->tot_len);
+
+ hdr = (struct message_transport_data *)pbuf->payload;
+
+ hdr->type = MESSAGE_TRANSPORT_DATA;
+ hdr->receiver = keypair->remote_index;
+ // Alignment required... pbuf_alloc has probably aligned data, but want to be sure
+ U64TO8_LITTLE(hdr->counter, keypair->sending_counter);
+
+ // Copy the encrypted (padded) data to the output packet - chacha20poly1305_encrypt() can encrypt data in-place which avoids call to mem_malloc
+ dst = &hdr->enc_packet[0];
+ if ((padded_len > 0) && q) {
+ // Note: before copying make sure we have inserted the IP header checksum
+ // The IP header checksum (and other checksums in the IP packet - e.g. ICMP) need to be calculated by LWIP before calling
+ // The Wireguard interface always needs checksums to be generated in software but the base netif may have some checksums generated by hardware
+
+ // Copy pbuf to memory - handles case where pbuf is chained
+ pbuf_copy_partial(q, dst, unpadded_len, 0);
+ }
+
+ // Then encrypt
+ wireguard_encrypt_packet(dst, dst, padded_len, keypair);
+
+ result = wireguardif_peer_output(netif, pbuf, peer);
+
+ if (result == ERR_OK) {
+ now = wireguard_sys_now();
+ peer->last_tx = now;
+ keypair->last_tx = now;
+ }
+
+ pbuf_free(pbuf);
+
+ // Check to see if we should rekey
+ if (keypair->sending_counter >= REKEY_AFTER_MESSAGES) {
+ peer->send_handshake = true;
+ } else if (keypair->initiator && wireguard_expired(keypair->keypair_millis, REKEY_AFTER_TIME)) {
+ peer->send_handshake = true;
+ }
+
+ } else {
+ // Failed to allocate memory
+ result = ERR_MEM;
+ }
+ } else {
+ // key has expired...
+ keypair_destroy(keypair);
+ result = ERR_CONN;
+ }
+ } else {
+ // No valid keys!
+ result = ERR_CONN;
+ }
+ return result;
+}
+
+// This is used as the output function for the Wireguard netif
+// The ipaddr here is the one inside the VPN which we use to lookup the correct peer/endpoint
+static err_t wireguardif_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ip4addr) {
+ struct wireguard_device *device = (struct wireguard_device *)netif->state;
+ // Send to peer that matches dest IP
+ ip_addr_t ipaddr;
+ ip_addr_copy_from_ip4(ipaddr, *ip4addr);
+ struct wireguard_peer *peer = peer_lookup_by_allowed_ip(device, &ipaddr);
+ if (peer) {
+ return wireguardif_output_to_peer(netif, q, &ipaddr, peer);
+ } else {
+ return ERR_RTE;
+ }
+}
+
+static void wireguardif_send_keepalive(struct wireguard_device *device, struct wireguard_peer *peer) {
+ // Send a NULL packet as a keep-alive
+ wireguardif_output_to_peer(device->netif, NULL, NULL, peer);
+}
+
+static void wireguardif_process_response_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *response, const ip_addr_t *addr, u16_t port) {
+ if (wireguard_process_handshake_response(device, peer, response)) {
+ // Packet is good
+ // Update the peer location
+ log_i(TAG "good handshake from %08x:%d", addr->u_addr.ip4.addr, port);
+ update_peer_addr(peer, addr, port);
+
+ wireguard_start_session(peer, true);
+ wireguardif_send_keepalive(device, peer);
+
+ // Set the IF-UP flag on netif
+ netif_set_link_up(device->netif);
+ } else {
+ // Packet bad
+ log_i(TAG "bad handshake from %08x:%d", addr->u_addr.ip4.addr, port);
+ }
+}
+
+static bool peer_add_ip(struct wireguard_peer *peer, ip_addr_t ip, ip_addr_t mask) {
+ bool result = false;
+ struct wireguard_allowed_ip *allowed;
+ int x;
+ // Look for existing match first
+ for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) {
+ allowed = &peer->allowed_source_ips[x];
+ if ((allowed->valid) && ip_addr_cmp(&allowed->ip, &ip) && ip_addr_cmp(&allowed->mask, &mask)) {
+ result = true;
+ break;
+ }
+ }
+ if (!result) {
+ // Look for a free slot
+ for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) {
+ allowed = &peer->allowed_source_ips[x];
+ if (!allowed->valid) {
+ allowed->valid = true;
+ allowed->ip = ip;
+ allowed->mask = mask;
+ result = true;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+static void wireguardif_process_data_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_transport_data *data_hdr, size_t data_len, const ip_addr_t *addr, u16_t port) {
+ struct wireguard_keypair *keypair;
+ uint64_t nonce;
+ uint8_t *src;
+ size_t src_len;
+ struct pbuf *pbuf;
+ struct ip_hdr *iphdr;
+ ip_addr_t dest;
+ bool dest_ok = false;
+ int x;
+ uint32_t now;
+ uint16_t header_len = 0xFFFF;
+ uint32_t idx = data_hdr->receiver;
+
+ keypair = get_peer_keypair_for_idx(peer, idx);
+
+ if (keypair) {
+ if (
+ (keypair->receiving_valid) &&
+ !wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME) &&
+ (keypair->sending_counter < REJECT_AFTER_MESSAGES)
+
+ ) {
+
+ nonce = U8TO64_LITTLE(data_hdr->counter);
+ src = &data_hdr->enc_packet[0];
+ src_len = data_len;
+
+ // We don't know the unpadded size until we have decrypted the packet and validated/inspected the IP header
+ pbuf = pbuf_alloc(PBUF_TRANSPORT, src_len - WIREGUARD_AUTHTAG_LEN, PBUF_RAM);
+ if (pbuf) {
+ // Decrypt the packet
+ memset(pbuf->payload, 0, pbuf->tot_len);
+ if (wireguard_decrypt_packet(pbuf->payload, src, src_len, nonce, keypair)) {
+
+ // 3. Since the packet has authenticated correctly, the source IP of the outer UDP/IP packet is used to update the endpoint for peer TrMv...WXX0.
+ // Update the peer location
+ update_peer_addr(peer, addr, port);
+
+ now = wireguard_sys_now();
+ keypair->last_rx = now;
+ peer->last_rx = now;
+
+ // Might need to shuffle next key --> current keypair
+ keypair_update(peer, keypair);
+
+ // Check to see if we should rekey
+ if (keypair->initiator && wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME - peer->keepalive_interval - REKEY_TIMEOUT)) {
+ peer->send_handshake = true;
+ }
+
+ // Make sure that link is reported as up
+ netif_set_link_up(device->netif);
+
+ if (pbuf->tot_len > 0) {
+ //4a. Once the packet payload is decrypted, the interface has a plaintext packet. If this is not an IP packet, it is dropped.
+ iphdr = (struct ip_hdr *)pbuf->payload;
+ // Check for packet replay / dupes
+ if (wireguard_check_replay(keypair, nonce)) {
+
+ // 4b. Otherwise, WireGuard checks to see if the source IP address of the plaintext inner-packet routes correspondingly in the cryptokey routing table
+ // Also check packet length!
+#if LWIP_IPV4
+ if (IPH_V(iphdr) == 4) {
+ ip_addr_copy_from_ip4(dest, iphdr->dest);
+ for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) {
+ if (peer->allowed_source_ips[x].valid) {
+ if (ip_addr_netcmp(&dest, &peer->allowed_source_ips[x].ip, ip_2_ip4(&peer->allowed_source_ips[x].mask))) {
+ dest_ok = true;
+ header_len = PP_NTOHS(IPH_LEN(iphdr));
+ break;
+ }
+ }
+ }
+ }
+#endif /* LWIP_IPV4 */
+#if LWIP_IPV6
+ if (IPH_V(iphdr) == 6) {
+ // TODO: IPV6 support for route filtering
+ header_len = PP_NTOHS(IPH_LEN(iphdr));
+ dest_ok = true;
+ }
+#endif /* LWIP_IPV6 */
+ if (header_len <= pbuf->tot_len) {
+
+ // 5. If the plaintext packet has not been dropped, it is inserted into the receive queue of the wg0 interface.
+ if (dest_ok) {
+ // Send packet to be process by LWIP
+ ip_input(pbuf, device->netif);
+ // pbuf is owned by IP layer now
+ pbuf = NULL;
+ }
+ } else {
+ // IP header is corrupt or lied about packet size
+ }
+ } else {
+ // This is a duplicate packet / replayed / too far out of order
+ }
+ } else {
+ // This was a keep-alive packet
+ }
+ }
+
+ if (pbuf) {
+ pbuf_free(pbuf);
+ }
+ }
+
+
+ } else {
+ //After Reject-After-Messages transport data messages or after the current secure session is Reject- After-Time seconds old,
+ // whichever comes first, WireGuard will refuse to send or receive any more transport data messages using the current secure session,
+ // until a new secure session is created through the 1-RTT handshake
+ keypair_destroy(keypair);
+ }
+
+ } else {
+ // Could not locate valid keypair for remote index
+ }
+}
+
+static struct pbuf *wireguardif_initiate_handshake(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *msg, err_t *error) {
+ struct pbuf *pbuf = NULL;
+ err_t err = ERR_OK;
+ if (wireguard_create_handshake_initiation(device, peer, msg)) {
+ // Send this packet out!
+ pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_handshake_initiation), PBUF_RAM);
+ if (pbuf) {
+ err = pbuf_take(pbuf, msg, sizeof(struct message_handshake_initiation));
+ if (err == ERR_OK) {
+ // OK!
+ } else {
+ pbuf_free(pbuf);
+ pbuf = NULL;
+ }
+ } else {
+ err = ERR_MEM;
+ }
+ } else {
+ err = ERR_ARG;
+ }
+ if (error) {
+ *error = err;
+ }
+ return pbuf;
+}
+
+static void wireguardif_send_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer) {
+ struct message_handshake_response packet;
+ struct pbuf *pbuf = NULL;
+ err_t err = ERR_OK;
+
+ if (wireguard_create_handshake_response(device, peer, &packet)) {
+
+ wireguard_start_session(peer, false);
+
+ // Send this packet out!
+ pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_handshake_response), PBUF_RAM);
+ if (pbuf) {
+ err = pbuf_take(pbuf, &packet, sizeof(struct message_handshake_response));
+ if (err == ERR_OK) {
+ // OK!
+ wireguardif_peer_output(device->netif, pbuf, peer);
+ }
+ pbuf_free(pbuf);
+ }
+ }
+}
+
+static size_t get_source_addr_port(const ip_addr_t *addr, u16_t port, uint8_t *buf, size_t buflen) {
+ size_t result = 0;
+
+#if LWIP_IPV4
+ if (IP_IS_V4(addr) && (buflen >= 4)) {
+ U32TO8_BIG(buf + result, PP_NTOHL(ip4_addr_get_u32(ip_2_ip4(addr))));
+ result += 4;
+ }
+#endif
+#if LWIP_IPV6
+ if (IP_IS_V6(addr) && (buflen >= 16)) {
+ U16TO8_BIG(buf + result + 0, IP6_ADDR_BLOCK1(ip_2_ip6(addr)));
+ U16TO8_BIG(buf + result + 2, IP6_ADDR_BLOCK2(ip_2_ip6(addr)));
+ U16TO8_BIG(buf + result + 4, IP6_ADDR_BLOCK3(ip_2_ip6(addr)));
+ U16TO8_BIG(buf + result + 6, IP6_ADDR_BLOCK4(ip_2_ip6(addr)));
+ U16TO8_BIG(buf + result + 8, IP6_ADDR_BLOCK5(ip_2_ip6(addr)));
+ U16TO8_BIG(buf + result + 10, IP6_ADDR_BLOCK6(ip_2_ip6(addr)));
+ U16TO8_BIG(buf + result + 12, IP6_ADDR_BLOCK7(ip_2_ip6(addr)));
+ U16TO8_BIG(buf + result + 14, IP6_ADDR_BLOCK8(ip_2_ip6(addr)));
+ result += 16;
+ }
+#endif
+ if (buflen >= result + 2) {
+ U16TO8_BIG(buf + result, port);
+ result += 2;
+ }
+ return result;
+}
+
+static void wireguardif_send_handshake_cookie(struct wireguard_device *device, const uint8_t *mac1, uint32_t index, const ip_addr_t *addr, u16_t port) {
+ struct message_cookie_reply packet;
+ struct pbuf *pbuf = NULL;
+ err_t err = ERR_OK;
+ uint8_t source_buf[18];
+ size_t source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf));
+
+ wireguard_create_cookie_reply(device, &packet, mac1, index, source_buf, source_len);
+
+ // Send this packet out!
+ pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_cookie_reply), PBUF_RAM);
+ if (pbuf) {
+ err = pbuf_take(pbuf, &packet, sizeof(struct message_cookie_reply));
+ if (err == ERR_OK) {
+ wireguardif_device_output(device, pbuf, addr, port);
+ }
+ pbuf_free(pbuf);
+ }
+}
+
+static bool wireguardif_check_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg, const ip_addr_t *addr, u16_t port) {
+ bool result = false;
+ uint8_t *data = (uint8_t *)msg;
+ uint8_t source_buf[18];
+ size_t source_len;
+ // We received an initiation packet check it is valid
+
+ if (wireguard_check_mac1(device, data, sizeof(struct message_handshake_initiation) - (2 * WIREGUARD_COOKIE_LEN), msg->mac1)) {
+ // mac1 is valid!
+ if (!wireguard_is_under_load()) {
+ // If we aren't under load we only need mac1 to be correct
+ result = true;
+ } else {
+ // If we are under load then check mac2
+ source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf));
+
+ result = wireguard_check_mac2(device, data, sizeof(struct message_handshake_initiation) - (WIREGUARD_COOKIE_LEN), source_buf, source_len, msg->mac2);
+
+ if (!result) {
+ // mac2 is invalid (cookie may have expired) or not present
+ // 5.3 Denial of Service Mitigation & Cookies
+ // If the responder receives a message with a valid msg.mac1 yet with an invalid msg.mac2, and is under load, it may respond with a cookie reply message
+ wireguardif_send_handshake_cookie(device, msg->mac1, msg->sender, addr, port);
+ }
+ }
+
+ } else {
+ // mac1 is invalid
+ }
+ return result;
+}
+
+static bool wireguardif_check_response_message(struct wireguard_device *device, struct message_handshake_response *msg, const ip_addr_t *addr, u16_t port) {
+ bool result = false;
+ uint8_t *data = (uint8_t *)msg;
+ uint8_t source_buf[18];
+ size_t source_len;
+ // We received an initiation packet check it is valid
+
+ if (wireguard_check_mac1(device, data, sizeof(struct message_handshake_response) - (2 * WIREGUARD_COOKIE_LEN), msg->mac1)) {
+ // mac1 is valid!
+ if (!wireguard_is_under_load()) {
+ // If we aren't under load we only need mac1 to be correct
+ result = true;
+ } else {
+ // If we are under load then check mac2
+ source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf));
+
+ result = wireguard_check_mac2(device, data, sizeof(struct message_handshake_response) - (WIREGUARD_COOKIE_LEN), source_buf, source_len, msg->mac2);
+
+ if (!result) {
+ // mac2 is invalid (cookie may have expired) or not present
+ // 5.3 Denial of Service Mitigation & Cookies
+ // If the responder receives a message with a valid msg.mac1 yet with an invalid msg.mac2, and is under load, it may respond with a cookie reply message
+ wireguardif_send_handshake_cookie(device, msg->mac1, msg->sender, addr, port);
+ }
+ }
+
+ } else {
+ // mac1 is invalid
+ }
+ return result;
+}
+
+
+void wireguardif_network_rx(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
+ LWIP_ASSERT("wireguardif_network_rx: invalid arg", arg != NULL);
+ LWIP_ASSERT("wireguardif_network_rx: invalid pbuf", p != NULL);
+ // We have received a packet from the base_netif to our UDP port - process this as a possible Wireguard packet
+ struct wireguard_device *device = (struct wireguard_device *)arg;
+ struct wireguard_peer *peer;
+ uint8_t *data = p->payload;
+ size_t len = p->len; // This buf, not chained ones
+
+ struct message_handshake_initiation *msg_initiation;
+ struct message_handshake_response *msg_response;
+ struct message_cookie_reply *msg_cookie;
+ struct message_transport_data *msg_data;
+
+ uint8_t type = wireguard_get_message_type(data, len);
+ ESP_LOGV(TAG, "network_rx: %08x:%d", addr->u_addr.ip4.addr, port);
+
+ switch (type) {
+ case MESSAGE_HANDSHAKE_INITIATION:
+ msg_initiation = (struct message_handshake_initiation *)data;
+ log_i(TAG "HANDSHAKE_INITIATION: %08x:%d", addr->u_addr.ip4.addr, port);
+ // Check mac1 (and optionally mac2) are correct - note it may internally generate a cookie reply packet
+ if (wireguardif_check_initiation_message(device, msg_initiation, addr, port)) {
+
+ peer = wireguard_process_initiation_message(device, msg_initiation);
+ if (peer) {
+ // Update the peer location
+ update_peer_addr(peer, addr, port);
+
+ // Send back a handshake response
+ wireguardif_send_handshake_response(device, peer);
+ }
+ }
+ break;
+
+ case MESSAGE_HANDSHAKE_RESPONSE:
+ log_i(TAG "HANDSHAKE_RESPONSE: %08x:%d", addr->u_addr.ip4.addr, port);
+ msg_response = (struct message_handshake_response *)data;
+
+ // Check mac1 (and optionally mac2) are correct - note it may internally generate a cookie reply packet
+ if (wireguardif_check_response_message(device, msg_response, addr, port)) {
+
+ peer = peer_lookup_by_handshake(device, msg_response->receiver);
+ if (peer) {
+ // Process the handshake response
+ wireguardif_process_response_message(device, peer, msg_response, addr, port);
+ }
+ }
+ break;
+
+ case MESSAGE_COOKIE_REPLY:
+ log_i(TAG "COOKIE_REPLY: %08x:%d", addr->u_addr.ip4.addr, port);
+ msg_cookie = (struct message_cookie_reply *)data;
+ peer = peer_lookup_by_handshake(device, msg_cookie->receiver);
+ if (peer) {
+ if (wireguard_process_cookie_message(device, peer, msg_cookie)) {
+ // Update the peer location
+ update_peer_addr(peer, addr, port);
+
+ // Don't send anything out - we stay quiet until the next initiation message
+ }
+ }
+ break;
+
+ case MESSAGE_TRANSPORT_DATA:
+ ESP_LOGV(TAG, "TRANSPORT_DATA: %08x:%d", addr->u_addr.ip4.addr, port);
+
+ msg_data = (struct message_transport_data *)data;
+ peer = peer_lookup_by_receiver(device, msg_data->receiver);
+ if (peer) {
+ // header is 16 bytes long so take that off the length
+ wireguardif_process_data_message(device, peer, msg_data, len - 16, addr, port);
+ }
+ break;
+
+ default:
+ // Unknown or bad packet header
+ break;
+ }
+ // Release data!
+ pbuf_free(p);
+}
+
+static err_t wireguard_start_handshake(struct netif *netif, struct wireguard_peer *peer) {
+ struct wireguard_device *device = (struct wireguard_device *)netif->state;
+ err_t result;
+ struct pbuf *pbuf;
+ struct message_handshake_initiation msg;
+
+ pbuf = wireguardif_initiate_handshake(device, peer, &msg, &result);
+ if (pbuf) {
+ result = wireguardif_peer_output(netif, pbuf, peer);
+ log_i(TAG "start handshake %08x,%d - %d", peer->ip.u_addr.ip4.addr, peer->port, result);
+ pbuf_free(pbuf);
+ peer->send_handshake = false;
+ peer->last_initiation_tx = wireguard_sys_now();
+ memcpy(peer->handshake_mac1, msg.mac1, WIREGUARD_COOKIE_LEN);
+ peer->handshake_mac1_valid = true;
+ }
+ return result;
+}
+
+static err_t wireguardif_lookup_peer(struct netif *netif, u8_t peer_index, struct wireguard_peer **out) {
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+ LWIP_ASSERT("state != NULL", (netif->state != NULL));
+ struct wireguard_device *device = (struct wireguard_device *)netif->state;
+ struct wireguard_peer *peer = NULL;
+ err_t result;
+
+ if (device->valid) {
+ peer = peer_lookup_by_peer_index(device, peer_index);
+ if (peer) {
+ result = ERR_OK;
+ } else {
+ result = ERR_ARG;
+ }
+ } else {
+ result = ERR_ARG;
+ }
+ *out = peer;
+ return result;
+}
+
+err_t wireguardif_connect(struct netif *netif, u8_t peer_index) {
+ struct wireguard_peer *peer;
+ err_t result = wireguardif_lookup_peer(netif, peer_index, &peer);
+ if (result == ERR_OK) {
+ // Check that a valid connect ip and port have been set
+ if (!ip_addr_isany(&peer->connect_ip) && (peer->connect_port > 0)) {
+ // Set the flag that we want to try connecting
+ peer->active = true;
+ peer->ip = peer->connect_ip;
+ peer->port = peer->connect_port;
+ result = ERR_OK;
+ } else {
+ result = ERR_ARG;
+ }
+ }
+ return result;
+}
+
+err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index) {
+ struct wireguard_peer *peer;
+ err_t result = wireguardif_lookup_peer(netif, peer_index, &peer);
+ if (result == ERR_OK) {
+ // Set the flag that we want to try connecting
+ peer->active = false;
+ // Wipe out current keys
+ keypair_destroy(&peer->next_keypair);
+ keypair_destroy(&peer->curr_keypair);
+ keypair_destroy(&peer->prev_keypair);
+ result = ERR_OK;
+ }
+ return result;
+}
+
+err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port) {
+ struct wireguard_peer *peer;
+ err_t result = wireguardif_lookup_peer(netif, peer_index, &peer);
+ if (result == ERR_OK) {
+ if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) {
+ result = ERR_OK;
+ } else {
+ result = ERR_CONN;
+ }
+ if (current_ip) {
+ *current_ip = peer->ip;
+ }
+ if (current_port) {
+ *current_port = peer->port;
+ }
+ }
+ return result;
+}
+
+err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index) {
+ struct wireguard_peer *peer;
+ err_t result = wireguardif_lookup_peer(netif, peer_index, &peer);
+ if (result == ERR_OK) {
+ crypto_zero(peer, sizeof(struct wireguard_peer));
+ peer->valid = false;
+ result = ERR_OK;
+ }
+ return result;
+}
+
+err_t wireguardif_update_endpoint(struct netif *netif, u8_t peer_index, const ip_addr_t *ip, u16_t port) {
+ struct wireguard_peer *peer;
+ err_t result = wireguardif_lookup_peer(netif, peer_index, &peer);
+ if (result == ERR_OK) {
+ peer->connect_ip = *ip;
+ peer->connect_port = port;
+ result = ERR_OK;
+ }
+ return result;
+}
+
+
+err_t wireguardif_add_peer(struct netif *netif, struct wireguardif_peer *p, u8_t *peer_index) {
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+ LWIP_ASSERT("state != NULL", (netif->state != NULL));
+ LWIP_ASSERT("p != NULL", (p != NULL));
+ struct wireguard_device *device = (struct wireguard_device *)netif->state;
+ err_t result;
+ uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN];
+ size_t public_key_len = sizeof(public_key);
+ struct wireguard_peer *peer = NULL;
+
+ uint32_t t1 = wireguard_sys_now();
+
+ if (wireguard_base64_decode(p->public_key, public_key, &public_key_len)
+ && (public_key_len == WIREGUARD_PUBLIC_KEY_LEN)) {
+
+ // See if the peer is already registered
+ peer = peer_lookup_by_pubkey(device, public_key);
+ if (!peer) {
+ // Not active - see if we have room to allocate a new one
+ peer = peer_alloc(device);
+ if (peer) {
+
+ if (wireguard_peer_init(device, peer, public_key, p->preshared_key)) {
+
+ peer->connect_ip = p->endpoint_ip;
+ peer->connect_port = p->endport_port;
+ peer->ip = peer->connect_ip;
+ peer->port = peer->connect_port;
+ if (p->keep_alive == WIREGUARDIF_KEEPALIVE_DEFAULT) {
+ peer->keepalive_interval = KEEPALIVE_TIMEOUT;
+ } else {
+ peer->keepalive_interval = p->keep_alive;
+ }
+ peer_add_ip(peer, p->allowed_ip, p->allowed_mask);
+ memcpy(peer->greatest_timestamp, p->greatest_timestamp, sizeof(peer->greatest_timestamp));
+
+ result = ERR_OK;
+ } else {
+ result = ERR_ARG;
+ }
+ } else {
+ result = ERR_MEM;
+ }
+ } else {
+ result = ERR_OK;
+ }
+ } else {
+ result = ERR_ARG;
+ }
+
+ uint32_t t2 = wireguard_sys_now();
+ log_i(TAG "Adding peer took %ums\r\n", (t2-t1));
+
+ if (peer_index) {
+ if (peer) {
+ *peer_index = wireguard_peer_index(device, peer);
+ } else {
+ *peer_index = WIREGUARDIF_INVALID_INDEX;
+ }
+ }
+ return result;
+}
+
+static bool should_send_initiation(struct wireguard_peer *peer) {
+ bool result = false;
+ if (wireguardif_can_send_initiation(peer)) {
+ if (peer->send_handshake) {
+ result = true;
+ } else if (peer->curr_keypair.valid && !peer->curr_keypair.initiator && wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME - peer->keepalive_interval)) {
+ result = true;
+ } else if (!peer->curr_keypair.valid && peer->active) {
+ result = true;
+ }
+ }
+ return result;
+}
+
+static bool should_send_keepalive(struct wireguard_peer *peer) {
+ bool result = false;
+ if (peer->keepalive_interval > 0) {
+ if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) {
+ if (wireguard_expired(peer->last_tx, peer->keepalive_interval)) {
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+static bool should_destroy_current_keypair(struct wireguard_peer *peer) {
+ bool result = false;
+ if (peer->curr_keypair.valid &&
+ (wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME) ||
+ (peer->curr_keypair.sending_counter >= REJECT_AFTER_MESSAGES))
+ ) {
+ result = true;
+ }
+ return result;
+}
+
+static bool should_reset_peer(struct wireguard_peer *peer) {
+ bool result = false;
+ if (peer->curr_keypair.valid && (wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME * 3))) {
+ result = true;
+ }
+ return result;
+}
+
+static void wireguardif_tmr(void *arg) {
+ struct wireguard_device *device = (struct wireguard_device *)arg;
+ struct wireguard_peer *peer;
+ int x;
+ // Reschedule this timer
+ sys_timeout(WIREGUARDIF_TIMER_MSECS, wireguardif_tmr, device);
+
+ // Check periodic things
+ bool link_up = false;
+ for (x=0; x < WIREGUARD_MAX_PEERS; x++) {
+ peer = &device->peers[x];
+ if (peer->valid) {
+ // Do we need to rekey / send a handshake?
+ if (should_reset_peer(peer)) {
+ // Nothing back for too long - we should wipe out all crypto state
+ keypair_destroy(&peer->next_keypair);
+ keypair_destroy(&peer->curr_keypair);
+ keypair_destroy(&peer->prev_keypair);
+ handshake_destroy(&peer->handshake);
+
+ // Revert back to default IP/port if these were altered
+ peer->ip = peer->connect_ip;
+ peer->port = peer->connect_port;
+ }
+ if (should_destroy_current_keypair(peer)) {
+ // Destroy current keypair
+ keypair_destroy(&peer->curr_keypair);
+ }
+ if (should_send_keepalive(peer)) {
+ wireguardif_send_keepalive(device, peer);
+ }
+ if (should_send_initiation(peer)) {
+ wireguard_start_handshake(device->netif, peer);
+ }
+
+ if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) {
+ link_up = true;
+ }
+ }
+ }
+
+ if (!link_up) {
+ // Clear the IF-UP flag on netif
+ netif_set_link_down(device->netif);
+ }
+}
+
+void wireguardif_shutdown(struct netif *netif) {
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+ LWIP_ASSERT("state != NULL", (netif->state != NULL));
+
+ struct wireguard_device * device = (struct wireguard_device *)netif->state;
+ // Disable timer.
+ sys_untimeout(wireguardif_tmr, device);
+ // remove UDP context.
+ if( device->udp_pcb ) {
+ udp_disconnect(device->udp_pcb);
+ udp_remove(device->udp_pcb);
+ device->udp_pcb = NULL;
+ }
+ // remove device context.
+ free(device);
+ netif->state = NULL;
+}
+
+err_t wireguardif_init(struct netif *netif) {
+ err_t result;
+ struct wireguardif_init_data *init_data;
+ struct wireguard_device *device;
+ struct udp_pcb *udp;
+ uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN];
+ size_t private_key_len = sizeof(private_key);
+
+ struct netif* underlying_netif;
+ tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, (void **)&underlying_netif);
+ log_i(TAG "underlying_netif = %p", underlying_netif);
+
+ LWIP_ASSERT("netif != NULL", (netif != NULL));
+ LWIP_ASSERT("state != NULL", (netif->state != NULL));
+
+ // We need to initialise the wireguard module
+ wireguard_init();
+ log_i(TAG "wireguard module initialized.");
+
+ if (netif && netif->state) {
+
+ // The init data is passed into the netif_add call as the 'state' - we will replace this with our private state data
+ init_data = (struct wireguardif_init_data *)netif->state;
+
+ // Clear out and set if function is successful
+ netif->state = NULL;
+
+ if (wireguard_base64_decode(init_data->private_key, private_key, &private_key_len)
+ && (private_key_len == WIREGUARD_PRIVATE_KEY_LEN)) {
+
+ udp = udp_new();
+
+ if (udp) {
+ result = udp_bind(udp, IP_ADDR_ANY, init_data->listen_port); // Note this listens on all interfaces! Really just want the passed netif
+ if (result == ERR_OK) {
+ device = (struct wireguard_device *)mem_calloc(1, sizeof(struct wireguard_device));
+ if (device) {
+ device->netif = netif;
+ device->underlying_netif = underlying_netif;
+ //udp_bind_netif(udp, underlying_netif);
+
+ device->udp_pcb = udp;
+ log_d(TAG "start device initialization");
+ // Per-wireguard netif/device setup
+ uint32_t t1 = wireguard_sys_now();
+ if (wireguard_device_init(device, private_key)) {
+ uint32_t t2 = wireguard_sys_now();
+ log_d(TAG "Device init took %ums\r\n", (t2-t1));
+
+#if LWIP_CHECKSUM_CTRL_PER_NETIF
+ NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL);
+#endif
+ netif->state = device;
+ netif->name[0] = 'w';
+ netif->name[1] = 'g';
+ netif->output = wireguardif_output;
+ netif->linkoutput = NULL;
+ netif->hwaddr_len = 0;
+ netif->mtu = WIREGUARDIF_MTU;
+ // We set up no state flags here - caller should set them
+ // NETIF_FLAG_LINK_UP is automatically set/cleared when at least one peer is connected
+ netif->flags = 0;
+
+ udp_recv(udp, wireguardif_network_rx, device);
+
+ // Start a periodic timer for this wireguard device
+ sys_timeout(WIREGUARDIF_TIMER_MSECS, wireguardif_tmr, device);
+
+ result = ERR_OK;
+ } else {
+ log_e(TAG "failed to initialize WireGuard device.");
+ mem_free(device);
+ device = NULL;
+ udp_remove(udp);
+ result = ERR_ARG;
+ }
+ } else {
+ log_e(TAG "failed to allocate device context.");
+ udp_remove(udp);
+ result = ERR_MEM;
+ }
+ } else {
+ log_e(TAG "failed to bind UDP err=%d", result);
+ udp_remove(udp);
+ }
+
+ } else {
+ log_e(TAG "failed to allocate UDP");
+ result = ERR_MEM;
+ }
+ } else {
+ log_e(TAG "invalid init_data private key");
+ result = ERR_ARG;
+ }
+ } else {
+ log_e(TAG "netif or state is NULL: netif=%p, netif.state:%p", netif, netif ? netif->state : NULL);
+ result = ERR_ARG;
+ }
+ return result;
+}
+
+void wireguardif_peer_init(struct wireguardif_peer *peer) {
+ LWIP_ASSERT("peer != NULL", (peer != NULL));
+ memset(peer, 0, sizeof(struct wireguardif_peer));
+ // Caller must provide 'public_key'
+ peer->public_key = NULL;
+ ip_addr_set_any(false, &peer->endpoint_ip);
+ peer->endport_port = WIREGUARDIF_DEFAULT_PORT;
+ peer->keep_alive = WIREGUARDIF_KEEPALIVE_DEFAULT;
+ ip_addr_set_any(false, &peer->allowed_ip);
+ ip_addr_set_any(false, &peer->allowed_mask);
+ memset(peer->greatest_timestamp, 0, sizeof(peer->greatest_timestamp));
+ peer->preshared_key = NULL;
+}
diff --git a/lib/WireGuard-ESP32/src/wireguardif.h b/lib/WireGuard-ESP32/src/wireguardif.h
new file mode 100644
index 00000000..ad9d4a15
--- /dev/null
+++ b/lib/WireGuard-ESP32/src/wireguardif.h
@@ -0,0 +1,137 @@
+/*
+ * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org)
+ * The original license is below:
+ *
+ * Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
+ * All rights reserved.
+ *
+ * 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, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Daniel Hope
+ */
+
+
+#ifndef _WIREGUARDIF_H_
+#define _WIREGUARDIF_H_
+
+#include "lwip/arch.h"
+#include "lwip/netif.h"
+#include "lwip/ip_addr.h"
+
+// Default MTU for WireGuard is 1420 bytes
+#define WIREGUARDIF_MTU (1420)
+
+#define WIREGUARDIF_DEFAULT_PORT (51820)
+#define WIREGUARDIF_KEEPALIVE_DEFAULT (0xFFFF)
+
+struct wireguardif_init_data {
+ // Required: the private key of this WireGuard network interface
+ const char *private_key;
+ // Required: What UDP port to listen on
+ u16_t listen_port;
+ // Optional: restrict send/receive of encapsulated WireGuard traffic to this network interface only (NULL to use routing table)
+ struct netif *bind_netif;
+};
+
+struct wireguardif_peer {
+ const char *public_key;
+ // Optional pre-shared key (32 bytes) - make sure this is NULL if not to be used
+ const uint8_t *preshared_key;
+ // tai64n of largest timestamp we have seen during handshake to avoid replays
+ uint8_t greatest_timestamp[12];
+
+ // Allowed ip/netmask (can add additional later but at least one is required)
+ ip_addr_t allowed_ip;
+ ip_addr_t allowed_mask;
+
+ // End-point details (may be blank)
+ ip_addr_t endpoint_ip;
+ u16_t endport_port;
+ u16_t keep_alive;
+};
+
+#define WIREGUARDIF_INVALID_INDEX (0xFF)
+
+/* static struct netif wg_netif_struct = {0};
+ * struct wireguard_interface wg;
+ * wg.private_key = "abcdefxxx..xxxxx=";
+ * wg.listen_port = 51820;
+ * wg.bind_netif = NULL; // Pass netif to listen on, NULL for all interfaces
+ *
+ * netif = netif_add(&netif_struct, &ipaddr, &netmask, &gateway, &wg, &wireguardif_init, &ip_input);
+ *
+ * netif_set_up(wg_net);
+ *
+ * struct wireguardif_peer peer;
+ * wireguardif_peer_init(&peer);
+ * peer.public_key = "apoehc...4322abcdfejg=;
+ * peer.preshared_key = NULL;
+ * peer.allowed_ip = allowed_ip;
+ * peer.allowed_mask = allowed_mask;
+ *
+ * // If you want to enable output connection
+ * peer.endpoint_ip = peer_ip;
+ * peer.endport_port = 12345;
+ *
+ * uint8_t wireguard_peer_index;
+ * wireguardif_add_peer(netif, &peer, &wireguard_peer_index);
+ *
+ * if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) {
+ * // Start outbound connection to peer
+ * wireguardif_connect(wg_net, wireguard_peer_index);
+ * }
+ *
+ */
+
+// Initialise a new WireGuard network interface (netif)
+err_t wireguardif_init(struct netif *netif);
+
+// Shutdown a WireGuard network interface (netif)
+void wireguardif_shutdown(struct netif *netif);
+
+// Helper to initialise the peer struct with defaults
+void wireguardif_peer_init(struct wireguardif_peer *peer);
+
+// Add a new peer to the specified interface - see wireguard.h for maximum number of peers allowed
+// On success the peer_index can be used to reference this peer in future function calls
+err_t wireguardif_add_peer(struct netif *netif, struct wireguardif_peer *peer, u8_t *peer_index);
+
+// Remove the given peer from the network interface
+err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index);
+
+// Update the "connect" IP of the given peer
+err_t wireguardif_update_endpoint(struct netif *netif, u8_t peer_index, const ip_addr_t *ip, u16_t port);
+
+// Try and connect to the given peer
+err_t wireguardif_connect(struct netif *netif, u8_t peer_index);
+
+// Stop trying to connect to the given peer
+err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index);
+
+// Is the given peer "up"? A peer is up if it has a valid session key it can communicate with
+err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port);
+
+#endif /* _WIREGUARDIF_H_ */
diff --git a/lib/lv_lib_zifont/lv_zifont.cpp b/lib/lv_lib_zifont/lv_zifont.cpp
index 43f7e340..7a3b7977 100644
--- a/lib/lv_lib_zifont/lv_zifont.cpp
+++ b/lib/lv_lib_zifont/lv_zifont.cpp
@@ -1,11 +1,11 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/*********************
* INCLUDES
*********************/
-#if !(defined(WINDOWS) || defined(POSIX) || defined(STM32F7xx))
+#if !(HASP_TARGET_PC || defined(STM32F7xx))
#include
#include
diff --git a/lib/lv_lib_zifont/lv_zifont.h b/lib/lv_lib_zifont/lv_zifont.h
index 31090b59..a5d5e7f2 100644
--- a/lib/lv_lib_zifont/lv_zifont.h
+++ b/lib/lv_lib_zifont/lv_zifont.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef LV_ZIFONT_H
diff --git a/platformio.ini b/platformio.ini
index 3aa92a4b..05f259ea 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -1,4 +1,4 @@
-; MIT License - Copyright (c) 2019-2023 Francis Van Roie
+; MIT License - Copyright (c) 2019-2024 Francis Van Roie
; For full license information read the LICENSE file in the project folder
;
; PlatformIO Project Configuration File
@@ -75,14 +75,14 @@ build_flags =
-D HASP_VER_MAJ=0
-D HASP_VER_MIN=7
;-D HASP_VER_REV=4
- -D HASP_VER_REV=0-rc8
+ -D HASP_VER_REV=0-rc11
;-D HASP_VER_REV=4-rc1
${override.build_flags}
; -- Shared library dependencies in all environments
; Warning : don't put comments after github links => causes infinite download loop
lib_deps =
- bblanchon/ArduinoJson@^6.21.3
+ bblanchon/ArduinoJson@^6.21.5
;git+https://github.com/fvanroie/ConsoleInput.git
;git+https://github.com/andrethomas/TasmotaSlave.git
;git+https://github.com/lvgl/lvgl.git
@@ -104,16 +104,16 @@ build_src_filter = +<*> -<.git/> - - - - -
#endif
#if defined(POSIX)
@@ -30,6 +30,9 @@ class BaseDevice {
public:
bool has_battery = false;
bool has_backligth_control = true;
+#if HASP_TARGET_PC
+ bool pc_is_running = true;
+#endif
virtual void reboot()
{}
diff --git a/src/dev/esp32/esp32.cpp b/src/dev/esp32/esp32.cpp
index 88d34460..3882c53d 100644
--- a/src/dev/esp32/esp32.cpp
+++ b/src/dev/esp32/esp32.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(ESP32)
@@ -9,6 +9,7 @@
#include "esp_system.h"
#include // needed to get the ResetInfo
#include "driver/adc.h"
+#include "driver/ledc.h"
#include "esp_adc_cal.h"
#include "esp_efuse.h"
@@ -109,6 +110,8 @@ Esp32Device::Esp32Device()
_backlight_power = 1;
_backlight_level = 255;
_backlight_pin = 255; // not TFT_BCKL because it is unknown at this stage
+ _backlight_pending = false;
+ _backlight_fading = false;
/* fill unique identifier with wifi mac */
byte mac[6];
@@ -240,6 +243,22 @@ const char* Esp32Device::get_hardware_id()
return _hardware_id.c_str();
}
+bool Esp32Device::cb_backlight(const ledc_cb_param_t *param, void *user_arg) {
+ reinterpret_cast(user_arg)->end_backlight_fade();
+ return false;
+}
+
+void Esp32Device::end_backlight_fade()
+{
+ if (_backlight_pending) {
+ _backlight_pending = false;
+ _backlight_fading = false;
+ update_backlight(_backlight_fade);
+ } else {
+ _backlight_fading = false;
+ }
+}
+
void Esp32Device::set_backlight_pin(uint8_t pin)
{
_backlight_pin = pin;
@@ -253,7 +272,10 @@ void Esp32Device::set_backlight_pin(uint8_t pin)
ledcSetup(BACKLIGHT_CHANNEL, BACKLIGHT_FREQUENCY, 10);
#endif
ledcAttachPin(pin, BACKLIGHT_CHANNEL);
- update_backlight();
+ ledc_fade_func_install(0);
+ ledc_cbs_t cbs = {cb_backlight};
+ ledc_cb_register(LEDC_LOW_SPEED_MODE, (ledc_channel_t) BACKLIGHT_CHANNEL, &cbs, this);
+ update_backlight(false);
} else {
LOG_VERBOSE(TAG_GUI, F("Backlight : Pin not set"));
}
@@ -262,7 +284,7 @@ void Esp32Device::set_backlight_pin(uint8_t pin)
void Esp32Device::set_backlight_invert(bool invert)
{
_backlight_invert = invert;
- update_backlight();
+ update_backlight(false);
}
bool Esp32Device::get_backlight_invert()
@@ -273,7 +295,7 @@ bool Esp32Device::get_backlight_invert()
void Esp32Device::set_backlight_level(uint8_t level)
{
_backlight_level = level;
- update_backlight();
+ update_backlight(false);
}
uint8_t Esp32Device::get_backlight_level()
@@ -284,7 +306,7 @@ uint8_t Esp32Device::get_backlight_level()
void Esp32Device::set_backlight_power(bool power)
{
_backlight_power = power;
- update_backlight();
+ update_backlight(false);
}
bool Esp32Device::get_backlight_power()
@@ -292,17 +314,37 @@ bool Esp32Device::get_backlight_power()
return _backlight_power != 0;
}
-void Esp32Device::update_backlight()
+void Esp32Device::update_backlight(bool fade)
{
if(_backlight_pin < GPIO_NUM_MAX) {
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
uint32_t duty = _backlight_power ? map(_backlight_level, 0, 255, 0, 1023) : 0;
if(_backlight_invert) duty = 1023 - duty;
- ledcWrite(BACKLIGHT_CHANNEL, duty); // ledChannel and value
+ if(_backlight_fading) {
+ _backlight_fade = fade;
+ _backlight_pending = true;
+ } else {
+ if(fade) {
+ _backlight_fading = true;
+ ledc_set_fade_time_and_start(LEDC_LOW_SPEED_MODE, (ledc_channel_t) BACKLIGHT_CHANNEL, duty, BACKLIGHT_FADEMS, LEDC_FADE_NO_WAIT);
+ } else {
+ ledcWrite(BACKLIGHT_CHANNEL, duty); // ledChannel and value
+ }
+ }
#else
uint32_t duty = _backlight_power ? map(_backlight_level, 0, 255, 0, 1023) : 0;
if(_backlight_invert) duty = 1023 - duty;
- ledcWrite(BACKLIGHT_CHANNEL, duty); // ledChannel and value
+ if(_backlight_fading) {
+ _backlight_fade = fade;
+ _backlight_pending = true;
+ } else {
+ if(fade) {
+ _backlight_fading = true;
+ ledc_set_fade_time_and_start(LEDC_LOW_SPEED_MODE, (ledc_channel_t) BACKLIGHT_CHANNEL, duty, BACKLIGHT_FADEMS, LEDC_FADE_NO_WAIT);
+ } else {
+ ledcWrite(BACKLIGHT_CHANNEL, duty); // ledChannel and value
+ }
+ }
#endif
}
diff --git a/src/dev/esp32/esp32.h b/src/dev/esp32/esp32.h
index 7dec242d..825a0eea 100644
--- a/src/dev/esp32/esp32.h
+++ b/src/dev/esp32/esp32.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DEVICE_ESP32_H
@@ -8,11 +8,14 @@
#include "../device.h"
#if defined(ESP32)
+#include "driver/ledc.h"
#ifndef BACKLIGHT_FREQUENCY
#define BACKLIGHT_FREQUENCY 20000
#endif
+#define BACKLIGHT_FADEMS 200
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -66,8 +69,13 @@ class Esp32Device : public BaseDevice {
uint8_t _backlight_level;
uint8_t _backlight_power;
uint8_t _backlight_invert;
+ bool _backlight_pending;
+ bool _backlight_fading;
+ bool _backlight_fade;
- void update_backlight();
+ void update_backlight(bool fade);
+ static bool cb_backlight(const ledc_cb_param_t *param, void *user_arg);
+ void end_backlight_fade();
};
} // namespace dev
diff --git a/src/dev/esp32/lanbonl8.cpp b/src/dev/esp32/lanbonl8.cpp
index 5104c7ba..be5513a5 100644
--- a/src/dev/esp32/lanbonl8.cpp
+++ b/src/dev/esp32/lanbonl8.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "lanbonl8.h"
diff --git a/src/dev/esp32/lanbonl8.h b/src/dev/esp32/lanbonl8.h
index 5f4ed667..79e1a691 100644
--- a/src/dev/esp32/lanbonl8.h
+++ b/src/dev/esp32/lanbonl8.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DEVICE_LANBONL8_H
diff --git a/src/dev/esp8266/esp8266.cpp b/src/dev/esp8266/esp8266.cpp
index be671830..a18d74e9 100644
--- a/src/dev/esp8266/esp8266.cpp
+++ b/src/dev/esp8266/esp8266.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(ESP8266)
diff --git a/src/dev/esp8266/esp8266.h b/src/dev/esp8266/esp8266.h
index 04087798..0f295424 100644
--- a/src/dev/esp8266/esp8266.h
+++ b/src/dev/esp8266/esp8266.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DEVICE_ESP8266_H
diff --git a/src/dev/posix/hasp_posix.cpp b/src/dev/posix/hasp_posix.cpp
index a70ff4e2..1e779b2e 100644
--- a/src/dev/posix/hasp_posix.cpp
+++ b/src/dev/posix/hasp_posix.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(POSIX)
@@ -19,7 +19,15 @@
#include "hasp_conf.h"
#include "hasp_debug.h"
+#ifdef USE_MONITOR
#include "display/monitor.h"
+#elif USE_FBDEV
+#include "display/fbdev.h"
+#include "drv/tft/tft_driver.h"
+#endif
+
+#include
+#include
// extern monitor_t monitor;
@@ -35,12 +43,6 @@ PosixDevice::PosixDevice()
_core_version = "unknown";
_chip_model = "unknown";
} else {
- // LOG_VERBOSE(0,"Sysname: %s", uts.sysname);
- // LOG_VERBOSE(0,"Nodename: %s", uts.nodename);
- // LOG_VERBOSE(0,"Release: %s", uts.release);
- // LOG_VERBOSE(0,"Version: %s", uts.version);
- // LOG_VERBOSE(0,"Machine: %s", uts.machine);
-
char version[256];
snprintf(version, sizeof(version), "%s %s", uts.sysname, uts.release);
_core_version = version;
@@ -53,6 +55,32 @@ PosixDevice::PosixDevice()
_backlight_level = 255;
}
+void PosixDevice::set_config(const JsonObject& settings)
+{
+ configOutput(settings, 0);
+#if USE_FBDEV
+ if(settings["fbdev"].is()) {
+ haspTft.fbdev_path = "/dev/" + settings["fbdev"].as();
+ }
+#if USE_EVDEV
+ if(settings["evdev"].is()) {
+ haspTft.evdev_names.push_back(settings["evdev"].as());
+ }
+ if(settings["evdevs"].is()) {
+ for(auto v : settings["evdevs"].as()) {
+ haspTft.evdev_names.push_back(v.as());
+ }
+ }
+#endif
+ if(settings["bldev"].is()) {
+ haspDevice.backlight_device = settings["bldev"].as();
+ }
+ if(settings["blmax"].is()) {
+ haspDevice.backlight_max = settings["blmax"];
+ }
+#endif
+}
+
void PosixDevice::reboot()
{}
void PosixDevice::show_info()
@@ -62,15 +90,16 @@ void PosixDevice::show_info()
if(uname(&uts) < 0) {
LOG_ERROR(0, "uname() error");
} else {
- LOG_VERBOSE(0, "Sysname: %s", uts.sysname);
- LOG_VERBOSE(0, "Nodename: %s", uts.nodename);
- LOG_VERBOSE(0, "Release: %s", uts.release);
- LOG_VERBOSE(0, "Version: %s", uts.version);
- LOG_VERBOSE(0, "Machine: %s", uts.machine);
+ LOG_VERBOSE(0, "Sysname : %s", uts.sysname);
+ LOG_VERBOSE(0, "Nodename : %s", uts.nodename);
+ LOG_VERBOSE(0, "Release : %s", uts.release);
+ LOG_VERBOSE(0, "Version : %s", uts.version);
+ LOG_VERBOSE(0, "Machine : %s", uts.machine);
}
- LOG_VERBOSE(0, "Processor : %s", "unknown");
- LOG_VERBOSE(0, "CPU freq. : %i MHz", 0);
+ LOG_VERBOSE(0, "Processor : %s", get_chip_model());
+ LOG_VERBOSE(0, "CPU freq. : %i MHz", get_cpu_frequency());
+ LOG_VERBOSE(0, "OS Version : %s", get_core_version());
}
const char* PosixDevice::get_hostname()
@@ -81,8 +110,11 @@ const char* PosixDevice::get_hostname()
void PosixDevice::set_hostname(const char* hostname)
{
_hostname = hostname;
+#if USE_MONITOR
monitor_title(hostname);
- // SDL_SetWindowTitle(monitor.window, hostname);
+#elif USE_FBDEV
+ // fbdev doesn't really have a title bar
+#endif
}
const char* PosixDevice::get_core_version()
@@ -146,13 +178,35 @@ void PosixDevice::update_backlight()
{
uint8_t level = _backlight_power ? _backlight_level : 0;
if(_backlight_invert) level = 255 - level;
+#if USE_MONITOR
monitor_backlight(level);
- // SDL_SetTextureColorMod(monitor.texture, level, level, level);
- // window_update(&monitor);
- // monitor.sdl_refr_qry = true;
- // monitor_sdl_refr(NULL);
- // const lv_area_t area = {1,1,0,0};
- // monitor_flush(NULL,&area,NULL);
+#elif USE_FBDEV
+ // set display backlight, if possible
+ if(backlight_device != "") {
+ if(backlight_max == 0) {
+ std::ifstream f;
+ f.open("/sys/class/backlight/" + backlight_device + "/max_brightness");
+ if(!f.fail()) {
+ f >> backlight_max;
+ f.close();
+ } else {
+ perror("Max brightness read failed");
+ }
+ }
+
+ int brightness = map(level, 0, 255, 0, backlight_max);
+ LOG_VERBOSE(0, "Setting brightness to %d/255 (%d)", level, brightness);
+
+ std::ofstream f;
+ f.open("/sys/class/backlight/" + backlight_device + "/brightness");
+ if(!f.fail()) {
+ f << brightness;
+ f.close();
+ } else {
+ perror("Brightness write failed (are you root?)");
+ }
+ }
+#endif
}
size_t PosixDevice::get_free_max_block()
@@ -192,6 +246,12 @@ bool PosixDevice::is_system_pin(uint8_t pin)
return false;
}
+void PosixDevice::run_thread(void (*func)(void*), void* arg)
+{
+ pthread_t thread;
+ pthread_create(&thread, NULL, (void* (*)(void*))func, arg);
+}
+
#ifndef TARGET_OS_MAC
long PosixDevice::get_uptime()
{
@@ -221,6 +281,25 @@ long PosixDevice::get_uptime()
} // namespace dev
+static time_t tv_sec_start = 0;
+
+unsigned long PosixMillis()
+{
+ struct timespec spec;
+ clock_gettime(CLOCK_REALTIME, &spec);
+ if(tv_sec_start == 0) {
+ tv_sec_start = spec.tv_sec;
+ }
+ unsigned long msec1 = (spec.tv_sec - tv_sec_start) * 1000;
+ unsigned long msec2 = spec.tv_nsec / 1e6;
+ return msec1 + msec2;
+}
+
+void msleep(unsigned long millis)
+{
+ usleep(millis * 1000);
+}
+
dev::PosixDevice haspDevice;
#endif // POSIX
diff --git a/src/dev/posix/hasp_posix.h b/src/dev/posix/hasp_posix.h
index 9dc8ad9f..70f62695 100644
--- a/src/dev/posix/hasp_posix.h
+++ b/src/dev/posix/hasp_posix.h
@@ -31,6 +31,8 @@ class PosixDevice : public BaseDevice {
public:
PosixDevice();
+ void set_config(const JsonObject& settings);
+
void reboot() override;
void show_info() override;
@@ -56,6 +58,12 @@ class PosixDevice : public BaseDevice {
bool is_system_pin(uint8_t pin) override;
+ void run_thread(void (*func)(void*), void* arg);
+
+ public:
+ std::string backlight_device;
+ int backlight_max = 0;
+
private:
std::string _hostname;
std::string _core_version;
@@ -71,6 +79,9 @@ class PosixDevice : public BaseDevice {
} // namespace dev
+extern unsigned long PosixMillis();
+extern void msleep(unsigned long millis);
+
using dev::PosixDevice;
extern dev::PosixDevice haspDevice;
diff --git a/src/dev/stm32f4/stm32f4.cpp b/src/dev/stm32f4/stm32f4.cpp
index d735891a..7a007aba 100644
--- a/src/dev/stm32f4/stm32f4.cpp
+++ b/src/dev/stm32f4/stm32f4.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(STM32F4xx)
diff --git a/src/dev/stm32f4/stm32f4.h b/src/dev/stm32f4/stm32f4.h
index 89af1699..2b4822d3 100644
--- a/src/dev/stm32f4/stm32f4.h
+++ b/src/dev/stm32f4/stm32f4.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DEVICE_STM32F4_H
diff --git a/src/dev/stm32f7/stm32f7.cpp b/src/dev/stm32f7/stm32f7.cpp
index 11497812..288d5594 100644
--- a/src/dev/stm32f7/stm32f7.cpp
+++ b/src/dev/stm32f7/stm32f7.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(STM32F7xx)
diff --git a/src/dev/stm32f7/stm32f7.h b/src/dev/stm32f7/stm32f7.h
index 1254acb5..8ae7079c 100644
--- a/src/dev/stm32f7/stm32f7.h
+++ b/src/dev/stm32f7/stm32f7.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DEVICE_STM32F4_H
diff --git a/src/dev/win32/hasp_win32.cpp b/src/dev/win32/hasp_win32.cpp
index 61fce87d..985a3e68 100644
--- a/src/dev/win32/hasp_win32.cpp
+++ b/src/dev/win32/hasp_win32.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(WINDOWS)
@@ -11,7 +11,11 @@
#include "hasp_conf.h"
#include "hasp_debug.h"
+#if USE_MONITOR
#include "display/monitor.h"
+#elif USE_WIN32DRV
+#include "win32drv/win32drv.h"
+#endif
namespace dev {
@@ -21,11 +25,33 @@ static inline void native_cpuid(unsigned int* eax, unsigned int* ebx, unsigned i
asm volatile("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "0"(*eax), "2"(*ecx) : "memory");
}
-void Win32Device::reboot()
-{}
-
-void Win32Device::show_info()
+Win32Device::Win32Device()
{
+ char buffer[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD length = sizeof(buffer);
+
+ if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameNetBIOS, buffer, &length)) {
+ _hostname = buffer;
+ } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameDnsHostname, buffer, &length)) {
+ _hostname = buffer;
+ } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsHostname, buffer, &length)) {
+ _hostname = buffer;
+ } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsDomain, buffer, &length)) {
+ _hostname = buffer;
+ } else {
+ _hostname = "localhost";
+ }
+
+ // Get the Windows version.
+ DWORD dwBuild = 0;
+ DWORD dwVersion = GetVersion();
+ DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
+ DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
+ if(dwVersion < 0x80000000) dwBuild = (DWORD)(HIWORD(dwVersion));
+
+ char version[128];
+ snprintf(version, sizeof(version), "Windows %d.%d.%d", dwMajorVersion, dwMinorVersion, dwBuild);
+ _core_version = version;
unsigned int eax, ebx, ecx, edx;
eax = 0;
@@ -35,10 +61,23 @@ void Win32Device::show_info()
memcpy(vendor, &ebx, 4);
memcpy(vendor + 4, &edx, 4);
memcpy(vendor + 8, &ecx, 4);
- vendor[12] = '\0';
+ vendor[12] = '\0';
+ _chip_model = vendor;
- LOG_VERBOSE(0, F("Processor : %s"), vendor);
+ // _backlight_pin = -1;
+ _backlight_power = 1;
+ _backlight_invert = 0;
+ _backlight_level = 255;
+}
+
+void Win32Device::reboot()
+{}
+
+void Win32Device::show_info()
+{
+ LOG_VERBOSE(0, F("Processor : %s"), get_chip_model());
LOG_VERBOSE(0, F("CPU freq. : %i MHz"), get_cpu_frequency());
+ LOG_VERBOSE(0, F("OS Version : %s"), get_core_version());
}
const char* Win32Device::get_hostname()
@@ -48,8 +87,11 @@ const char* Win32Device::get_hostname()
void Win32Device::set_hostname(const char* hostname)
{
_hostname = hostname;
+#if USE_MONITOR
monitor_title(hostname);
- // SDL_SetWindowTitle(monitor.window, hostname);
+#elif USE_WIN32DRV
+ lv_win32_set_title(hostname);
+#endif
}
const char* Win32Device::get_core_version()
{
@@ -58,7 +100,7 @@ const char* Win32Device::get_core_version()
const char* Win32Device::get_chip_model()
{
- return "SDL2";
+ return _chip_model.c_str();
}
const char* Win32Device::get_hardware_id()
@@ -112,7 +154,9 @@ void Win32Device::update_backlight()
{
uint8_t level = _backlight_power ? _backlight_level : 0;
if(_backlight_invert) level = 255 - level;
+#if USE_MONITOR
monitor_backlight(level);
+#endif
}
size_t Win32Device::get_free_max_block()
@@ -143,6 +187,11 @@ bool Win32Device::is_system_pin(uint8_t pin)
return false;
}
+void Win32Device::run_thread(void (*func)(void*), void* arg)
+{
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, NULL);
+}
+
long Win32Device::get_uptime()
{
return GetTickCount64() / 1000;
@@ -150,6 +199,11 @@ long Win32Device::get_uptime()
} // namespace dev
+long Win32Millis()
+{
+ return GetTickCount64();
+}
+
dev::Win32Device haspDevice;
-#endif // WINDOWS
\ No newline at end of file
+#endif // WINDOWS
diff --git a/src/dev/win32/hasp_win32.h b/src/dev/win32/hasp_win32.h
index 3c2edb23..a378b0bc 100644
--- a/src/dev/win32/hasp_win32.h
+++ b/src/dev/win32/hasp_win32.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DEVICE_WINDOWS_H
@@ -18,39 +18,7 @@ namespace dev {
class Win32Device : public BaseDevice {
public:
- Win32Device()
- {
- char buffer[MAX_COMPUTERNAME_LENGTH + 1];
- DWORD length = sizeof(buffer);
-
- if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameNetBIOS, buffer, &length)) {
- _hostname = buffer;
- } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNameDnsHostname, buffer, &length)) {
- _hostname = buffer;
- } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsHostname, buffer, &length)) {
- _hostname = buffer;
- } else if(GetComputerNameExA((COMPUTER_NAME_FORMAT)ComputerNamePhysicalDnsDomain, buffer, &length)) {
- _hostname = buffer;
- } else {
- _hostname = "localhost";
- }
-
- // Get the Windows version.
- DWORD dwBuild = 0;
- DWORD dwVersion = GetVersion();
- DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
- DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
- if(dwVersion < 0x80000000) dwBuild = (DWORD)(HIWORD(dwVersion));
-
- char version[128];
- snprintf(version, sizeof(version), "Windows %d.%d-%d", dwMajorVersion, dwMinorVersion, dwBuild);
- _core_version = version;
-
- // _backlight_pin = -1;
- _backlight_power = 1;
- _backlight_invert = 0;
- _backlight_level = 255;
- }
+ Win32Device();
void reboot() override;
void show_info() override;
@@ -77,9 +45,12 @@ class Win32Device : public BaseDevice {
bool is_system_pin(uint8_t pin) override;
+ void run_thread(void (*func)(void*), void* arg);
+
private:
std::string _hostname;
std::string _core_version;
+ std::string _chip_model;
uint8_t _backlight_pin;
uint8_t _backlight_level;
@@ -91,9 +62,11 @@ class Win32Device : public BaseDevice {
} // namespace dev
+extern long Win32Millis();
+
using dev::Win32Device;
extern dev::Win32Device haspDevice;
#endif // WINDOWS
-#endif // HASP_DEVICE_WINDOWS_H
\ No newline at end of file
+#endif // HASP_DEVICE_WINDOWS_H
diff --git a/src/drv/old/hasp_drv_ft5206.h b/src/drv/old/hasp_drv_ft5206.h
index ce25edaf..5d0ee0d7 100644
--- a/src/drv/old/hasp_drv_ft5206.h
+++ b/src/drv/old/hasp_drv_ft5206.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DRV_FT5206_H
diff --git a/src/drv/old/hasp_drv_ft6336u.h b/src/drv/old/hasp_drv_ft6336u.h
index e672651b..8a17726e 100644
--- a/src/drv/old/hasp_drv_ft6336u.h
+++ b/src/drv/old/hasp_drv_ft6336u.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DRV_FT6336U_H
diff --git a/src/drv/old/hasp_drv_gt911.h b/src/drv/old/hasp_drv_gt911.h
index 74d22fde..e95665a7 100644
--- a/src/drv/old/hasp_drv_gt911.h
+++ b/src/drv/old/hasp_drv_gt911.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/*
diff --git a/src/drv/old/hasp_drv_tft_espi.cpp b/src/drv/old/hasp_drv_tft_espi.cpp
index a27411bf..7d3e4bfa 100644
--- a/src/drv/old/hasp_drv_tft_espi.cpp
+++ b/src/drv/old/hasp_drv_tft_espi.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/*********************
diff --git a/src/drv/old/hasp_drv_tft_espi.h b/src/drv/old/hasp_drv_tft_espi.h
index faa00cd9..d3721b82 100644
--- a/src/drv/old/hasp_drv_tft_espi.h
+++ b/src/drv/old/hasp_drv_tft_espi.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef TFT_ESPI_DRV_H
diff --git a/src/drv/old/hasp_drv_touch.cpp b/src/drv/old/hasp_drv_touch.cpp
index ef4c7b93..b667f8d1 100644
--- a/src/drv/old/hasp_drv_touch.cpp
+++ b/src/drv/old/hasp_drv_touch.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
diff --git a/src/drv/old/hasp_drv_touch.h b/src/drv/old/hasp_drv_touch.h
index 237a6c47..b4fb398e 100644
--- a/src/drv/old/hasp_drv_touch.h
+++ b/src/drv/old/hasp_drv_touch.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DRV_TOUCH_H
diff --git a/src/drv/old/hasp_drv_xpt2046.h b/src/drv/old/hasp_drv_xpt2046.h
index 93889cb4..f00960db 100644
--- a/src/drv/old/hasp_drv_xpt2046.h
+++ b/src/drv/old/hasp_drv_xpt2046.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DRV_XPT2046B_H
diff --git a/src/drv/tft/tft_defines.h b/src/drv/tft/tft_defines.h
index b886f8f9..ab789682 100644
--- a/src/drv/tft/tft_defines.h
+++ b/src/drv/tft/tft_defines.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TFT_DEFINES_H
diff --git a/src/drv/tft/tft_driver.h b/src/drv/tft/tft_driver.h
index 913be18f..c8bed996 100644
--- a/src/drv/tft/tft_driver.h
+++ b/src/drv/tft/tft_driver.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_BASE_TFT_DRIVER_H
@@ -77,9 +77,15 @@ class BaseTft {
#elif defined(STM32F7)
#warning Building for STM32F7xx Tfts
#include "tft_driver_tftespi.h"
-#elif defined(WINDOWS) || defined(POSIX)
+#elif USE_MONITOR && HASP_TARGET_PC
// #warning Building for SDL2
#include "tft_driver_sdl2.h"
+#elif USE_WIN32DRV && HASP_TARGET_PC
+// #warning Building for Win32Drv
+#include "tft_driver_win32drv.h"
+#elif USE_FBDEV && HASP_TARGET_PC
+// #warning Building for POSIX fbdev
+#include "tft_driver_posix_fbdev.h"
#else
// #warning Building for Generic Tfts
using dev::BaseTft;
diff --git a/src/drv/tft/tft_driver_arduinogfx.cpp b/src/drv/tft/tft_driver_arduinogfx.cpp
index 69084b6a..c946120a 100644
--- a/src/drv/tft/tft_driver_arduinogfx.cpp
+++ b/src/drv/tft/tft_driver_arduinogfx.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(ARDUINO) && defined(HASP_USE_ARDUINOGFX)
@@ -63,6 +63,16 @@ void ArduinoGfx::init(int w, int h)
tft = new Arduino_RGB_Display(w, h, rgbpanel, 0 /* rotation */, TFT_AUTO_FLUSH, bus, TFT_RST,
gc9503v_type1_init_operations, sizeof(gc9503v_type1_init_operations));
+#elif(TFT_WIDTH == 480) && (TFT_HEIGHT == 480) && defined(ST7701_DRIVER) && defined(ST7701_4848S040)
+ Arduino_DataBus* bus = new Arduino_SWSPI(TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, TFT_MISO);
+ Arduino_ESP32RGBPanel* rgbpanel = new Arduino_ESP32RGBPanel(
+ TFT_DE, TFT_VSYNC, TFT_HSYNC, TFT_PCLK, TFT_R0, TFT_R1, TFT_R2, TFT_R3, TFT_R4, TFT_G0, TFT_G1, TFT_G2, TFT_G3,
+ TFT_G4, TFT_G5, TFT_B0, TFT_B1, TFT_B2, TFT_B3, TFT_B4, TFT_HSYNC_POLARITY, TFT_HSYNC_FRONT_PORCH,
+ TFT_HSYNC_PULSE_WIDTH, TFT_HSYNC_BACK_PORCH, TFT_VSYNC_POLARITY, TFT_VSYNC_FRONT_PORCH, TFT_VSYNC_PULSE_WIDTH,
+ TFT_VSYNC_BACK_PORCH);
+
+ tft = new Arduino_RGB_Display(w, h, rgbpanel, 0 /* rotation */, TFT_AUTO_FLUSH, bus, TFT_RST,
+ st7701_4848S040_init_operations, sizeof(st7701_4848S040_init_operations));
#elif(TFT_WIDTH == 480) && (TFT_HEIGHT == 480) && defined(ST7701_DRIVER)
/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
Arduino_DataBus* bus = new Arduino_SWSPI(TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, TFT_MISO);
diff --git a/src/drv/tft/tft_driver_arduinogfx.h b/src/drv/tft/tft_driver_arduinogfx.h
index 6db9546b..8d6d1f80 100644
--- a/src/drv/tft/tft_driver_arduinogfx.h
+++ b/src/drv/tft/tft_driver_arduinogfx.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_ARDUINOGFX_DRIVER_H
diff --git a/src/drv/tft/tft_driver_lovyangfx.cpp b/src/drv/tft/tft_driver_lovyangfx.cpp
index d6ba0892..9d6d9a6a 100644
--- a/src/drv/tft/tft_driver_lovyangfx.cpp
+++ b/src/drv/tft/tft_driver_lovyangfx.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(ARDUINO) && defined(LGFX_USE_V1)
@@ -187,7 +187,7 @@ static lgfx::Bus_SPI* init_spi_bus(Preferences* prefs)
static void configure_panel(lgfx::Panel_Device* panel, Preferences* prefs)
{
- auto cfg = panel->config(); // Get the structure for display panel settings.
+ auto cfg = panel->config(); // Get the structure for display panel settings.
cfg.pin_cs = prefs->getInt("cs", TFT_CS); // CS required
cfg.pin_rst = prefs->getInt("rst", TFT_RST); // RST sum development board RST linkage
@@ -201,27 +201,27 @@ static void configure_panel(lgfx::Panel_Device* panel, Preferences* prefs)
cfg.memory_width = prefs->getUInt("memory_width", cfg.panel_width); // Maximum width supported by driver IC
cfg.memory_height = prefs->getUInt("memory_height", cfg.panel_height); // Maximum height supported by driver IC
- cfg.offset_x = prefs->getUInt("offset_x", 0); // Amount of offset in the X direction of the panel
- cfg.offset_y = prefs->getUInt("offset_y", 0); // Amount of offset in the Y direction of the panel
+ cfg.offset_x = prefs->getUInt("offset_x", 0); // Amount of offset in the X direction of the panel
+ cfg.offset_y = prefs->getUInt("offset_y", 0); // Amount of offset in the Y direction of the panel
cfg.offset_rotation =
- prefs->getUInt("offset_rotation", TFT_OFFSET_ROTATION); // Offset of the rotation 0 ~ 7 (4 ~ 7 is upside down)
+ prefs->getUInt("offset_rotation", TFT_OFFSET_ROTATION); // Offset of the rotation 0 ~ 7 (4 ~ 7 is upside down)
cfg.dummy_read_pixel = prefs->getUInt("dummy_read_pixel", 8); // Number of dummy read bits before pixel read
cfg.dummy_read_bits =
prefs->getUInt("dummy_read_bits", 1); // bits of dummy read before reading data other than pixels
cfg.readable = prefs->getBool("readable", false); // true if data can be read
-#ifdef INVERT_COLORS // This is configurable un Web UI
+#ifdef INVERT_COLORS // This is configurable un Web UI
cfg.invert =
prefs->getBool("invert", INVERT_COLORS != 0); // true if the light and darkness of the panel is reversed
#else
- cfg.invert = prefs->getBool("invert", false); // true if the light and darkness of the panel is reversed
+ cfg.invert = prefs->getBool("invert", false); // true if the light and darkness of the panel is reversed
#endif
#ifdef TFT_RGB_ORDER
cfg.rgb_order =
prefs->getBool("rgb_order", TFT_RGB_ORDER != 0); // true if the red and blue of the panel are swapped
#else
- cfg.rgb_order = prefs->getBool("rgb_order", false); // true if the red and blue of the panel are swapped
+ cfg.rgb_order = prefs->getBool("rgb_order", false); // true if the red and blue of the panel are swapped
#endif
bool dlen_16bit = false;
@@ -453,7 +453,7 @@ lgfx::ITouch* _init_touch(Preferences* preferences)
touch->config(cfg);
return touch;
}
-#endif
+#endif
#endif // HASP_USE_LGFX_TOUCH
@@ -592,7 +592,7 @@ void LovyanGfx::init(int w, int h)
lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x12, 0x04, ~0, axp_i2c_freq); // LDO2 enable
lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x92, 0x00, 0xF8,
axp_i2c_freq); // GPIO1 OpenDrain (M5Tough TOUCH)
- lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x95, 0x84, 0x72, axp_i2c_freq); // GPIO4 enable
+ lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x95, 0x84, 0x72, axp_i2c_freq); // GPIO4 enable
if(/*use_reset*/ true) {
lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x96, 0, ~0x02, axp_i2c_freq); // GPIO4 LOW (LCD RST)
lgfx::i2c::writeRegister8(axp_i2c_port, axp_i2c_addr, 0x94, 0, ~0x02,
@@ -639,7 +639,14 @@ void LovyanGfx::init(int w, int h)
_panel_instance->setLight(new Light_M5Tough());
#elif defined(ESP32_2432S028R)
+
+#if defined(ILI9341_DRIVER)
auto _panel_instance = new lgfx::Panel_ILI9341();
+#elif defined(ILI9342_DRIVER)
+ auto _panel_instance = new lgfx::Panel_ILI9342();
+#elif defined(ST7789_DRIVER)
+ auto _panel_instance = new lgfx::Panel_ST7789();
+#endif
auto _bus_instance = new lgfx::Bus_SPI();
auto _touch_instance = new lgfx::Touch_XPT2046();
@@ -675,7 +682,7 @@ void LovyanGfx::init(int w, int h)
cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;
cfg.readable = true;
- cfg.invert = false;
+ cfg.invert = INVERT_COLORS;
cfg.rgb_order = false;
cfg.dlen_16bit = false;
cfg.bus_shared = false;
diff --git a/src/drv/tft/tft_driver_lovyangfx.h b/src/drv/tft/tft_driver_lovyangfx.h
index 4d6a5d09..e82fad0a 100644
--- a/src/drv/tft/tft_driver_lovyangfx.h
+++ b/src/drv/tft/tft_driver_lovyangfx.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_LOVYANGFX_DRIVER_H
diff --git a/src/drv/tft/tft_driver_posix_fbdev.cpp b/src/drv/tft/tft_driver_posix_fbdev.cpp
new file mode 100644
index 00000000..a6ec8d91
--- /dev/null
+++ b/src/drv/tft/tft_driver_posix_fbdev.cpp
@@ -0,0 +1,251 @@
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
+ For full license information read the LICENSE file in the project folder */
+
+#if USE_FBDEV && HASP_TARGET_PC
+
+#include "hasplib.h"
+#include "lvgl.h"
+
+#include "display/fbdev.h"
+
+#include "drv/tft/tft_driver.h"
+#include "tft_driver_posix_fbdev.h"
+
+#if USE_EVDEV || USE_BSD_EVDEV
+#include "indev/evdev.h"
+#endif
+
+#include "dev/device.h"
+#include "hasp_debug.h"
+#include "hasp_gui.h"
+
+#ifdef HASP_CUSTOMIZE_BOOTLOGO
+#include "custom/bootlogo.h" // Sketch tab header for xbm images
+#else
+#include "custom/bootlogo_template.h" // Sketch tab header for xbm images
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if USE_BSD_EVDEV
+#include
+#else
+#include
+#endif
+
+extern uint16_t tft_width;
+extern uint16_t tft_height;
+
+namespace dev {
+
+/**
+ * A task to measure the elapsed time for LittlevGL
+ * @param data unused
+ * @return never return
+ */
+static void* tick_thread(void* data)
+{
+ (void)data;
+
+ while(1) {
+ usleep(5000); /*Sleep for 5 millisecond*/
+ lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
+ }
+
+ return 0;
+}
+
+int32_t TftFbdevDrv::width()
+{
+ return _width;
+}
+int32_t TftFbdevDrv::height()
+{
+ return _height;
+}
+
+static void* gui_entrypoint(void* arg)
+{
+#if HASP_USE_LVGL_TASK
+ // create an LVGL GUI task thread
+ pthread_t gui_pthread;
+ pthread_create(&gui_pthread, 0, (void* (*)(void*))gui_task, NULL);
+#endif
+ // create an LVGL tick thread
+ pthread_t tick_pthread;
+ pthread_create(&tick_pthread, 0, tick_thread, NULL);
+ return 0;
+}
+
+void TftFbdevDrv::init(int32_t w, int h)
+{
+ // try to switch the active tty to tty7
+ int tty_fd = open("/dev/tty0", O_WRONLY);
+ if(tty_fd == -1) {
+ perror("Couldn't open /dev/tty0 (try running as root)");
+ } else {
+ if(ioctl(tty_fd, VT_ACTIVATE, 7) == -1) perror("Couldn't change active tty");
+ }
+ close(tty_fd);
+
+ // check active tty
+ std::ifstream f;
+ f.open("/sys/class/tty/tty0/active");
+ std::string tty;
+ f >> tty;
+ tty = "/dev/" + tty;
+ f.close();
+
+ // try to hide the cursor
+ tty_fd = open(tty.c_str(), O_WRONLY);
+ if(tty_fd == -1) {
+ perror("Couldn't open active tty (try running as root)");
+ } else {
+ write(tty_fd, "\033[?25l", 6);
+ }
+ close(tty_fd);
+
+ /* Add a display
+ * Use the 'fbdev' driver which uses POSIX framebuffer device as a display
+ * The following input devices are handled: mouse, keyboard, mousewheel */
+ fbdev_init(fbdev_path.empty() ? NULL : fbdev_path.c_str());
+ fbdev_get_sizes((uint32_t*)&_width, (uint32_t*)&_height);
+
+ // show the splashscreen early
+ splashscreen();
+
+ tft_width = _width;
+ tft_height = _height;
+
+#if USE_EVDEV || USE_BSD_EVDEV
+ DIR* dir = opendir("/dev/input");
+ if(dir == NULL) {
+ perror("/dev/input opendir failed");
+ } else {
+ // iterate through /dev/input devices
+ struct dirent* dirent;
+ unsigned char ev_type[EV_MAX / 8 + 1];
+ while((dirent = readdir(dir)) != NULL) {
+ // make sure it's a block device matching /dev/input/event*
+ if(strncmp(dirent->d_name, "event", 5) != 0 || strlen(dirent->d_name) <= 5) continue;
+ if(dirent->d_type != DT_CHR) continue;
+ // skip device if not specified on command line
+ if(!evdev_names.empty() &&
+ std::find(evdev_names.begin(), evdev_names.end(), std::string(dirent->d_name)) == evdev_names.end())
+ continue;
+ // get full path
+ char dev_path[64];
+ strcpy(dev_path, "/dev/input/");
+ strcat(dev_path, dirent->d_name);
+#if USE_BSD_EVDEV
+ // open the device
+ int fd = open(dev_path, O_RDONLY | O_NOCTTY);
+#else
+ int fd = open(dev_path, O_RDONLY | O_NOCTTY | O_NDELAY);
+#endif
+ if(fd == -1) {
+ perror("input open failed");
+ continue;
+ }
+ // read supported event types
+ memset(ev_type, 0, sizeof(ev_type));
+ if(ioctl(fd, EVIOCGBIT(0, sizeof(ev_type)), ev_type) < 0) {
+ perror("ioctl failed");
+ close(fd);
+ continue;
+ }
+ // read device name
+ char dev_name[256];
+ if(ioctl(fd, EVIOCGNAME(sizeof(dev_name)), dev_name) < 0) {
+ perror("ioctl failed");
+ close(fd);
+ continue;
+ }
+ // check which types are supported; judge LVGL device type
+ lv_indev_type_t dev_type;
+ const char* dev_type_name;
+ if(ev_type[EV_REL / 8] & (1 << (EV_REL % 8))) {
+ dev_type = LV_INDEV_TYPE_POINTER;
+ dev_type_name = "EV_REL";
+ } else if(ev_type[EV_ABS / 8] & (1 << (EV_ABS % 8))) {
+ dev_type = LV_INDEV_TYPE_POINTER;
+ dev_type_name = "EV_ABS";
+ } else if(ev_type[EV_KEY / 8] & (1 << (EV_KEY % 8))) {
+ dev_type = LV_INDEV_TYPE_KEYPAD;
+ dev_type_name = "EV_KEY";
+ } else {
+ close(fd);
+ continue;
+ }
+ // register the device
+ switch(dev_type) {
+ case LV_INDEV_TYPE_POINTER:
+ LOG_VERBOSE(TAG_TFT, F("Pointer : %s %s (%s)"), dev_path, dev_type_name, dev_name);
+ break;
+ case LV_INDEV_TYPE_KEYPAD:
+ LOG_VERBOSE(TAG_TFT, F("Keypad : %s %s (%s)"), dev_path, dev_type_name, dev_name);
+ break;
+ default:
+ LOG_VERBOSE(TAG_TFT, F("Input : %s %s (%s)"), dev_path, dev_type_name, dev_name);
+ break;
+ }
+ close(fd);
+ // print verbose resolution info
+ lv_indev_t* indev;
+ if(!evdev_register(dev_path, dev_type, &indev) || indev == NULL) {
+ printf("Failed to register evdev\n");
+ continue;
+ }
+ evdev_data_t* user_data = (evdev_data_t*)indev->driver.user_data;
+ LOG_VERBOSE(TAG_TFT, F("Resolution : X=%d (%d..%d), Y=%d (%d..%d)"), user_data->x_max,
+ user_data->x_absinfo.minimum, user_data->x_absinfo.maximum, user_data->y_max,
+ user_data->y_absinfo.minimum, user_data->y_absinfo.maximum);
+ }
+ closedir(dir);
+ }
+#endif
+
+ gui_entrypoint(NULL);
+}
+void TftFbdevDrv::show_info()
+{
+ splashscreen();
+
+ LOG_VERBOSE(TAG_TFT, F("Driver : %s"), get_tft_model());
+}
+
+void TftFbdevDrv::splashscreen()
+{
+ uint8_t fg[] = logoFgColor;
+ uint8_t bg[] = logoBgColor;
+ lv_color_t fgColor = lv_color_make(fg[0], fg[1], fg[2]);
+ lv_color_t bgColor = lv_color_make(bg[0], bg[1], bg[2]);
+ fbdev_splashscreen(logoImage, logoWidth, logoHeight, fgColor, bgColor);
+}
+void TftFbdevDrv::set_rotation(uint8_t rotation)
+{}
+void TftFbdevDrv::set_invert(bool invert)
+{}
+void TftFbdevDrv::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
+{
+ lv_disp_flush_ready(disp);
+}
+bool TftFbdevDrv::is_driver_pin(uint8_t pin)
+{
+ return false;
+}
+const char* TftFbdevDrv::get_tft_model()
+{
+ return "POSIX fbdev";
+}
+
+} // namespace dev
+
+dev::TftFbdevDrv haspTft;
+
+#endif // WINDOWS || POSIX
diff --git a/src/drv/tft/tft_driver_posix_fbdev.h b/src/drv/tft/tft_driver_posix_fbdev.h
new file mode 100644
index 00000000..8cf8862b
--- /dev/null
+++ b/src/drv/tft/tft_driver_posix_fbdev.h
@@ -0,0 +1,50 @@
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
+ For full license information read the LICENSE file in the project folder */
+
+#ifndef HASP_FBDEV_DRIVER_H
+#define HASP_FBDEV_DRIVER_H
+
+#include "tft_driver.h"
+
+#if USE_FBDEV && HASP_TARGET_PC
+// #warning Building H driver FBDEV
+
+#include "lvgl.h"
+
+#include
+
+namespace dev {
+
+class TftFbdevDrv : BaseTft {
+ public:
+ void init(int w, int h);
+ void show_info();
+ void splashscreen();
+
+ void set_rotation(uint8_t rotation);
+ void set_invert(bool invert);
+
+ void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p);
+ bool is_driver_pin(uint8_t pin);
+
+ const char* get_tft_model();
+
+ int32_t width();
+ int32_t height();
+
+ public:
+ std::string fbdev_path;
+ std::vector evdev_names;
+
+ private:
+ int32_t _width, _height;
+};
+
+} // namespace dev
+
+using dev::TftFbdevDrv;
+extern dev::TftFbdevDrv haspTft;
+
+#endif // HASP_TARGET_PC
+
+#endif // HASP_FBDEV_DRIVER_H
diff --git a/src/drv/tft/tft_driver_sdl2.cpp b/src/drv/tft/tft_driver_sdl2.cpp
index a2b44233..6f14b1a9 100644
--- a/src/drv/tft/tft_driver_sdl2.cpp
+++ b/src/drv/tft/tft_driver_sdl2.cpp
@@ -1,7 +1,7 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
-#if defined(WINDOWS) || defined(POSIX)
+#if USE_MONITOR && HASP_TARGET_PC
#include "hasplib.h"
#include "lvgl.h"
@@ -75,6 +75,10 @@ void TftSdl::init(int32_t w, int h)
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed
* Create an SDL thread to do this*/
SDL_CreateThread(tick_thread, "tick", NULL);
+
+#if HASP_USE_LVGL_TASK
+#error "SDL2 LVGL task is not implemented"
+#endif
}
void TftSdl::show_info()
{
@@ -115,4 +119,4 @@ const char* TftSdl::get_tft_model()
dev::TftSdl haspTft;
-#endif // WINDOWS || POSIX
\ No newline at end of file
+#endif // WINDOWS || POSIX
diff --git a/src/drv/tft/tft_driver_sdl2.h b/src/drv/tft/tft_driver_sdl2.h
index 85b32ee0..54f65e89 100644
--- a/src/drv/tft/tft_driver_sdl2.h
+++ b/src/drv/tft/tft_driver_sdl2.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_SDL2_DRIVER_H
@@ -6,7 +6,7 @@
#include "tft_driver.h"
-#if defined(WINDOWS) || defined(POSIX)
+#if USE_MONITOR && HASP_TARGET_PC
// #warning Building H driver TFT SDL2
#include "lvgl.h"
@@ -40,6 +40,6 @@ class TftSdl : BaseTft {
using dev::TftSdl;
extern dev::TftSdl haspTft;
-#endif // defined(WINDOWS) || defined(POSIX)
+#endif // HASP_TARGET_PC
#endif // HASP_SDL2_DRIVER_H
diff --git a/src/drv/tft/tft_driver_tftespi.cpp b/src/drv/tft/tft_driver_tftespi.cpp
index 291f3b20..6db53134 100644
--- a/src/drv/tft/tft_driver_tftespi.cpp
+++ b/src/drv/tft/tft_driver_tftespi.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(ARDUINO) && defined(USER_SETUP_LOADED)
diff --git a/src/drv/tft/tft_driver_tftespi.h b/src/drv/tft/tft_driver_tftespi.h
index 3d72003c..94e32fa3 100644
--- a/src/drv/tft/tft_driver_tftespi.h
+++ b/src/drv/tft/tft_driver_tftespi.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TFTESPI_DRIVER_H
diff --git a/src/drv/tft/tft_driver_win32drv.cpp b/src/drv/tft/tft_driver_win32drv.cpp
new file mode 100644
index 00000000..7c6e8732
--- /dev/null
+++ b/src/drv/tft/tft_driver_win32drv.cpp
@@ -0,0 +1,149 @@
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
+ For full license information read the LICENSE file in the project folder */
+
+#if USE_WIN32DRV && HASP_TARGET_PC
+
+#include "hasplib.h"
+#include "lvgl.h"
+
+#include "win32drv/win32drv.h"
+
+#include "drv/tft/tft_driver.h"
+#include "tft_driver_win32drv.h"
+
+#include "dev/device.h"
+#include "hasp_debug.h"
+#include "hasp_gui.h"
+
+#ifdef HASP_CUSTOMIZE_BOOTLOGO
+#include "custom/bootlogo.h" // Sketch tab header for xbm images
+#else
+#include "custom/bootlogo_template.h" // Sketch tab header for xbm images
+#endif
+
+namespace dev {
+
+/**
+ * A task to measure the elapsed time for LittlevGL
+ * @param data unused
+ * @return never return
+ */
+static DWORD tick_thread(void* data)
+{
+ (void)data;
+
+ while(1) {
+ Sleep(5); /*Sleep for 5 millisecond*/
+ lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
+ }
+
+ return 0;
+}
+
+int32_t TftWin32Drv::width()
+{
+ return _width;
+}
+int32_t TftWin32Drv::height()
+{
+ return _height;
+}
+
+static void win32_message_loop(lv_task_t* param)
+{
+ MSG Message;
+#if HASP_USE_LVGL_TASK
+ while(haspDevice.pc_is_running && GetMessageW(&Message, NULL, 0, 0)) {
+ TranslateMessage(&Message);
+ DispatchMessageW(&Message);
+ }
+ // apparently GetMessageW doesn't deliver WM_QUIT
+ haspDevice.pc_is_running = false;
+#else
+ BOOL Result = PeekMessageW(&Message, NULL, 0, 0, TRUE);
+ if(Result != 0 && Result != -1) {
+ TranslateMessage(&Message);
+ DispatchMessageW(&Message);
+ if(Message.message == WM_QUIT) haspDevice.pc_is_running = false;
+ }
+#endif
+}
+
+static DWORD gui_entrypoint(HANDLE semaphore)
+{
+ /* Add a display
+ * Use the 'win32drv' driver which creates window on PC's monitor to simulate a display
+ * The following input devices are handled: mouse, keyboard, mousewheel */
+ lv_win32_init(0, SW_SHOWNORMAL, haspTft.width(), haspTft.height(), 0);
+ lv_win32_set_title(haspDevice.get_hostname());
+
+#if HASP_USE_LVGL_TASK
+ // let the init() function continue
+ ReleaseSemaphore(semaphore, 1, NULL);
+ // run the LVGL task as a thread
+ HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)gui_task, NULL, 0, NULL);
+ // run a blocking message loop on this thread
+ win32_message_loop(NULL);
+ // wait for the LVGL task now
+ WaitForSingleObject(thread, 4000);
+#else
+ // create a LVGL tick thread
+ CreateThread(NULL, 0, tick_thread, NULL, 0, NULL);
+ // create a LVGL task for the message loop
+ lv_task_create(win32_message_loop, 5, LV_TASK_PRIO_HIGHEST, NULL);
+#endif
+ return 0;
+}
+
+void TftWin32Drv::init(int32_t w, int h)
+{
+ _width = w;
+ _height = h;
+
+#if HASP_USE_LVGL_TASK
+ // run a thread for creating the window and running the message loop
+ HANDLE semaphore = CreateSemaphore(NULL, 0, 1, NULL);
+ HANDLE thread = CreateThread(NULL, 0, gui_entrypoint, semaphore, 0, NULL);
+ WaitForSingleObject(semaphore, INFINITE);
+#else
+ // do not use the gui_task(), just init the GUI and return
+ gui_entrypoint(NULL);
+#endif
+}
+void TftWin32Drv::show_info()
+{
+ splashscreen();
+
+ LOG_VERBOSE(TAG_TFT, F("Driver : %s"), get_tft_model());
+}
+
+void TftWin32Drv::splashscreen()
+{
+ uint8_t fg[] = logoFgColor;
+ uint8_t bg[] = logoBgColor;
+ lv_color_t fgColor = lv_color_make(fg[0], fg[1], fg[2]);
+ lv_color_t bgColor = lv_color_make(bg[0], bg[1], bg[2]);
+ lv_win32_splashscreen(logoImage, logoWidth, logoHeight, lv_color_to32(fgColor), lv_color_to32(bgColor));
+}
+void TftWin32Drv::set_rotation(uint8_t rotation)
+{}
+void TftWin32Drv::set_invert(bool invert)
+{}
+void TftWin32Drv::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
+{
+ lv_disp_flush_ready(disp);
+}
+bool TftWin32Drv::is_driver_pin(uint8_t pin)
+{
+ return false;
+}
+const char* TftWin32Drv::get_tft_model()
+{
+ return "Win32Drv";
+}
+
+} // namespace dev
+
+dev::TftWin32Drv haspTft;
+
+#endif // WINDOWS || POSIX
diff --git a/src/drv/tft/tft_driver_win32drv.h b/src/drv/tft/tft_driver_win32drv.h
new file mode 100644
index 00000000..dabd0da4
--- /dev/null
+++ b/src/drv/tft/tft_driver_win32drv.h
@@ -0,0 +1,44 @@
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
+ For full license information read the LICENSE file in the project folder */
+
+#ifndef HASP_WIN32DRV_DRIVER_H
+#define HASP_WIN32DRV_DRIVER_H
+
+#include "tft_driver.h"
+
+#if USE_WIN32DRV && HASP_TARGET_PC
+// #warning Building H driver WIN32DRV
+
+#include "lvgl.h"
+
+namespace dev {
+
+class TftWin32Drv : BaseTft {
+ public:
+ void init(int w, int h);
+ void show_info();
+ void splashscreen();
+
+ void set_rotation(uint8_t rotation);
+ void set_invert(bool invert);
+
+ void flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p);
+ bool is_driver_pin(uint8_t pin);
+
+ const char* get_tft_model();
+
+ int32_t width();
+ int32_t height();
+
+ private:
+ int32_t _width, _height;
+};
+
+} // namespace dev
+
+using dev::TftWin32Drv;
+extern dev::TftWin32Drv haspTft;
+
+#endif // HASP_TARGET_PC
+
+#endif // HASP_WIN32DRV_DRIVER_H
diff --git a/src/drv/touch/touch_driver.h b/src/drv/touch/touch_driver.h
index 674558f7..054e8cad 100644
--- a/src/drv/touch/touch_driver.h
+++ b/src/drv/touch/touch_driver.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_BASE_TOUCH_DRIVER_H
@@ -84,6 +84,9 @@ class BaseTouch {
#elif TOUCH_DRIVER == 0x1680
#warning Building for GSL1680
#include "touch_driver_gslx680.h"
+#elif TOUCH_DRIVER == 0x2007
+#warning Building for TSC2007
+#include "touch_driver_tsc2007.h"
#elif defined(LGFX_USE_V1)
#warning Building for LovyanGfx Touch
#include "touch_driver_lovyangfx.h"
diff --git a/src/drv/touch/touch_driver_analog.h b/src/drv/touch/touch_driver_analog.h
index 75cdf071..4648ef27 100644
--- a/src/drv/touch/touch_driver_analog.h
+++ b/src/drv/touch/touch_driver_analog.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_ANALOG_TOUCH_DRIVER_H
diff --git a/src/drv/touch/touch_driver_ft6336u.h b/src/drv/touch/touch_driver_ft6336u.h
index efc419cf..4ee5c2d3 100644
--- a/src/drv/touch/touch_driver_ft6336u.h
+++ b/src/drv/touch/touch_driver_ft6336u.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_FT6336T_TOUCH_DRIVER_H
diff --git a/src/drv/touch/touch_driver_gslx680.h b/src/drv/touch/touch_driver_gslx680.h
index ca022960..82f23a90 100644
--- a/src/drv/touch/touch_driver_gslx680.h
+++ b/src/drv/touch/touch_driver_gslx680.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_GSL1680_TOUCH_DRIVER_H
diff --git a/src/drv/touch/touch_driver_gt911.cpp b/src/drv/touch/touch_driver_gt911.cpp
index c3da9ef0..1ff67cad 100644
--- a/src/drv/touch/touch_driver_gt911.cpp
+++ b/src/drv/touch/touch_driver_gt911.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(ARDUINO) && (TOUCH_DRIVER == 0x0911) && !defined(HASP_USE_LGFX_TOUCH)
diff --git a/src/drv/touch/touch_driver_gt911.h b/src/drv/touch/touch_driver_gt911.h
index ac5447d4..983e696e 100644
--- a/src/drv/touch/touch_driver_gt911.h
+++ b/src/drv/touch/touch_driver_gt911.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_GT911_TOUCH_DRIVER_H
diff --git a/src/drv/touch/touch_driver_lovyangfx.h b/src/drv/touch/touch_driver_lovyangfx.h
index 21302165..355123b3 100644
--- a/src/drv/touch/touch_driver_lovyangfx.h
+++ b/src/drv/touch/touch_driver_lovyangfx.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_LOVYANGFX_TOUCH_DRIVER_H
diff --git a/src/drv/touch/touch_driver_stmpe610.h b/src/drv/touch/touch_driver_stmpe610.h
index c3a605da..1b52653e 100644
--- a/src/drv/touch/touch_driver_stmpe610.h
+++ b/src/drv/touch/touch_driver_stmpe610.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_STMPE610_TOUCH_DRIVER_H
diff --git a/src/drv/touch/touch_driver_tftespi.h b/src/drv/touch/touch_driver_tftespi.h
index 4762844a..8fc82a91 100644
--- a/src/drv/touch/touch_driver_tftespi.h
+++ b/src/drv/touch/touch_driver_tftespi.h
@@ -1,10 +1,10 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TFTESPI_TOUCH_DRIVER_H
#define HASP_TFTESPI_TOUCH_DRIVER_H
-#ifdef ARDUINO && defined(USER_SETUP_LOADED)
+#if defined(ARDUINO) && defined(USER_SETUP_LOADED)
#include
#include "touch_driver.h" // base class
diff --git a/src/drv/touch/touch_driver_tsc2007.h b/src/drv/touch/touch_driver_tsc2007.h
new file mode 100644
index 00000000..2c27ee5d
--- /dev/null
+++ b/src/drv/touch/touch_driver_tsc2007.h
@@ -0,0 +1,104 @@
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
+ For full license information read the LICENSE file in the project folder */
+
+#ifndef HASP_TSC2007_TOUCH_DRIVER_H
+#define HASP_TSC2007_TOUCH_DRIVER_H
+
+#if defined(ARDUINO) && !defined(HASP_USE_LGFX_TOUCH)
+#include
+#include "ArduinoLog.h"
+#include "hasp_conf.h"
+
+#include
+#include "Adafruit_TSC2007.h"
+
+#include "touch_driver.h" // base class
+#include "touch_helper.h" // i2c scanner
+
+#include "hasp_debug.h"
+
+#include "../../hasp/hasp.h" // for hasp_sleep_state
+extern uint8_t hasp_sleep_state;
+
+// This is calibration data for the raw touch data to the screen coordinates
+#define TS_MINX 150
+#define TS_MINY 130
+#define TS_MAXX 3800
+#define TS_MAXY 4000
+#define TS_MIN_PRESSURE 100
+
+namespace dev {
+
+class TouchTsc2007 : public BaseTouch {
+ public:
+ Adafruit_TSC2007* ts;
+
+ IRAM_ATTR bool read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data)
+ {
+ uint16_t x, y, z1, z2;
+ if (ts->read_touch(&x, &y, &z1, &z2) && (z1 > TS_MIN_PRESSURE)) {
+ if(hasp_sleep_state != HASP_SLEEP_OFF) hasp_update_sleep_state(); // update Idle
+
+ data->state = LV_INDEV_STATE_PR;
+ hasp_set_sleep_offset(0); // Reset the offset
+
+ // Scale from ~0->4000 to tft.width using the calibration #'s
+ x = map(x, TS_MINX, TS_MAXX, 0, TFT_WIDTH);
+ y = map(y, TS_MINY, TS_MAXY, 0, TFT_HEIGHT);
+
+ // LOG_INFO(TAG_DRVR, F("Touch point: %i, %i"), x, y);
+
+#if defined(TOUCH_SWAP_XY) && (TOUCH_SWAP_XY)
+ data->point.x = y;
+ data->point.y = x;
+#else
+ data->point.x = x;
+ data->point.y = y;
+#endif
+
+#if defined(TOUCH_INVERSE_X) && (TOUCH_INVERSE_X)
+ data->point.x = _width_max - x;
+#endif
+#if defined(TOUCH_INVERSE_Y) && (TOUCH_INVERSE_Y)
+ data->point.y = _height_max - y;
+#endif
+
+ } else {
+ data->state = LV_INDEV_STATE_REL;
+ }
+
+ /*Return `false` because we are not buffering and no more data to read*/
+ return false;
+ }
+
+ void init(int w, int h)
+ {
+ _height_max = h - 1;
+ _width_max = w - 1;
+
+ // tsc2007_touch = new Adafruit_TSC2007();
+ LOG_VERBOSE(TAG_DRVR, F("%s %d"), __FILE__, __LINE__);
+
+ ts = new Adafruit_TSC2007();
+
+ // Startup sequence CONTROLLER parT
+ if (!ts->begin()) {
+ LOG_INFO(TAG_DRVR, F("Failed to find Adafruit TSC2007 chip"));
+ while (1) { delay(10); }
+ }
+ LOG_INFO(TAG_DRVR, F("Found Adafruit TSC2007 chip"));
+ }
+
+ private:
+ uint16_t _width_max;
+ uint16_t _height_max;
+};
+
+} // namespace dev
+
+using dev::TouchTsc2007;
+dev::TouchTsc2007 haspTouch;
+
+#endif // ARDUINO
+
+#endif // HASP_TSC2007_TOUCH_DRIVER_H
\ No newline at end of file
diff --git a/src/drv/touch/touch_helper.h b/src/drv/touch/touch_helper.h
index 3f11cd13..54b656f3 100644
--- a/src/drv/touch/touch_helper.h
+++ b/src/drv/touch/touch_helper.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TOUCH_HELPER_H
diff --git a/src/hal/hasp_hal.cpp b/src/hal/hasp_hal.cpp
index 1918fc9c..7a9c8278 100644
--- a/src/hal/hasp_hal.cpp
+++ b/src/hal/hasp_hal.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_hal.h"
diff --git a/src/hal/hasp_hal.h b/src/hal/hasp_hal.h
index d1c34d53..e9c29332 100644
--- a/src/hal/hasp_hal.h
+++ b/src/hal/hasp_hal.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_HAL_H
diff --git a/src/hasp/hasp.cpp b/src/hasp/hasp.cpp
index 9187f4ad..35388570 100644
--- a/src/hasp/hasp.cpp
+++ b/src/hasp/hasp.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
@@ -11,7 +11,7 @@
#include "ArduinoLog.h"
#endif
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
#include
#include
#include
@@ -121,18 +121,21 @@ HASP_ATTRIBUTE_FAST_MEM void hasp_update_sleep_state()
gui_hide_pointer(true);
hasp_sleep_state = HASP_SLEEP_LONG;
dispatch_idle_state(HASP_SLEEP_LONG);
+ dispatch_run_script(NULL, "L:/idle_long.cmd", TAG_HASP);
}
} else if(sleepTimeShort > 0 && idle >= sleepTimeShort) {
if(hasp_sleep_state != HASP_SLEEP_SHORT) {
gui_hide_pointer(true);
hasp_sleep_state = HASP_SLEEP_SHORT;
dispatch_idle_state(HASP_SLEEP_SHORT);
+ dispatch_run_script(NULL, "L:/idle_short.cmd", TAG_HASP);
}
} else {
if(hasp_sleep_state != HASP_SLEEP_OFF) {
gui_hide_pointer(false);
hasp_sleep_state = HASP_SLEEP_OFF;
dispatch_idle_state(HASP_SLEEP_OFF);
+ dispatch_run_script(NULL, "L:/idle_off.cmd", TAG_HASP);
}
}
}
diff --git a/src/hasp/hasp.h b/src/hasp/hasp.h
index 4b9b5217..bc786c50 100644
--- a/src/hasp/hasp.h
+++ b/src/hasp/hasp.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_H
diff --git a/src/hasp/hasp_attribute.cpp b/src/hasp/hasp_attribute.cpp
index f0934fb7..b903cc93 100644
--- a/src/hasp/hasp_attribute.cpp
+++ b/src/hasp/hasp_attribute.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
@@ -19,6 +19,9 @@ LV_FONT_DECLARE(unscii_8_icon);
extern const char** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map
extern const char* msgbox_default_map[]; // memory pointer to lvgl default btnmatrix map
+extern const uint8_t rootca_crt_bundle_start[] asm("_binary_data_cert_x509_crt_bundle_bin_start");
+extern const uint8_t rootca_crt_bundle_end[] asm("_binary_data_cert_x509_crt_bundle_bin_end");
+
void my_image_release_resources(lv_obj_t* obj)
{
if(!obj) return;
@@ -1345,8 +1348,9 @@ static hasp_attribute_type_t special_attribute_src(lv_obj_t* obj, const char* pa
#if defined(ARDUINO) && defined(ARDUINO_ARCH_ESP32)
#if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0
HTTPClient http;
+ // http.begin(payload, (const char*)rootca_crt_bundle_start);
http.begin(payload);
- http.setTimeout(1000);
+ http.setTimeout(5000);
http.setConnectTimeout(5000);
// const char* hdrs[] = {"Content-Type"};
diff --git a/src/hasp/hasp_attribute.h b/src/hasp/hasp_attribute.h
index c5c1b742..1e431a2f 100644
--- a/src/hasp/hasp_attribute.h
+++ b/src/hasp/hasp_attribute.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_ATTRIBUTE_H
diff --git a/src/hasp/hasp_attribute_helper.h b/src/hasp/hasp_attribute_helper.h
index 2b48bcbd..ee078300 100644
--- a/src/hasp/hasp_attribute_helper.h
+++ b/src/hasp/hasp_attribute_helper.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp
index 86ca9818..03b0da9d 100644
--- a/src/hasp/hasp_dispatch.cpp
+++ b/src/hasp/hasp_dispatch.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include
@@ -16,7 +16,7 @@
#include "../hasp_debug.h"
#include "hasp_gui.h" // for screenshot
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
#include
#include
#include
@@ -269,6 +269,42 @@ static void dispatch_output(const char* topic, const char* payload)
#endif
}
+// static inline size_t dispatch_msg_length(size_t len)
+// {
+// return (len / 64) * 64 + 64;
+// }
+
+// void dispatch_enqueue_message(const char* topic, const char* payload, size_t payload_len, uint8_t source)
+// {
+// // Add new message to the queue
+// dispatch_message_t data;
+
+// size_t topic_len = strlen(topic);
+// data.topic = (char*)hasp_calloc(sizeof(char), dispatch_msg_length(topic_len + 1));
+// data.payload = (char*)hasp_calloc(sizeof(char), dispatch_msg_length(payload_len + 1));
+// data.source = source;
+
+// if(!data.topic || !data.payload) {
+// LOG_ERROR(TAG_MQTT_RCV, D_ERROR_OUT_OF_MEMORY);
+// hasp_free(data.topic);
+// hasp_free(data.payload);
+// return;
+// }
+// memcpy(data.topic, topic, topic_len);
+// memcpy(data.payload, payload, payload_len);
+
+// {
+// size_t attempt = 0;
+// while(xQueueSend(message_queue, &data, (TickType_t)0) == errQUEUE_FULL && attempt < 100) {
+// delay(5);
+// attempt++;
+// };
+// if(attempt >= 100) {
+// LOG_ERROR(TAG_MSGR, D_ERROR_OUT_OF_MEMORY);
+// }
+// }
+// }
+
// objectattribute=value
static void dispatch_command(const char* topic, const char* payload, bool update, uint8_t source)
{
@@ -460,10 +496,12 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source)
}
if(strcasecmp_P(topic, PSTR("debug")) == 0) {
+#if HASP_TARGET_ARDUINO
if(update)
debugSetConfig(settings);
else
debugGetConfig(settings);
+#endif
}
else if(strcasecmp_P(topic, PSTR("gui")) == 0) {
@@ -503,6 +541,14 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source)
else
timeGetConfig(settings);
}
+#if HASP_USE_WIREGUARD > 0
+ else if(strcasecmp_P(topic, PSTR(FP_WG)) == 0) {
+ if(update)
+ wgSetConfig(settings);
+ else
+ wgGetConfig(settings);
+ }
+#endif
#if HASP_USE_MQTT > 0
else if(strcasecmp_P(topic, PSTR(FP_MQTT)) == 0) {
if(update)
@@ -726,7 +772,7 @@ void dispatch_parse_jsonl(std::istream& stream, uint8_t& saved_page_id)
void dispatch_parse_jsonl(const char*, const char* payload, uint8_t source)
{
if(source != TAG_MQTT) saved_jsonl_page = haspPages.get();
-#if HASP_USE_CONFIG > 0
+#if HASP_USE_CONFIG > 0 && HASP_TARGET_ARDUINO
CharStream stream((char*)payload);
// stream.setTimeout(10);
dispatch_parse_jsonl(stream, saved_jsonl_page);
@@ -757,6 +803,11 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source)
return;
}
+ // if(!gui_acquire(pdMS_TO_TICKS(500))) {
+ // LOG_ERROR(TAG_MSGR, F(D_FILE_LOAD_FAILED), payload);
+ // return;
+ // }
+
// char buffer[512]; // use stack
String buffer((char*)0); // use heap
buffer.reserve(512);
@@ -780,6 +831,7 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source)
}
}
+ // gui_release();
cmdfile.close();
LOG_INFO(TAG_MSGR, F(D_FILE_LOADED), payload);
#else
@@ -790,7 +842,11 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source)
path[0] = '.';
path[1] = '\0';
strcat(path, filename);
+#if defined(WINDOWS)
path[1] = '\\';
+#elif defined(POSIX)
+ path[1] = '/';
+#endif
LOG_TRACE(TAG_HASP, F("Loading %s from disk..."), path);
std::ifstream f(path); // taking file as inputstream
@@ -808,6 +864,48 @@ void dispatch_run_script(const char*, const char* payload, uint8_t source)
#endif
}
+#if HASP_TARGET_PC
+static void shell_command_thread(char* cmdline)
+{
+ // run the command
+ FILE* pipe = popen(cmdline, "r");
+ // free the string duplicated previously
+ free(cmdline);
+ if(!pipe) {
+ LOG_ERROR(TAG_MSGR, F("Couldn't execute system command"));
+ return;
+ }
+ // read each line, up to 1023 chars long
+ char command[1024];
+ while(fgets(command, sizeof(command), pipe) != NULL) {
+ // strip newline character
+ char* temp = command;
+ while(*temp) {
+ if(*temp == '\r' || *temp == '\n') {
+ *temp = '\0';
+ break;
+ }
+ temp++;
+ }
+ // run the command
+ LOG_INFO(TAG_MSGR, F("Running '%s'"), command);
+ dispatch_text_line(command, TAG_MSGR);
+ }
+ // close the pipe, check return code
+ int status_code = pclose(pipe);
+ if(status_code) {
+ LOG_ERROR(TAG_MSGR, F("Process exited with non-zero return code %d"), status_code);
+ }
+}
+
+void dispatch_shell_execute(const char*, const char* payload, uint8_t source)
+{
+ // must duplicate the string for thread's own usage
+ char* command = strdup(payload);
+ haspDevice.run_thread((void (*)(void*))shell_command_thread, (void*)command);
+}
+#endif
+
void dispatch_current_page()
{
char topic[8];
@@ -891,7 +989,14 @@ void dispatch_page(const char*, const char* payload, uint8_t source)
void dispatch_clear_page(const char*, const char* page, uint8_t source)
{
if(!strcasecmp(page, "all")) {
+#if !HASP_TARGET_PC
hasp_init();
+#else
+ // workaround for "clearpage all" deadlocking or crashing on PC build (when called from non-LVGL thread)
+ for(uint8_t pageid = 0; pageid <= HASP_NUM_PAGES; pageid++) {
+ haspPages.clear(pageid);
+ }
+#endif
return;
}
@@ -1105,7 +1210,7 @@ void dispatch_reboot(bool saveConfig)
LOG_VERBOSE(TAG_MSGR, F("-------------------------------------"));
LOG_TRACE(TAG_MSGR, F(D_DISPATCH_REBOOT));
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
fflush(stdout);
#else
Serial.flush();
@@ -1190,26 +1295,22 @@ void dispatch_queue_discovery(const char*, const char*, uint8_t source)
dispatchSecondsToNextDiscovery = seconds;
}
-// Periodically publish a JSON string facilitating plate discovery
-void dispatch_send_discovery(const char*, const char*, uint8_t source)
+void dispatch_get_discovery_data(JsonDocument& doc)
{
-#if HASP_USE_MQTT > 0
-
- StaticJsonDocument<1024> doc;
- char data[1024];
char buffer[64];
- doc[F("node")] = haspDevice.get_hostname();
- doc[F("mdl")] = haspDevice.get_model();
- doc[F("mf")] = F(D_MANUFACTURER);
- doc[F("hwid")] = haspDevice.get_hardware_id();
- doc[F("pages")] = haspPages.count();
- doc[F("sw")] = haspDevice.get_version();
+ doc[F("node")] = haspDevice.get_hostname();
+ doc[F("mdl")] = haspDevice.get_model();
+ doc[F("mf")] = F(D_MANUFACTURER);
+ doc[F("hwid")] = haspDevice.get_hardware_id();
+ doc[F("pages")] = haspPages.count();
+ doc[F("sw")] = haspDevice.get_version();
+ doc[F("node_t")] = String("hasp/") + haspDevice.get_hostname() + "/";
#if HASP_USE_HTTP > 0
network_get_ipaddress(buffer, sizeof(buffer));
doc[F("uri")] = String(F("http://")) + String(buffer);
-#elif defined(WINDOWS) || defined(POSIX)
+#elif HASP_TARGET_PC
doc[F("uri")] = "http://google.pt";
#endif
@@ -1221,7 +1322,17 @@ void dispatch_send_discovery(const char*, const char*, uint8_t source)
#if HASP_USE_GPIO > 0
gpio_discovery(input, relay, led, dimmer);
#endif
+}
+// Periodically publish a JSON string facilitating plate discovery
+void dispatch_send_discovery(const char*, const char*, uint8_t source)
+{
+#if HASP_USE_MQTT > 0
+ StaticJsonDocument<1024> doc;
+ char data[1024];
+ char buffer[64];
+
+ dispatch_get_discovery_data(doc);
size_t len = serializeJson(doc, data);
switch(mqtt_send_discovery(data, len)) {
@@ -1313,8 +1424,8 @@ void dispatch_current_state(uint8_t source)
bool dispatch_factory_reset()
{
bool formatted = true;
- bool erased = true;
- bool cleared = true;
+ bool erased = true;
+ bool cleared = true;
#if ESP32
erased = nvs_clear_user_config();
@@ -1346,7 +1457,7 @@ void dispatch_idle_state(uint8_t state)
{
char topic[8];
char buffer[8];
- memcpy_P(topic, PSTR("idle"), 8);
+ memcpy_P(topic, PSTR("idle"), 5);
hasp_get_sleep_payload(state, buffer);
dispatch_state_subtopic(topic, buffer);
}
@@ -1481,6 +1592,9 @@ void dispatchSetup()
dispatch_add_command(PSTR("sensors"), dispatch_send_sensordata);
dispatch_add_command(PSTR("theme"), dispatch_theme);
dispatch_add_command(PSTR("run"), dispatch_run_script);
+#if HASP_TARGET_PC
+ dispatch_add_command(PSTR("shell"), dispatch_shell_execute);
+#endif
dispatch_add_command(PSTR("service"), dispatch_service);
dispatch_add_command(PSTR("antiburn"), dispatch_antiburn);
dispatch_add_command(PSTR("calibrate"), dispatch_calibrate);
@@ -1502,7 +1616,7 @@ void dispatchSetup()
dispatch_add_command(PSTR("unzip"), filesystemUnzip);
#endif
#endif
-#if HASP_USE_CONFIG > 0
+#if HASP_USE_CONFIG > 0 && HASP_TARGET_ARDUINO
dispatch_add_command(PSTR("setupap"), oobeFakeSetup);
#endif
/* WARNING: remember to expand the commands array when adding new commands */
@@ -1511,7 +1625,20 @@ void dispatchSetup()
}
IRAM_ATTR void dispatchLoop()
-{}
+{
+ // UBaseType_t msg_count = uxQueueMessagesWaiting(message_queue));
+ // if(msg_count == 0) return;
+
+ // dispatch_message_t data;
+ // while(xQueueReceive(message_queue, &data, (TickType_t)0)) {
+ // LOG_WARNING(TAG_MSGR, F("[%d] QUE %s => %s"), msg_count, data.topic, data.payload);
+ // size_t length = strlen(data.payload);
+ // dispatch_topic_payload(data.topic, data.payload, length > 0, data.source);
+ // hasp_free(data.topic);
+ // hasp_free(data.payload);
+ // // delay(1);
+ // }
+}
#if 1 || ARDUINO
void dispatchEverySecond()
@@ -1543,7 +1670,7 @@ void everySecond()
{
if(dispatch_setings.teleperiod > 0) {
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
- std::chrono::seconds elapsed = std::chrono::duration_cast(end - begin);
+ std::chrono::seconds elapsed = std::chrono::duration_cast(end - begin);
if(elapsed.count() >= dispatch_setings.teleperiod) {
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
diff --git a/src/hasp/hasp_dispatch.h b/src/hasp/hasp_dispatch.h
index 245da30c..545d4617 100644
--- a/src/hasp/hasp_dispatch.h
+++ b/src/hasp/hasp_dispatch.h
@@ -1,10 +1,19 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DISPATCH_H
#define HASP_DISPATCH_H
#include "hasplib.h"
+// #include "freertos/queue.h"
+
+// QueueHandle_t message_queue;
+// typedef struct
+// {
+// char* topic; //[64];
+// char* payload; //[512];
+// uint source;
+// } dispatch_message_t;
struct dispatch_conf_t
{
@@ -91,6 +100,7 @@ void dispatch_state_val(const char* topic, hasp_event_t eventid, int32_t val);
void dispatch_state_antiburn(hasp_event_t eventid);
/* ===== Getter and Setter Functions ===== */
+void dispatch_get_discovery_data(JsonDocument& doc);
/* ===== Read/Write Configuration ===== */
diff --git a/src/hasp/hasp_event.cpp b/src/hasp/hasp_event.cpp
index 433bc7ea..0b52e91b 100644
--- a/src/hasp/hasp_event.cpp
+++ b/src/hasp/hasp_event.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/* ********************************************************************************************
@@ -176,9 +176,9 @@ void event_timer_clock(lv_task_t* task)
timeval curTime;
int rslt = gettimeofday(&curTime, NULL);
(void)rslt; // unused
- time_t seconds = curTime.tv_sec;
- useconds_t tv_msec = curTime.tv_usec / 1000;
- tm* timeinfo = localtime(&seconds);
+ time_t seconds = curTime.tv_sec;
+ auto tv_msec = curTime.tv_usec / 1000;
+ tm* timeinfo = localtime(&seconds);
lv_task_set_period(task, data->interval - tv_msec);
char buffer[128] = {0};
@@ -287,14 +287,20 @@ static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16
{
char data[512];
{
+ StaticJsonDocument<256> doc;
+ size_t len = text ? strlen(text) : 0;
+ doc.set(text); // use text as-is
+ char serialized_text[256];
+ len = serializeJson(doc, serialized_text, sizeof(serialized_text));
+
char eventname[8];
Parser::get_event_name(eventid, eventname, sizeof(eventname));
-
if(const char* tag = my_obj_get_tag(obj))
- snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\",\"tag\":%s}"), eventname,
- val, text, tag);
+ snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":%s,\"tag\":%s}"), eventname,
+ val, serialized_text, tag);
else
- snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":\"%s\"}"), eventname, val, text);
+ snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d,\"text\":%s}"), eventname, val,
+ serialized_text);
}
event_send_object_data(obj, data);
}
@@ -435,7 +441,6 @@ void textarea_event_handler(lv_obj_t* obj, lv_event_t event)
{
char eventname[8];
Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname));
-
if(const char* tag = my_obj_get_tag(obj))
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"text\":\"%s\",\"tag\":%s}"), eventname,
lv_textarea_get_text(obj), tag);
@@ -527,7 +532,6 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
{
char eventname[8];
Parser::get_event_name(last_value_sent, eventname, sizeof(eventname));
-
if(const char* tag = my_obj_get_tag(obj))
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"tag\":%s}"), eventname, tag);
else
@@ -835,7 +839,7 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event)
if(!translate_event(obj, event, hasp_event_id) || event == LV_EVENT_VALUE_CHANGED) return;
/* Get the new value */
- lv_color_t color = lv_cpicker_get_color(obj);
+ lv_color_t color = lv_cpicker_get_color(obj);
lv_cpicker_color_mode_t mode = lv_cpicker_get_color_mode(obj);
if(hasp_event_id == HASP_EVENT_CHANGED && last_color_sent.full == color.full) return; // same value as before
@@ -853,12 +857,16 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event)
if(const char* tag = my_obj_get_tag(obj))
snprintf_P(data, sizeof(data),
- PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%d,\"v\":%d,\"tag\":%s}"),
- eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, hsv.s, hsv.v, tag);
+ PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%"
+ "d,\"v\":%d,\"tag\":%s}"),
+ eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h,
+ hsv.s, hsv.v, tag);
else
snprintf_P(data, sizeof(data),
- PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%d,\"v\":%d}"), eventname,
- c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h, hsv.s, hsv.v);
+ PSTR("{\"event\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d,\"h\":%d,\"s\":%"
+ "d,\"v\":%d}"),
+ eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue, hsv.h,
+ hsv.s, hsv.v);
}
event_send_object_data(obj, data);
@@ -907,4 +915,4 @@ void calendar_event_handler(lv_obj_t* obj, lv_event_t event)
// event_update_group(obj->user_data.groupid, obj, val, min, max);
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/hasp/hasp_event.h b/src/hasp/hasp_event.h
index 0bbd55ca..f4c5a06b 100644
--- a/src/hasp/hasp_event.h
+++ b/src/hasp/hasp_event.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_EVENT_H
diff --git a/src/hasp/hasp_font.cpp b/src/hasp/hasp_font.cpp
index 1f50c81a..d86a4f14 100644
--- a/src/hasp/hasp_font.cpp
+++ b/src/hasp/hasp_font.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include
@@ -68,7 +68,7 @@ void font_setup()
} else {
LOG_ERROR(TAG_FONT, F("FreeType " D_SERVICE_START_FAILED));
}
-#elif defined(WINDOWS) || defined(POSIX)
+#elif HASP_TARGET_PC
#else
#endif
diff --git a/src/hasp/hasp_font.h b/src/hasp/hasp_font.h
index f2e7eee3..c98351bd 100644
--- a/src/hasp/hasp_font.h
+++ b/src/hasp/hasp_font.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_FONT_H
diff --git a/src/hasp/hasp_lvfs.cpp b/src/hasp/hasp_lvfs.cpp
index 3275dc48..32ba5b63 100644
--- a/src/hasp/hasp_lvfs.cpp
+++ b/src/hasp/hasp_lvfs.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "lv_fs_if.h"
diff --git a/src/hasp/hasp_lvfs.h b/src/hasp/hasp_lvfs.h
index 40099f38..e86bfc71 100644
--- a/src/hasp/hasp_lvfs.h
+++ b/src/hasp/hasp_lvfs.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_LVFS_H
diff --git a/src/hasp/hasp_mem.cpp b/src/hasp/hasp_mem.cpp
index 51942271..09267fa1 100644
--- a/src/hasp/hasp_mem.cpp
+++ b/src/hasp/hasp_mem.cpp
@@ -1,5 +1,5 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include
@@ -53,6 +53,11 @@ void* lodepng_malloc(size_t size)
if(size > LODEPNG_MAX_ALLOC) return 0;
#endif
+ // void* ptr = hasp_malloc(size);
+ // if(ptr) return ptr;
+
+ // /* PSram was full retry after clearing cache*/
+ // lv_img_cache_invalidate_src(NULL);
return hasp_malloc(size);
}
diff --git a/src/hasp/hasp_nvs.cpp b/src/hasp/hasp_nvs.cpp
index 439a1bea..1ce54e93 100644
--- a/src/hasp/hasp_nvs.cpp
+++ b/src/hasp/hasp_nvs.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifdef ESP32
@@ -6,6 +6,8 @@
#include "hasplib.h"
#include "hasp_nvs.h"
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
bool nvs_user_begin(Preferences& preferences, const char* key, bool readonly)
{
if(preferences.begin(key, false, "config")) {
@@ -22,16 +24,16 @@ bool nvs_user_begin(Preferences& preferences, const char* key, bool readonly)
bool nvs_clear_user_config()
{
- const char* name[] = {FP_TIME, FP_OTA, FP_HTTP, FP_FTP, FP_MQTT, FP_WIFI};
+ const char* name[] = {FP_TIME, FP_OTA, FP_HTTP, FP_FTP, FP_MQTT, FP_WIFI, FP_WG};
Preferences preferences;
bool state = true;
- for(int i = 0; i < sizeof(name) / sizeof(name[0]); i++) {
+ for(int i = 0; i < ARRAY_SIZE(name); i++) {
if(preferences.begin(name[i], false) && !preferences.clear()) state = false;
preferences.end();
}
- for(int i = 0; i < sizeof(name) / sizeof(name[0]); i++) {
+ for(int i = 0; i < ARRAY_SIZE(name); i++) {
if(preferences.begin(name[i], false, "config") && !preferences.clear()) state = false;
preferences.end();
}
@@ -226,19 +228,30 @@ void nvs_setup()
nvs_stats.free_entries, nvs_stats.total_entries);
{ // TODO: remove migratrion of keys from default NVS partition to CONFIG partition
- const char* name[8] = {FP_TIME, FP_OTA, FP_HTTP, FP_FTP, FP_MQTT, FP_WIFI};
+ const struct {
+ const char* name;
+ const char* config;
+ } sec[] = {
+ { .name = FP_TIME, .config = FP_CONFIG_PASS },
+ { .name = FP_OTA, .config = FP_CONFIG_PASS },
+ { .name = FP_HTTP, .config = FP_CONFIG_PASS },
+ { .name = FP_FTP, .config = FP_CONFIG_PASS },
+ { .name = FP_MQTT, .config = FP_CONFIG_PASS },
+ { .name = FP_WIFI, .config = FP_CONFIG_PASS },
+ { .name = FP_WG, .config = FP_CONFIG_PRIVATE_KEY }
+ };
Preferences oldPrefs, newPrefs;
- for(int i = 0; i < 6; i++) {
- if(oldPrefs.begin(name[i], false) && newPrefs.begin(name[i], false, "config")) {
- LOG_INFO(TAG_NVS, "opened %s", name[i]);
- String password = oldPrefs.getString(FP_CONFIG_PASS, D_PASSWORD_MASK);
+ for(int i = 0; i < ARRAY_SIZE(sec); i++) {
+ if(oldPrefs.begin(sec[i].name, false) && newPrefs.begin(sec[i].name, false, "config")) {
+ LOG_INFO(TAG_NVS, "opened %s", sec[i].name);
+ String password = oldPrefs.getString(sec[i].config, D_PASSWORD_MASK);
if(password != D_PASSWORD_MASK) {
- LOG_INFO(TAG_NVS, "found %s %s => %s", name[i], D_PASSWORD_MASK, password.c_str());
- size_t len = newPrefs.putString(FP_CONFIG_PASS, password);
+ LOG_INFO(TAG_NVS, "found %s %s => %s", sec[i].name, D_PASSWORD_MASK, password.c_str());
+ size_t len = newPrefs.putString(sec[i].config, password);
if(len == password.length()) {
- oldPrefs.remove(FP_CONFIG_PASS);
- LOG_INFO(TAG_NVS, "Moved %s key %s to new NVS partition", name[i], FP_CONFIG_PASS);
+ oldPrefs.remove(sec[i].config);
+ LOG_INFO(TAG_NVS, "Moved %s key %s to new NVS partition", sec[i].name, sec[i].config);
}
}
}
diff --git a/src/hasp/hasp_nvs.h b/src/hasp/hasp_nvs.h
index 809f65ca..ef87e5a6 100644
--- a/src/hasp/hasp_nvs.h
+++ b/src/hasp/hasp_nvs.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_NVS_H
diff --git a/src/hasp/hasp_object.cpp b/src/hasp/hasp_object.cpp
index 08fd170e..68b1f8eb 100644
--- a/src/hasp/hasp_object.cpp
+++ b/src/hasp/hasp_object.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/* ********************************************************************************************
@@ -179,7 +179,7 @@ int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc)
{
int i = 0;
-#if defined(WINDOWS) || defined(POSIX) || defined(ESP32)
+#if HASP_TARGET_PC || defined(ESP32)
std::string v;
v.reserve(64);
diff --git a/src/hasp/hasp_object.h b/src/hasp/hasp_object.h
index cd1a0a20..5bfe157a 100644
--- a/src/hasp/hasp_object.h
+++ b/src/hasp/hasp_object.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_OBJECT_H
diff --git a/src/hasp/hasp_page.cpp b/src/hasp/hasp_page.cpp
index bb970e57..23e72c2a 100644
--- a/src/hasp/hasp_page.cpp
+++ b/src/hasp/hasp_page.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
@@ -244,7 +244,11 @@ void Page::load_jsonl(const char* pagesfile)
path[0] = '.';
path[1] = '\0';
strcat(path, pagesfile);
+#if defined(WINDOWS)
path[1] = '\\';
+#elif defined(POSIX)
+ path[1] = '/';
+#endif
LOG_TRACE(TAG_HASP, F("Loading %s from disk..."), path);
std::ifstream f(path); // taking file as inputstream
diff --git a/src/hasp/hasp_page.h b/src/hasp/hasp_page.h
index cfc9b27a..44c85d56 100644
--- a/src/hasp/hasp_page.h
+++ b/src/hasp/hasp_page.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_PAGES_H
diff --git a/src/hasp/hasp_parser.cpp b/src/hasp/hasp_parser.cpp
index 0b85e415..a44a9741 100644
--- a/src/hasp/hasp_parser.cpp
+++ b/src/hasp/hasp_parser.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifdef ARDUINO
@@ -136,34 +136,34 @@ void Parser::get_event_name(uint8_t eventid, char* buffer, size_t size)
{
switch(eventid) {
case HASP_EVENT_ON:
- memcpy_P(buffer, PSTR("on"), size);
+ memcpy_P(buffer, PSTR("on"), 3);
break;
case HASP_EVENT_OFF:
- memcpy_P(buffer, PSTR("off"), size);
+ memcpy_P(buffer, PSTR("off"), 4);
break;
case HASP_EVENT_UP:
- memcpy_P(buffer, PSTR("up"), size);
+ memcpy_P(buffer, PSTR("up"), 3);
break;
case HASP_EVENT_DOWN:
- memcpy_P(buffer, PSTR("down"), size);
+ memcpy_P(buffer, PSTR("down"), 5);
break;
case HASP_EVENT_RELEASE:
- memcpy_P(buffer, PSTR("release"), size);
+ memcpy_P(buffer, PSTR("release"), 8);
break;
case HASP_EVENT_LONG:
- memcpy_P(buffer, PSTR("long"), size);
+ memcpy_P(buffer, PSTR("long"), 5);
break;
case HASP_EVENT_HOLD:
- memcpy_P(buffer, PSTR("hold"), size);
+ memcpy_P(buffer, PSTR("hold"), 5);
break;
case HASP_EVENT_LOST:
- memcpy_P(buffer, PSTR("lost"), size);
+ memcpy_P(buffer, PSTR("lost"), 5);
break;
case HASP_EVENT_CHANGED:
- memcpy_P(buffer, PSTR("changed"), size);
+ memcpy_P(buffer, PSTR("changed"), 8);
break;
default:
- memcpy_P(buffer, PSTR("unknown"), size);
+ memcpy_P(buffer, PSTR("unknown"), 8);
}
}
@@ -238,4 +238,4 @@ long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/hasp/hasp_parser.h b/src/hasp/hasp_parser.h
index 4b9a8748..d1c44bea 100644
--- a/src/hasp/hasp_parser.h
+++ b/src/hasp/hasp_parser.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_PARSER_H
diff --git a/src/hasp/hasp_style.cpp b/src/hasp/hasp_style.cpp
index f0281998..b783f006 100644
--- a/src/hasp/hasp_style.cpp
+++ b/src/hasp/hasp_style.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_attribute.h" /*To see all the hashes*/
diff --git a/src/hasp/hasp_task.cpp b/src/hasp/hasp_task.cpp
index 23fb2027..a6d01900 100644
--- a/src/hasp/hasp_task.cpp
+++ b/src/hasp/hasp_task.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
diff --git a/src/hasp/hasp_task.h b/src/hasp/hasp_task.h
index eef11077..1630900c 100644
--- a/src/hasp/hasp_task.h
+++ b/src/hasp/hasp_task.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TASK_H
diff --git a/src/hasp/lv_theme_hasp.h b/src/hasp/lv_theme_hasp.h
index c7dd2c32..a1995bed 100644
--- a/src/hasp/lv_theme_hasp.h
+++ b/src/hasp/lv_theme_hasp.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef LV_THEME_HASP_H
diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp
index 61811a83..75ac0bb5 100644
--- a/src/hasp_config.cpp
+++ b/src/hasp_config.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if HASP_USE_CONFIG > 0
@@ -8,7 +8,9 @@
#include "hasp_config.h"
#include "hasp_debug.h"
#include "hasp_gui.h"
+#if HASP_TARGET_ARDUINO
#include "hal/hasp_hal.h"
+#endif
// #include "hasp_ota.h" included in conf
// #include "hasp_filesystem.h" included in conf
@@ -21,7 +23,9 @@
#include "EEPROM.h"
#endif
+#if HASP_USE_EEPROM > 0
#include "StreamUtils.h" // For EEPromStream
+#endif
extern uint16_t dispatchTelePeriod;
extern uint32_t dispatchLastMillis;
@@ -29,6 +33,7 @@ extern uint32_t dispatchLastMillis;
extern gui_conf_t gui_settings;
extern dispatch_conf_t dispatch_settings;
+#if HASP_TARGET_ARDUINO
void confDebugSet(const __FlashStringHelper* fstr_name)
{
/*char buffer[128];
@@ -36,6 +41,7 @@ void confDebugSet(const __FlashStringHelper* fstr_name)
debugPrintln(buffer);*/
LOG_VERBOSE(TAG_CONF, F(D_BULLET "%S set"), fstr_name);
}
+#endif
void confDebugSet(const char* fstr_name)
{
/*char buffer[128];
@@ -44,6 +50,7 @@ void confDebugSet(const char* fstr_name)
LOG_VERBOSE(TAG_CONF, F(D_BULLET "%s set"), fstr_name);
}
+#if HASP_TARGET_ARDUINO
bool configSet(bool& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name)
{
if(!setting.isNull()) {
@@ -117,6 +124,20 @@ bool configSet(lv_color_t& value, const JsonVariant& setting, const __FlashStrin
}
return false;
}
+bool configSet(char *value, size_t size, const JsonVariant& setting, const __FlashStringHelper* fstr_name)
+{
+ if(!setting.isNull()) {
+ const char *val = setting;
+ if(strcmp(value, val) != 0) {
+ confDebugSet(fstr_name);
+ strncpy(value, val, size - 1);
+ value[size - 1] = '\0';
+ return true;
+ }
+ }
+ return false;
+}
+#endif
bool configSet(bool& value, const JsonVariant& setting, const char* fstr_name)
{
@@ -194,39 +215,43 @@ bool configSet(lv_color_t& value, const JsonVariant& setting, const char* fstr_n
void configSetupDebug(JsonDocument& settings)
{
+#if HASP_TARGET_ARDUINO
debugSetup(settings[FPSTR(FP_DEBUG)]);
+#endif
debugStart(); // Debug started, now we can use it; HASP header sent
}
-void configStorePasswords(JsonDocument& settings, String& wifiPass, String& mqttPass, String& httpPass)
+void configStorePasswords(JsonDocument& settings, String& wifiPass, String& mqttPass, String& httpPass, String &wgPrivKey)
{
const char* pass = ("pass");
wifiPass = settings[FPSTR(FP_WIFI)][pass].as();
mqttPass = settings[FPSTR(FP_MQTT)][pass].as();
httpPass = settings[FPSTR(FP_HTTP)][pass].as();
+ wgPrivKey = settings[FPSTR(FP_WG)][FPSTR(FP_CONFIG_PRIVATE_KEY)].as();
}
-void configRestorePasswords(JsonDocument& settings, String& wifiPass, String& mqttPass, String& httpPass)
+void configRestorePasswords(JsonDocument& settings, String& wifiPass, String& mqttPass, String& httpPass, String& wgPrivKey)
{
const char* pass = ("pass");
if(!settings[FPSTR(FP_WIFI)][pass].isNull()) settings[FPSTR(FP_WIFI)][pass] = wifiPass;
if(!settings[FPSTR(FP_MQTT)][pass].isNull()) settings[FPSTR(FP_MQTT)][pass] = mqttPass;
if(!settings[FPSTR(FP_HTTP)][pass].isNull()) settings[FPSTR(FP_HTTP)][pass] = httpPass;
+ if(!settings[FPSTR(FP_WG)][FPSTR(FP_CONFIG_PRIVATE_KEY)].isNull()) settings[FPSTR(FP_WG)][FPSTR(FP_CONFIG_PRIVATE_KEY)] = wgPrivKey;
}
void configMaskPasswords(JsonDocument& settings)
{
String passmask = F(D_PASSWORD_MASK);
- configRestorePasswords(settings, passmask, passmask, passmask);
+ configRestorePasswords(settings, passmask, passmask, passmask, passmask);
}
DeserializationError configParseFile(String& configFile, JsonDocument& settings)
{
+ DeserializationError result = DeserializationError::InvalidInput;
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
File file = HASP_FS.open(configFile, "r");
- DeserializationError result;
if(file) {
// size_t size = file.size();
@@ -239,41 +264,61 @@ DeserializationError configParseFile(String& configFile, JsonDocument& settings)
return result;
}
return DeserializationError::InvalidInput;
+#elif HASP_TARGET_PC
+ lv_fs_file_t f;
+ lv_fs_res_t res;
+ lv_fs_open(&f, "L:/config.json", LV_FS_MODE_RD);
+ if(res == LV_FS_RES_OK) {
+ uint32_t size = 0, read = 0;
+ if(lv_fs_size(&f, &size) == LV_FS_RES_OK && size != 0) {
+ char* buf = (char*)malloc(size + 1);
+ if(lv_fs_read(&f, buf, size, &read) == LV_FS_RES_OK && read == size) {
+ result = deserializeJson(settings, buf);
+ }
+ }
+ lv_fs_close(&f);
+ return result;
+ }
+ LOG_ERROR(TAG_HASP, F("Opening config.json from FS failed %d"), res);
+ return result;
#else
- return DeserializationError::InvalidInput;
+ return result;
#endif
}
DeserializationError configRead(JsonDocument& settings, bool setupdebug)
{
- String configFile((char*)0);
+ String configFile;
configFile.reserve(32);
configFile = String(FPSTR(FP_HASP_CONFIG_FILE));
DeserializationError error;
-#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
+ if(setupdebug) configSetupDebug(settings); // Now we can use log
+
+#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 || HASP_TARGET_PC
error = configParseFile(configFile, settings);
if(!error) {
- String output, wifiPass, mqttPass, httpPass;
+ String output, wifiPass, mqttPass, httpPass, wgPrivKey;
/* Load Debug params */
if(setupdebug) {
- configSetupDebug(settings); // Now we can use log
LOG_INFO(TAG_CONF, F("SPI flash FS mounted"));
+#if HASP_TARGET_ARDUINO
filesystemInfo();
filesystemList();
+#endif
}
LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str());
- configStorePasswords(settings, wifiPass, mqttPass, httpPass);
+ configStorePasswords(settings, wifiPass, mqttPass, httpPass, wgPrivKey);
// Output settings in log with masked passwords
configMaskPasswords(settings);
serializeJson(settings, output);
LOG_VERBOSE(TAG_CONF, output.c_str());
- configRestorePasswords(settings, wifiPass, mqttPass, httpPass);
+ configRestorePasswords(settings, wifiPass, mqttPass, httpPass, wgPrivKey);
LOG_INFO(TAG_CONF, F(D_FILE_LOADED), configFile.c_str());
// if(setupdebug) debugSetup();
@@ -289,9 +334,6 @@ DeserializationError configRead(JsonDocument& settings, bool setupdebug)
#endif
- // File does not exist or error reading file
- if(setupdebug) configSetupDebug(settings); // Now we can use log
-
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
LOG_ERROR(TAG_CONF, F(D_FILE_LOAD_FAILED), configFile.c_str());
#endif
@@ -345,16 +387,16 @@ void configBackupToEeprom()
*/
void configWrite()
{
- String configFile((char*)0);
+ String configFile;
configFile.reserve(32);
configFile = String(FPSTR(FP_HASP_CONFIG_FILE));
- String settingsChanged((char*)0);
+ String settingsChanged;
settingsChanged.reserve(128);
settingsChanged = F(D_CONFIG_CHANGED);
/* Read Config File */
- DynamicJsonDocument doc(8 * 256);
+ DynamicJsonDocument doc(MAX_CONFIG_JSON_ALLOC_SIZE);
LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str());
configRead(doc, false);
LOG_INFO(TAG_CONF, F(D_FILE_LOADED), configFile.c_str());
@@ -382,6 +424,17 @@ void configWrite()
}
#endif
+#if HASP_USE_WIREGUARD > 0
+ module = FPSTR(FP_WG);
+ if(settings[module].as().isNull()) settings.createNestedObject(module);
+ changed = wgGetConfig(settings[module]);
+ if(changed) {
+ LOG_VERBOSE(TAG_WG, settingsChanged.c_str());
+ configOutput(settings[module], TAG_WG);
+ writefile = true;
+ }
+#endif
+
#if HASP_USE_MQTT > 0
module = FPSTR(FP_MQTT);
if(settings[module].as().isNull()) settings.createNestedObject(module);
@@ -436,6 +489,7 @@ void configWrite()
}
#endif
+#if HASP_TARGET_ARDUINO
module = FPSTR(FP_DEBUG);
if(settings[module].as().isNull()) settings.createNestedObject(module);
changed = debugGetConfig(settings[module]);
@@ -444,6 +498,7 @@ void configWrite()
configOutput(settings[module], TAG_DEBG);
writefile = true;
}
+#endif
if(settings[FPSTR(FP_GUI)].as().isNull()) settings.createNestedObject(FPSTR(FP_GUI));
changed = guiGetConfig(settings[FPSTR(FP_GUI)]);
@@ -515,7 +570,7 @@ void configWrite()
void configSetup()
{
- DynamicJsonDocument settings(1024 + 512);
+ DynamicJsonDocument settings(MAX_CONFIG_JSON_ALLOC_SIZE);
for(uint32_t i = 0; i < 2; i++) {
if(i == 0) {
@@ -535,9 +590,10 @@ void configSetup()
configRead(settings, true);
}
- // #if HASP_USE_SPIFFS > 0
+#if HASP_TARGET_ARDUINO
LOG_INFO(TAG_DEBG, F("Loading debug settings"));
debugSetConfig(settings[FPSTR(FP_DEBUG)]);
+#endif
LOG_INFO(TAG_GPIO, F("Loading GUI settings"));
guiSetConfig(settings[FPSTR(FP_GUI)]);
LOG_INFO(TAG_HASP, F("Loading HASP settings"));
@@ -549,6 +605,11 @@ void configSetup()
wifiSetConfig(settings[FPSTR(FP_WIFI)]);
#endif
+#if HASP_USE_WIREGUARD > 0
+ LOG_INFO(TAG_WG, F("Loading WireGuard settings"));
+ wgSetConfig(settings[FPSTR(FP_WG)]);
+#endif
+
#if HASP_USE_MQTT > 0
LOG_INFO(TAG_MQTT, F("Loading MQTT settings"));
mqttSetConfig(settings[FPSTR(FP_MQTT)]);
@@ -574,6 +635,12 @@ void configSetup()
gpioSetConfig(settings[FPSTR(FP_GPIO)]);
#endif
+ // target-specific config
+#if defined(POSIX)
+ LOG_INFO(TAG_CONF, F("Loading POSIX-specific settings"));
+ haspDevice.set_config(settings[F("posix")]);
+#endif
+
LOG_INFO(TAG_CONF, F(D_CONFIG_LOADED));
}
// #endif
@@ -584,15 +651,15 @@ void configLoop(void)
void configOutput(const JsonObject& settings, uint8_t tag)
{
- String output((char*)0);
+ String output;
output.reserve(128);
serializeJson(settings, output);
- String passmask((char*)0);
+ String passmask;
passmask.reserve(128);
passmask = F("\"pass\":\"" D_PASSWORD_MASK "\"");
- String password((char*)0);
+ String password;
password.reserve(128);
String pass = F("pass");
@@ -600,28 +667,61 @@ void configOutput(const JsonObject& settings, uint8_t tag)
password = F("\"pass\":\"");
password += settings[pass].as();
password += F("\"");
+#if HASP_TARGET_ARDUINO
output.replace(password, passmask);
+#elif HASP_TARGET_PC
+ size_t pos = 0;
+ if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask);
+#endif
}
if(!settings[FPSTR(FP_WIFI)][pass].isNull()) {
password = F("\"pass\":\"");
password += settings[FPSTR(FP_WIFI)][pass].as();
password += F("\"");
+#if HASP_TARGET_ARDUINO
output.replace(password, passmask);
+#elif HASP_TARGET_PC
+ size_t pos = 0;
+ if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask);
+#endif
}
if(!settings[FPSTR(FP_MQTT)][pass].isNull()) {
password = F("\"pass\":\"");
password += settings[FPSTR(FP_MQTT)][pass].as();
password += F("\"");
+#if HASP_TARGET_ARDUINO
output.replace(password, passmask);
+#elif HASP_TARGET_PC
+ size_t pos = 0;
+ if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask);
+#endif
}
if(!settings[FPSTR(FP_HTTP)][pass].isNull()) {
password = F("\"pass\":\"");
password += settings[FPSTR(FP_HTTP)][pass].as();
password += F("\"");
+#if HASP_TARGET_ARDUINO
output.replace(password, passmask);
+#elif HASP_TARGET_PC
+ size_t pos = 0;
+ if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask);
+#endif
+ }
+
+ if(!settings[FPSTR(FP_WG)][FPSTR(FP_CONFIG_PRIVATE_KEY)].isNull()) {
+ password = F("\"privkey\":\"");
+ password += settings[FPSTR(FP_WG)][FPSTR(FP_CONFIG_PRIVATE_KEY)].as();
+ password += F("\"");
+ passmask = F("\"privkey\":\"" D_PASSWORD_MASK "\"");
+#if HASP_TARGET_ARDUINO
+ output.replace(password, passmask);
+#elif HASP_TARGET_PC
+ size_t pos = 0;
+ if((pos = output.find(password)) != std::string::npos) output.replace(pos, password.size(), passmask);
+#endif
}
LOG_VERBOSE(tag, output.c_str());
@@ -649,4 +749,4 @@ bool configClearEeprom()
#endif
}
-#endif // HAS_USE_CONFIG
\ No newline at end of file
+#endif // HAS_USE_CONFIG
diff --git a/src/hasp_config.h b/src/hasp_config.h
index 3e465a95..04160d30 100644
--- a/src/hasp_config.h
+++ b/src/hasp_config.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if HASP_USE_CONFIG > 0
@@ -8,6 +8,8 @@
#include "hasplib.h"
+#define MAX_CONFIG_JSON_ALLOC_SIZE (2048)
+
/* ===== Default Event Processors ===== */
void configSetup(void);
void configLoop(void);
@@ -23,12 +25,15 @@ void configOutput(const JsonObject& settings, uint8_t tag);
bool configClearEeprom(void);
/* ===== Getter and Setter Functions ===== */
+#if HASP_TARGET_ARDUINO
bool configSet(bool& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
bool configSet(int8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
bool configSet(uint8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
bool configSet(uint16_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
bool configSet(int32_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
bool configSet(lv_color_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
+bool configSet(char* value, size_t size, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
+#endif
bool configSet(bool& value, const JsonVariant& setting, const char* fstr_name);
bool configSet(int8_t& value, const JsonVariant& setting, const char* fstr_name);
bool configSet(uint8_t& value, const JsonVariant& setting, const char* fstr_name);
@@ -38,8 +43,10 @@ bool configSet(lv_color_t& value, const JsonVariant& setting, const char* fstr_n
void configMaskPasswords(JsonDocument& settings);
/* ===== Read/Write Configuration ===== */
+#if HASP_TARGET_ARDUINO
void configSetConfig(JsonObject& settings);
void configGetConfig(JsonDocument& settings);
+#endif
/* json keys used in the configfile */
const char FP_CONFIG_STARTPAGE[] PROGMEM = "startpage";
@@ -69,6 +76,9 @@ const char FP_CONFIG_BROADCAST_TOPIC[] PROGMEM = "broadcast_t";
const char FP_CONFIG_BAUD[] PROGMEM = "baud";
const char FP_CONFIG_LOG[] PROGMEM = "log";
const char FP_CONFIG_PROTOCOL[] PROGMEM = "proto";
+const char FP_CONFIG_VPN_IP[] PROGMEM = "vpnip";
+const char FP_CONFIG_PRIVATE_KEY[] PROGMEM = "privkey";
+const char FP_CONFIG_PUBLIC_KEY[] PROGMEM = "pubkey";
const char FP_GUI_ROTATION[] PROGMEM = "rotate";
const char FP_GUI_INVERT[] PROGMEM = "invert";
const char FP_GUI_TICKPERIOD[] PROGMEM = "tick";
@@ -87,6 +97,7 @@ const char FP_GPIO_CONFIG[] PROGMEM = "config";
const char FP_HASP_CONFIG_FILE[] PROGMEM = "/config.json";
const char FP_WIFI[] PROGMEM = "wifi";
+const char FP_WG[] PROGMEM = "wg";
const char FP_MQTT[] PROGMEM = "mqtt";
const char FP_HTTP[] PROGMEM = "http";
const char FP_FTP[] PROGMEM = "ftp";
@@ -100,4 +111,4 @@ const char FP_OTA[] PROGMEM = "ota";
#endif
-#endif // HASP_USE_CONFIG
\ No newline at end of file
+#endif // HASP_USE_CONFIG
diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp
index df523c19..c249ece5 100644
--- a/src/hasp_debug.cpp
+++ b/src/hasp_debug.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
@@ -8,12 +8,12 @@
#include "hasp_debug.h"
#include "hasp_macro.h"
-#if(!defined(WINDOWS)) && (!defined(POSIX))
+#if HASP_TARGET_ARDUINO
#define debug_print(io, ...) io->printf(__VA_ARGS__)
#define debug_newline(io) io->println()
-#else
+#elif HASP_TARGET_PC
#include
#include
#include
@@ -21,6 +21,18 @@
#define debug_print(io, ...) fprintf(stdout, __VA_ARGS__)
#define debug_newline(io) fprintf(stdout, "\n")
+#if defined(WINDOWS)
+#include
+#include
+#define cwd _getcwd
+#endif
+
+#if defined(POSIX)
+#include
+#include
+#define cwd getcwd
+#endif
+
#endif
bool debugAnsiCodes = false;
@@ -99,7 +111,7 @@ static inline void debug_flush()
HASP_SERIAL.flush();
#endif
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
fflush(stdout);
#endif
}
@@ -116,22 +128,22 @@ void debugEverySecond()
void debugStart(void)
{
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
debug_newline();
debugPrintHaspHeader(NULL);
debug_newline();
+ char curdir[PATH_MAX];
+ LOG_INFO(TAG_DEBG, F("Configuration directory: %s"), cwd(curdir, sizeof(curdir)));
LOG_INFO(TAG_DEBG, F("Environment: " PIOENV));
LOG_INFO(TAG_DEBG, F("Console started"));
debug_flush();
-#else
+#endif
#if HASP_USE_CONSOLE > 0
consoleSetup();
#endif
-
-#endif
}
void debugStop()
@@ -321,6 +333,10 @@ void debug_get_tag(uint8_t tag, char* buffer)
memcpy_P(buffer, PSTR("CUST"), 5);
break;
+ case TAG_WG:
+ memcpy_P(buffer, PSTR("WG "), 5);
+ break;
+
default:
memcpy_P(buffer, PSTR("----"), 5);
break;
@@ -441,4 +457,4 @@ void debugPrintPrefix(uint8_t tag, int level, Print* _logOutput)
#else
debug_print(_logOutput, PSTR(" %s: "), buffer);
#endif
-}
\ No newline at end of file
+}
diff --git a/src/hasp_debug.h b/src/hasp_debug.h
index b805004e..ea77d54a 100644
--- a/src/hasp_debug.h
+++ b/src/hasp_debug.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DEBUG_H
@@ -17,7 +17,7 @@
#include "lang/lang.h"
-#if(!defined(WINDOWS)) && (!defined(POSIX))
+#if HASP_TARGET_ARDUINO
/* ===== Default Event Processors ===== */
void debugSetup(JsonObject settings);
@@ -194,6 +194,7 @@ enum {
TAG_FTP = 68,
TAG_TIME = 69,
TAG_NETW = 70,
+ TAG_WG = 71,
TAG_LVGL = 90,
TAG_LVFS = 91,
diff --git a/src/hasp_eeprom.cpp b/src/hasp_eeprom.cpp
index 4a576c4a..dc3f83da 100644
--- a/src/hasp_eeprom.cpp
+++ b/src/hasp_eeprom.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h" // load first
diff --git a/src/hasp_eeprom.h b/src/hasp_eeprom.h
index 4d6cde2e..fa10b893 100644
--- a/src/hasp_eeprom.h
+++ b/src/hasp_eeprom.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_EEPROM_H
diff --git a/src/hasp_filesystem.cpp b/src/hasp_filesystem.cpp
index 56c96cc3..ac39a344 100644
--- a/src/hasp_filesystem.cpp
+++ b/src/hasp_filesystem.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifdef ARDUINO
diff --git a/src/hasp_filesystem.h b/src/hasp_filesystem.h
index 3bb3d490..0299fc7f 100644
--- a/src/hasp_filesystem.h
+++ b/src/hasp_filesystem.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_FILESYSTEM_H
diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp
index 3d05a80e..13caf317 100644
--- a/src/hasp_gui.cpp
+++ b/src/hasp_gui.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
@@ -207,21 +207,8 @@ static inline void gui_init_images()
static inline void gui_init_filesystems()
{
#if LV_USE_FS_IF != 0
- //_lv_fs_init(); // lvgl File System -- not needed, it done in lv_init() when LV_USE_FILESYSTEM is set
LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_ENABLED));
lv_fs_if_init(); // auxiliary file system drivers
- // filesystem_list_path("L:/");
-
- lv_fs_file_t f;
- lv_fs_res_t res;
- res = lv_fs_open(&f, "L:/config.json", LV_FS_MODE_RD);
- if(res == LV_FS_RES_OK) {
- LOG_VERBOSE(TAG_HASP, F("TEST Opening config.json OK"));
- lv_fs_close(&f);
- } else {
- LOG_ERROR(TAG_HASP, F("TEST Opening config.json from FS failed %d"), res);
- }
-
#else
LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_DISABLED));
#endif
@@ -305,17 +292,27 @@ void guiSetup()
#endif
disp_drv.monitor_cb = gui_monitor_cb;
+ // register a touchscreen/mouse driver - only on real hardware and SDL2
+ // Win32 and POSIX handles input drivers in tft_driver
+#if TOUCH_DRIVER != -1 || USE_MONITOR
/* Initialize the touch pad */
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
-#if defined(WINDOWS) || defined(POSIX)
+#if USE_MONITOR && HASP_TARGET_PC
indev_drv.read_cb = mouse_read;
#else
indev_drv.read_cb = gui_touch_read;
#endif
lv_indev_t* mouse_indev = lv_indev_drv_register(&indev_drv);
mouse_indev->driver.type = LV_INDEV_TYPE_POINTER;
+#else
+ // find the first registered input device to add a cursor to
+ lv_indev_t* mouse_indev = NULL;
+ while((mouse_indev = lv_indev_get_next(mouse_indev))) {
+ if(mouse_indev->driver.type == LV_INDEV_TYPE_POINTER) break;
+ }
+#endif
/*Set a cursor for the mouse*/
LOG_TRACE(TAG_GUI, F("Initialize Cursor"));
@@ -336,16 +333,18 @@ void guiSetup()
cursor = lv_img_create(mouse_layer, NULL); /*Create an image object for the cursor */
lv_img_set_src(cursor, &mouse_cursor_icon); /*Set the image source*/
#else
- cursor = lv_obj_create(mouse_layer, NULL); // show cursor object on every page
+ cursor = lv_obj_create(mouse_layer, NULL); // show cursor object on every page
lv_obj_set_size(cursor, 9, 9);
lv_obj_set_style_local_radius(cursor, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE);
lv_obj_set_style_local_bg_color(cursor, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_obj_set_style_local_bg_opa(cursor, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
#endif
gui_hide_pointer(false);
- lv_indev_set_cursor(mouse_indev, cursor); /*Connect the image object to the driver*/
+ if(mouse_indev != NULL) {
+ lv_indev_set_cursor(mouse_indev, cursor); /*Connect the image object to the driver*/
+ }
-#if !(defined(WINDOWS) || defined(POSIX))
+#if HASP_TARGET_ARDUINO
// drv_touch_init(gui_settings.rotation); // Touch driver
haspTouch.init(tft_width, tft_height);
haspTouch.set_calibration(gui_settings.cal_data);
@@ -386,7 +385,7 @@ IRAM_ATTR void guiLoop(void)
// tick.update();
#endif
-#if !(defined(WINDOWS) || defined(POSIX))
+#if HASP_TARGET_ARDUINO
// haspTouch.loop();
#endif
}
@@ -396,23 +395,34 @@ void guiEverySecond(void)
// nothing
}
-#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
-
#if HASP_USE_LVGL_TASK == 1
-static void gui_task(void* args)
+void gui_task(void* args)
{
LOG_TRACE(TAG_GUI, "Start to run LVGL");
- while(1) {
+ while(haspDevice.pc_is_running) {
+ // no idea what MQTT has to do with LVGL - the #if is copied from the code below
+#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
/* Try to take the semaphore, call lvgl related function on success */
- // if(pdTRUE == xSemaphoreTake(xGuiSemaphore, pdMS_TO_TICKS(10))) {
if(pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
lv_task_handler();
xSemaphoreGive(xGuiSemaphore);
vTaskDelay(pdMS_TO_TICKS(5));
}
+#else
+ // optimize lv_task_handler() by actually using the returned delay value
+ auto time_start = millis();
+ uint32_t sleep_time = lv_task_handler();
+ delay(sleep_time);
+ auto time_end = millis();
+ lv_tick_inc(time_end - time_start);
+#endif
}
}
+#endif // HASP_USE_LVGL_TASK
+#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
+
+#if HASP_USE_LVGL_TASK == 1
esp_err_t gui_setup_lvgl_task()
{
#if CONFIG_FREERTOS_UNICORE == 0
diff --git a/src/hasp_gui.h b/src/hasp_gui.h
index a95e877a..dd3680a8 100644
--- a/src/hasp_gui.h
+++ b/src/hasp_gui.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_GUI_H
@@ -60,6 +60,11 @@ uint32_t guiScreenshotEtag();
void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p);
void gui_antiburn_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p);
+/* ===== Main LVGL Task ===== */
+#if HASP_USE_LVGL_TASK == 1
+void gui_task(void* args);
+#endif
+
/* ===== Locks ===== */
#ifdef ESP32
IRAM_ATTR bool gui_acquire(TickType_t timeout);
@@ -73,4 +78,4 @@ bool guiGetConfig(const JsonObject& settings);
bool guiSetConfig(const JsonObject& settings);
#endif // HASP_USE_CONFIG
-#endif // HASP_GUI_H
\ No newline at end of file
+#endif // HASP_GUI_H
diff --git a/src/hasp_oobe.cpp b/src/hasp_oobe.cpp
index 291e3c47..1e9cb932 100644
--- a/src/hasp_oobe.cpp
+++ b/src/hasp_oobe.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if HASP_USE_CONFIG > 0
@@ -213,7 +213,7 @@ static void oobeSetupSsid(void)
lv_obj_set_style_local_text_font(pwd_ta, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, defaultfont);
lv_textarea_set_text(pwd_ta, "");
- lv_textarea_set_max_length(pwd_ta, 32);
+ lv_textarea_set_max_length(pwd_ta, MAX_PASSWORD_LENGTH);
lv_textarea_set_pwd_mode(pwd_ta, true);
lv_textarea_set_one_line(pwd_ta, true);
lv_textarea_set_cursor_hidden(pwd_ta, true);
diff --git a/src/hasp_oobe.h b/src/hasp_oobe.h
index 931ab220..b5b5ad0e 100644
--- a/src/hasp_oobe.h
+++ b/src/hasp_oobe.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if HASP_USE_CONFIG > 0
diff --git a/src/hasplib.h b/src/hasplib.h
index 1cd8691b..05ce613c 100644
--- a/src/hasplib.h
+++ b/src/hasplib.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifdef ARDUINO
diff --git a/src/lang/da_DK.h b/src/lang/da_DK.h
index b24d806d..13df8dbc 100644
--- a/src/lang/da_DK.h
+++ b/src/lang/da_DK.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Settings"
#define D_HTTP_FTP_SETTINGS "FTP Settings"
#define D_HTTP_WIFI_SETTINGS "Wifi Settings"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Settings"
#define D_HTTP_GPIO_SETTINGS "GPIO Settings"
#define D_HTTP_MDNS_SETTINGS "mDNS Settings"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch"
diff --git a/src/lang/de_DE.h b/src/lang/de_DE.h
index b24d806d..13df8dbc 100644
--- a/src/lang/de_DE.h
+++ b/src/lang/de_DE.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Settings"
#define D_HTTP_FTP_SETTINGS "FTP Settings"
#define D_HTTP_WIFI_SETTINGS "Wifi Settings"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Settings"
#define D_HTTP_GPIO_SETTINGS "GPIO Settings"
#define D_HTTP_MDNS_SETTINGS "mDNS Settings"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch"
diff --git a/src/lang/en_US.h b/src/lang/en_US.h
index b24d806d..13df8dbc 100644
--- a/src/lang/en_US.h
+++ b/src/lang/en_US.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Settings"
#define D_HTTP_FTP_SETTINGS "FTP Settings"
#define D_HTTP_WIFI_SETTINGS "Wifi Settings"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Settings"
#define D_HTTP_GPIO_SETTINGS "GPIO Settings"
#define D_HTTP_MDNS_SETTINGS "mDNS Settings"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch"
diff --git a/src/lang/es_ES.h b/src/lang/es_ES.h
index 45938eb1..613e47ba 100644
--- a/src/lang/es_ES.h
+++ b/src/lang/es_ES.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "Ajustes HTTP"
#define D_HTTP_HTTP_SETTINGS "Ajustes FTP"
#define D_HTTP_WIFI_SETTINGS "Ajustes Wifi"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "Ajustes MQTT"
#define D_HTTP_GPIO_SETTINGS "Ajustes GPIO"
#define D_HTTP_MDNS_SETTINGS "Ajustes mDNS"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Fallado"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Velocidad de enlace"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "Dirección MAC"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "Servidor DNS"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Toque la pantalla para ajustar WiFi o conectarse a un punto de acceso"
#define D_OOBE_SCAN_TO_CONNECT "Scanee para conectar"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Débil"
#define D_WIFI_RSSI_BAD "Muy baka"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Botón"
#define D_GPIO_TOUCH "Capacitive Touch" // new
diff --git a/src/lang/fr_FR.h b/src/lang/fr_FR.h
index aa5748a1..f84d3995 100644
--- a/src/lang/fr_FR.h
+++ b/src/lang/fr_FR.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "Paramètres HTTP"
#define D_HTTP_FTP_SETTINGS "Paramètres FTP"
#define D_HTTP_WIFI_SETTINGS "Paramètres Wifi"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "Paramètres MQTT"
#define D_HTTP_GPIO_SETTINGS "Paramètres GPIO"
#define D_HTTP_MDNS_SETTINGS "Paramètres mDNS"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Échec"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Vitesse de liaison"
#define D_INFO_FULL_DUPLEX "Duplex intégral"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "Adresse MAC"
#define D_INFO_GATEWAY "Passerelle"
#define D_INFO_DNS_SERVER "Serveur DNS"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Touchez l'écran pour configurer le WiFi ou branchez ce point d'accès:"
#define D_OOBE_SCAN_TO_CONNECT "Scanner pour se connecter"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Faible"
#define D_WIFI_RSSI_BAD "Très mauvais"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Interrupteur"
#define D_GPIO_BUTTON "Bouton"
#define D_GPIO_TOUCH "Touche Capacitive"
diff --git a/src/lang/hu_HU.h b/src/lang/hu_HU.h
index b24d806d..13df8dbc 100644
--- a/src/lang/hu_HU.h
+++ b/src/lang/hu_HU.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Settings"
#define D_HTTP_FTP_SETTINGS "FTP Settings"
#define D_HTTP_WIFI_SETTINGS "Wifi Settings"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Settings"
#define D_HTTP_GPIO_SETTINGS "GPIO Settings"
#define D_HTTP_MDNS_SETTINGS "mDNS Settings"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch"
diff --git a/src/lang/lang.h b/src/lang/lang.h
index 20411ecd..cfc2ed88 100644
--- a/src/lang/lang.h
+++ b/src/lang/lang.h
@@ -11,7 +11,7 @@
#endif
// language independent defines
-#define D_PASSWORD_MASK "********"
+#define D_PASSWORD_MASK "********" // beware: webui have this string hardcoded!
#define D_BULLET " * "
#define D_MANUFACTURER "openHASP"
#define D_BACK_ICON "↩ "
diff --git a/src/lang/nl_NL.h b/src/lang/nl_NL.h
index cafb4be1..9bec3fbd 100644
--- a/src/lang/nl_NL.h
+++ b/src/lang/nl_NL.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Instellingen"
#define D_HTTP_FTP_SETTINGS "FTP Instellingen"
#define D_HTTP_WIFI_SETTINGS "Wifi Instellingen"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Instellingen"
#define D_HTTP_GPIO_SETTINGS "GPIO Instellingen"
#define D_HTTP_MDNS_SETTINGS "mDNS Instellingen"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Mislukt"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Snelheid"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "Fysiek adres (MAC)"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Raak het scherm aan om WiFi in te stellen of meld je aan op AP:"
#define D_OOBE_SCAN_TO_CONNECT "Scan code"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Zwak"
#define D_WIFI_RSSI_BAD "Zeer Slecht"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Schakelaar"
#define D_GPIO_BUTTON "Drukknop"
#define D_GPIO_TOUCH "Aanraakknop"
diff --git a/src/lang/pt_BR.h b/src/lang/pt_BR.h
index 3c765fb9..169e3a8d 100644
--- a/src/lang/pt_BR.h
+++ b/src/lang/pt_BR.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Settings"
#define D_HTTP_FTP_SETTINGS "FTP Settings"
#define D_HTTP_WIFI_SETTINGS "Wifi Settings"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Settings"
#define D_HTTP_GPIO_SETTINGS "GPIO Settings"
#define D_HTTP_MDNS_SETTINGS "mDNS Settings"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch"
diff --git a/src/lang/pt_PT.h b/src/lang/pt_PT.h
index 56414b1b..265b26f0 100644
--- a/src/lang/pt_PT.h
+++ b/src/lang/pt_PT.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "Configurar HTTP"
#define D_HTTP_FTP_SETTINGS "Configurar FTP"
#define D_HTTP_WIFI_SETTINGS "Configurar Wifi"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "Configurar MQTT"
#define D_HTTP_GPIO_SETTINGS "Configurar GPIO"
#define D_HTTP_MDNS_SETTINGS "Configurar mDNS"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Em falha"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "Endereço MAC"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "Servidor DNS"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Toque no ecrã para configurar WiFi ou para se ligar a um access point"
#define D_OOBE_SCAN_TO_CONNECT "Procurar rede"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_BAD "Muito baixo"
#define D_WIFI_RSSI_FAIR "Decente"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Interruptor"
#define D_GPIO_BUTTON "Botão"
#define D_GPIO_TOUCH "Capacitive Touch" // new
diff --git a/src/lang/ro_RO.h b/src/lang/ro_RO.h
index b24d806d..13df8dbc 100644
--- a/src/lang/ro_RO.h
+++ b/src/lang/ro_RO.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Settings"
#define D_HTTP_FTP_SETTINGS "FTP Settings"
#define D_HTTP_WIFI_SETTINGS "Wifi Settings"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Settings"
#define D_HTTP_GPIO_SETTINGS "GPIO Settings"
#define D_HTTP_MDNS_SETTINGS "mDNS Settings"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch"
diff --git a/src/lang/zh_CN.h b/src/lang/zh_CN.h
index b24d806d..13df8dbc 100644
--- a/src/lang/zh_CN.h
+++ b/src/lang/zh_CN.h
@@ -127,6 +127,7 @@
#define D_HTTP_HTTP_SETTINGS "HTTP Settings"
#define D_HTTP_FTP_SETTINGS "FTP Settings"
#define D_HTTP_WIFI_SETTINGS "Wifi Settings"
+#define D_HTTP_WIREGUARD_SETTINGS "WireGuard Settings"
#define D_HTTP_MQTT_SETTINGS "MQTT Settings"
#define D_HTTP_GPIO_SETTINGS "GPIO Settings"
#define D_HTTP_MDNS_SETTINGS "mDNS Settings"
@@ -191,6 +192,7 @@
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
+#define D_INFO_WIREGUARD "WireGuard"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_BSSID "BSSID"
@@ -200,6 +202,8 @@
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
+#define D_INFO_ENDPOINT_IP "Endpoint IP"
+#define D_INFO_ENDPOINT_PORT "Endpoint Port"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
@@ -212,6 +216,9 @@
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
+#define D_WG_INITIALIZED "Initialized"
+#define D_WG_BAD_CONFIG "Missing or bad configuration"
+
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch"
diff --git a/src/log/hasp_debug.cpp b/src/log/hasp_debug.cpp
index dafed245..cbca09c6 100644
--- a/src/log/hasp_debug.cpp
+++ b/src/log/hasp_debug.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/* ===========================================================================
diff --git a/src/main_arduino.cpp b/src/main.cpp
similarity index 90%
rename from src/main_arduino.cpp
rename to src/main.cpp
index 86b53902..b065909c 100644
--- a/src/main_arduino.cpp
+++ b/src/main.cpp
@@ -1,8 +1,6 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
-#if !(defined(WINDOWS) || defined(POSIX))
-
/*
#ifdef CORE_DEBUG_LEVEL
#undef CORE_DEBUG_LEVEL
@@ -28,9 +26,9 @@
#include "hasp_gui.h"
#endif
-bool isConnected;
-uint8_t mainLoopCounter = 0;
-unsigned long mainLastLoopTime = 0;
+static bool isConnected;
+static uint8_t mainLoopCounter = 0;
+static unsigned long mainLastLoopTime = 0;
#ifdef HASP_USE_STAT_COUNTER
uint16_t statLoopCounter = 0; // measures the average looptime
@@ -40,11 +38,23 @@ void setup()
{
// hal_setup();
+#if HASP_TARGET_ARDUINO
esp_log_level_set("*", ESP_LOG_NONE); // set all components to ERROR level
// esp_log_level_set("wifi", ESP_LOG_NONE); // enable WARN logs from WiFi stack
// esp_log_level_set("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client
// esp_log_level_set("esp_crt_bundle", ESP_LOG_VERBOSE); // enable WARN logs from WiFi stack
// esp_log_level_set("esp_tls", ESP_LOG_VERBOSE); // enable WARN logs from WiFi stack
+#elif HASP_TARGET_PC
+ // Initialize lvgl environment
+ lv_init();
+ lv_log_register_print_cb(debugLvglLogEvent);
+#if HASP_USE_CONFIG
+ // initialize FS before running configSetup()
+ // normally, it's initialized in guiSetup(), but Arduino doesn't need FS in configSetup()
+ lv_fs_if_init();
+#endif
+#endif
+
haspDevice.init();
/****************************
@@ -149,7 +159,7 @@ void setup()
gui_setup_lvgl_task();
#endif // HASP_USE_LVGL_TASK
- mainLastLoopTime = -1000; // reset loop counter
+ mainLastLoopTime = 0; // reset loop counter
}
IRAM_ATTR void loop()
@@ -195,7 +205,7 @@ IRAM_ATTR void loop()
/* Timer Loop */
if(millis() - mainLastLoopTime >= 1000) {
- mainLastLoopTime += 1000;
+ mainLastLoopTime = millis();
/* Runs Every Second */
haspEverySecond(); // sleep timer & statusupdate
@@ -237,10 +247,9 @@ IRAM_ATTR void loop()
case 4:
#if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0
isConnected = networkEvery5Seconds(); // Check connection
-
+#endif
#if HASP_USE_MQTT > 0
mqttEvery5Seconds(isConnected);
-#endif
#endif
break;
@@ -270,5 +279,3 @@ IRAM_ATTR void loop()
delay(2); // ms
#endif
}
-
-#endif
diff --git a/src/main_pc.cpp b/src/main_pc.cpp
new file mode 100644
index 00000000..e61b3b06
--- /dev/null
+++ b/src/main_pc.cpp
@@ -0,0 +1,226 @@
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
+ For full license information read the LICENSE file in the project folder */
+
+#if HASP_TARGET_PC
+
+#if defined(WINDOWS)
+
+#include
+#include
+#include
+#include
+// MSDN recommends against using getcwd & chdir names
+#define cwd _getcwd
+#define cd _chdir
+#endif
+
+#if defined(POSIX)
+#include
+#include
+#include
+#include
+#include
+#include
+#define cwd getcwd
+#define cd chdir
+#endif
+
+#include
+#include
+
+#include "hasplib.h"
+
+#if USE_MONITOR
+#include "display/monitor.h"
+#endif
+
+#include "hasp_debug.h"
+
+// hasp_gui.cpp
+extern uint16_t tft_width;
+extern uint16_t tft_height;
+
+// main.cpp
+extern void setup();
+extern void loop();
+
+#if defined(WINDOWS)
+// https://gist.github.com/kingseva/a918ec66079a9475f19642ec31276a21
+void BindStdHandlesToConsole()
+{
+ // TODO: Add Error checking.
+
+ // Redirect the CRT standard input, output, and error handles to the console
+ freopen("CONIN$", "r", stdin);
+ freopen("CONOUT$", "w", stderr);
+ freopen("CONOUT$", "w", stdout);
+
+ // Note that there is no CONERR$ file
+ HANDLE hStdout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE hStdin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ SetStdHandle(STD_OUTPUT_HANDLE, hStdout);
+ SetStdHandle(STD_ERROR_HANDLE, hStdout);
+ SetStdHandle(STD_INPUT_HANDLE, hStdin);
+
+ // Clear the error state for each of the C++ standard stream objects.
+ std::wclog.clear();
+ std::clog.clear();
+ std::wcout.clear();
+ std::cout.clear();
+ std::wcerr.clear();
+ std::cerr.clear();
+ std::wcin.clear();
+ std::cin.clear();
+}
+
+void InitializeConsoleOutput()
+{
+ bool isConsoleApp;
+
+ // How to check if the program is run from a console?
+ // https://stackoverflow.com/questions/9009333/how-to-check-if-the-program-is-run-from-a-console
+ HWND consoleWnd = GetConsoleWindow();
+ DWORD dwProcessId;
+ GetWindowThreadProcessId(consoleWnd, &dwProcessId);
+
+ if(GetCurrentProcessId() == dwProcessId) {
+ isConsoleApp = true; // Opened in Console
+ } else {
+ isConsoleApp = false; // Opened in Windows
+ }
+
+ // Use normal console that launched the program
+ AttachConsole(ATTACH_PARENT_PROCESS);
+
+ // Test if the application was started from a Console Window
+ if(!isConsoleApp) {
+ // If started from Windows, use detached Log Console Window
+ AllocConsole();
+ }
+
+ // Redirect all standard output streams to the console
+ BindStdHandlesToConsole();
+}
+#endif
+
+void usage(const char* progName, const char* version)
+{
+ std::cout << "\n"
+ << progName << " " << version << " [options]" << std::endl
+ << std::endl
+ << "Options:" << std::endl
+ << " -h | --help Print this help" << std::endl
+ << " -q | --quiet Suppress console output (can improve performance)" << std::endl
+#if !USE_FBDEV
+ << " -W | --width Width of the window" << std::endl
+ << " -H | --height Height of the window" << std::endl
+#endif
+ << " -c | --config Configuration/storage directory" << std::endl
+#if defined(WINDOWS)
+ << " (default: 'AppData\\hasp\\hasp')" << std::endl
+#elif defined(POSIX)
+ << " (default: '~/.local/share/hasp/hasp')" << std::endl
+#endif
+ << std::endl;
+ fflush(stdout);
+}
+
+int main(int argc, char* argv[])
+{
+ bool showhelp = false;
+ bool console = true;
+ char config[PATH_MAX] = {'\0'};
+
+#if defined(WINDOWS)
+ InitializeConsoleOutput();
+ SetConsoleCP(65001); // 65001 = UTF-8
+#endif
+
+ for(int arg = 1; arg < argc; arg++) {
+ if(strncmp(argv[arg], "--help", 6) == 0 || strncmp(argv[arg], "-h", 2) == 0) {
+ showhelp = true;
+ } else if(strncmp(argv[arg], "--quiet", 7) == 0 || strncmp(argv[arg], "-q", 2) == 0) {
+#if defined(WINDOWS)
+ FreeConsole();
+#endif
+#if defined(POSIX)
+ int nullfd = open("/dev/null", O_WRONLY);
+ dup2(nullfd, 1);
+ close(nullfd);
+#endif
+#if !USE_FBDEV
+ } else if(strncmp(argv[arg], "--width", 7) == 0 || strncmp(argv[arg], "-W", 2) == 0) {
+ if(arg + 1 < argc) {
+ int w = atoi(argv[arg + 1]);
+ if(w > 0) tft_width = w;
+ arg++;
+ } else {
+ std::cout << "Missing width value" << std::endl;
+ showhelp = true;
+ }
+ } else if(strncmp(argv[arg], "--height", 8) == 0 || strncmp(argv[arg], "-H", 2) == 0) {
+ if(arg + 1 < argc) {
+ int h = atoi(argv[arg + 1]);
+ if(h > 0) tft_height = h;
+ arg++;
+ } else {
+ std::cout << "Missing height value" << std::endl;
+ showhelp = true;
+ }
+#endif
+ } else if(strncmp(argv[arg], "--config", 8) == 0 || strncmp(argv[arg], "-c", 2) == 0) {
+ if(arg + 1 < argc) {
+ strcpy(config, argv[arg + 1]);
+ arg++;
+ } else {
+ std::cout << "Missing config directory" << std::endl;
+ showhelp = true;
+ }
+ } else {
+ std::cout << "Unrecognized command line parameter: " << argv[arg] << std::endl;
+ showhelp = true;
+ }
+ }
+
+ if(showhelp) {
+ usage("openHASP", haspDevice.get_version());
+ goto end;
+ }
+
+ if(config[0] == '\0') {
+#if USE_MONITOR
+ SDL_Init(0); // Needs to be initialized for GetPerfPath
+ strcpy(config, SDL_GetPrefPath("hasp", "hasp"));
+ SDL_Quit(); // We'll properly init later
+#elif defined(WINDOWS)
+ if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, config))) {
+ PathAppendA(config, "hasp");
+ PathAppendA(config, "hasp");
+ }
+#elif defined(POSIX)
+ struct passwd* pw = getpwuid(getuid());
+ strcpy(config, pw->pw_dir);
+ strcat(config, "/.local/share/hasp/hasp");
+#endif
+ }
+ cd(config);
+
+ setup();
+ while(haspDevice.pc_is_running) {
+ loop();
+ }
+
+end:
+#if defined(WINDOWS)
+ std::cout << std::endl << std::flush;
+ fflush(stdout);
+ FreeConsole();
+ exit(0);
+#endif
+ return 0;
+}
+
+#endif
diff --git a/src/main_sdl2.cpp b/src/main_sdl2.cpp
deleted file mode 100644
index d2942333..00000000
--- a/src/main_sdl2.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
- For full license information read the LICENSE file in the project folder */
-
-#if defined(WINDOWS) || defined(POSIX)
-
-#if defined(WINDOWS)
-
-#include
-#include
-// MSDN recommends against using getcwd & chdir names
-#define cwd _getcwd
-#define cd _chdir
-#endif
-
-#if defined(POSIX)
-#include
-#include
-#define cwd getcwd
-#define cd chdir
-#endif
-
-#include
-#include
-
-#include "hasplib.h"
-
-// #include "app_hal.h"
-#include "display/monitor.h"
-
-#include "hasp_debug.h"
-#include "hasp_gui.h"
-
-#include "dev/device.h"
-
-bool isConnected;
-bool isRunning = 1;
-
-uint8_t mainLoopCounter = 0;
-unsigned long mainLastLoopTime = 0;
-
-#ifdef HASP_USE_STAT_COUNTER
-uint16_t statLoopCounter = 0; // measures the average looptime
-#endif
-
-extern uint16_t tft_width;
-extern uint16_t tft_height;
-
-#if defined(WINDOWS)
-// https://gist.github.com/kingseva/a918ec66079a9475f19642ec31276a21
-void BindStdHandlesToConsole()
-{
- // TODO: Add Error checking.
-
- // Redirect the CRT standard input, output, and error handles to the console
- freopen("CONIN$", "r", stdin);
- freopen("CONOUT$", "w", stderr);
- freopen("CONOUT$", "w", stdout);
-
- // Note that there is no CONERR$ file
- HANDLE hStdout = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- HANDLE hStdin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- SetStdHandle(STD_OUTPUT_HANDLE, hStdout);
- SetStdHandle(STD_ERROR_HANDLE, hStdout);
- SetStdHandle(STD_INPUT_HANDLE, hStdin);
-
- // Clear the error state for each of the C++ standard stream objects.
- std::wclog.clear();
- std::clog.clear();
- std::wcout.clear();
- std::cout.clear();
- std::wcerr.clear();
- std::cerr.clear();
- std::wcin.clear();
- std::cin.clear();
-}
-
-void InitializeConsoleOutput()
-{
- bool isConsoleApp;
-
- // How to check if the program is run from a console?
- // https://stackoverflow.com/questions/9009333/how-to-check-if-the-program-is-run-from-a-console
- HWND consoleWnd = GetConsoleWindow();
- DWORD dwProcessId;
- GetWindowThreadProcessId(consoleWnd, &dwProcessId);
-
- if(GetCurrentProcessId() == dwProcessId) {
- isConsoleApp = true; // Opened in Console
- } else {
- isConsoleApp = false; // Opened in Windows
- }
-
- // Use normal console that launched the program
- AttachConsole(ATTACH_PARENT_PROCESS);
-
- // Test if the application was started from a Console Window
- if(!isConsoleApp) {
- // If started from Windows, use detached Log Console Window
- AllocConsole();
- }
-
- // Redirect all standard output streams to the console
- BindStdHandlesToConsole();
-}
-#endif
-
-void setup()
-{
- // Load Settings
-
- // Init debug log
- // debug_init();
-
- // Initialize lvgl environment
- lv_init();
- lv_log_register_print_cb(debugLvglLogEvent);
-
- haspDevice.init(); // hardware setup
- haspDevice.show_info(); // debug info
- // hal_setup();
- guiSetup();
-
- LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__);
- dispatchSetup(); // for hasp and oobe
- haspSetup();
-
-#if HASP_USE_MQTT > 0
- LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__);
- mqttSetup(); // Hasp must be running
- mqttStart();
-#endif
-
-#if HASP_USE_GPIO > 0
- LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__);
- gpioSetup();
-#endif
-
-#if defined(HASP_USE_CUSTOM)
- custom_setup();
-#endif
-
- mainLastLoopTime = millis(); // - 1000; // reset loop counter
- LOG_DEBUG(TAG_MAIN, "%s %d", __FILE__, __LINE__);
- // delay(250);
-}
-
-void loop()
-{
- haspLoop();
- mqttLoop();
-
- // debugLoop(); // Console
- haspDevice.loop();
- guiLoop();
-
-#if HASP_USE_GPIO > 0
- gpioLoop();
-#endif
-
-#if defined(HASP_USE_CUSTOM)
- custom_loop();
-#endif
-
-#ifdef HASP_USE_STAT_COUNTER
- statLoopCounter++; // measures the average looptime
-#endif
-
- /* Timer Loop */
- if(millis() - mainLastLoopTime >= 1000) {
- /* Runs Every Second */
- haspEverySecond(); // sleep timer
- dispatchEverySecond(); // sleep timer
-
-#if HASP_USE_ARDUINOOTA > 0
- otaEverySecond(); // progressbar
-#endif
-
-#if defined(HASP_USE_CUSTOM)
- custom_every_second();
-#endif
-
- /* Runs Every 5 Seconds */
- if(mainLoopCounter == 0 || mainLoopCounter == 5) {
-
- haspDevice.loop_5s();
- gpioEvery5Seconds();
-
-#if defined(HASP_USE_MQTT)
- mqttEvery5Seconds(true);
-#endif
-
-#if defined(HASP_USE_CUSTOM)
- custom_every_5seconds();
-#endif
- }
-
- /* Reset loop counter every 10 seconds */
- if(mainLoopCounter >= 9) {
- mainLoopCounter = 0;
- } else {
- mainLoopCounter++;
- }
- mainLastLoopTime += 1000;
- }
- // delay(6);
-}
-
-void usage(const char* progName, const char* version)
-{
- std::cout << "\n\n"
- << progName << " " << version << " [options]" << std::endl
- << std::endl
- << "Options:" << std::endl
- << " -? | --help Print this help" << std::endl
- << " -w | --width Width of the window" << std::endl
- << " -h | --height Height of the window" << std::endl
- << " --mqttname MQTT device name topic (default: computer hostname)" << std::endl
- << " --mqtthost MQTT broker hostname or IP address" << std::endl
- << " --mqttport MQTT broker port (default: 1883)" << std::endl
- << " --mqttuser MQTT username" << std::endl
- << " --mqttpass MQTT password" << std::endl
- << " --mqttgroup MQTT groupname (default: plates)" << std::endl
- << std::endl
- // << " -t | --topic Base topic of the mqtt messages (default: hasp)" << std::endl
- // << std::endl
- // << " -f | --fullscreen Open the application fullscreen" << std::endl
- // << " -v | --verbose Verbosity level" << std::endl
- << std::endl;
- fflush(stdout);
-#if defined(WINDOWS)
- static const char s[] = "\n";
- DWORD slen = lstrlen(s);
- WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), s, slen, &slen, NULL);
-#endif
-}
-
-int main(int argc, char* argv[])
-{
- bool showhelp = false;
- int count;
-
-#if defined(WINDOWS)
- InitializeConsoleOutput();
- SetConsoleCP(65001); // 65001 = UTF-8
- static const char s[] = "tränenüberströmt™\n";
- DWORD slen = lstrlen(s);
- WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), s, slen, &slen, NULL);
-
- HANDLE std_out = GetStdHandle(STD_OUTPUT_HANDLE);
- if(std_out == INVALID_HANDLE_VALUE) {
- return 66;
- }
- if(!WriteConsole(std_out, "Hello World!\n", 13, NULL, NULL)) {
- return 67;
- }
-#endif
-
- SDL_Init(0); // Needs to be initialized for GetPerfPath
- char buf[4096]; // never know how much is needed
- std::cout << "CWD: " << cwd(buf, sizeof buf) << std::endl;
- cd(SDL_GetPrefPath("hasp", "hasp"));
- std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl;
- SDL_Quit(); // We'll properly init later
-
- // Change to preferences dir
- std::cout << "\nCommand-line arguments:\n";
- for(count = 0; count < argc; count++)
- std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
-
- StaticJsonDocument<1024> settings;
-
- for(count = 0; count < argc; count++) {
- if(argv[count][0] == '-') {
-
- if(strncmp(argv[count], "--help", 6) == 0 || strncmp(argv[count], "-?", 2) == 0) {
- showhelp = true;
- }
-
- if(strncmp(argv[count], "--width", 7) == 0 || strncmp(argv[count], "-w", 2) == 0) {
- int w = atoi(argv[count + 1]);
- if(w > 0) tft_width = w;
- }
-
- if(strncmp(argv[count], "--height", 8) == 0 || strncmp(argv[count], "-h", 2) == 0) {
- int h = atoi(argv[count + 1]);
- if(h > 0) tft_height = h;
- }
-
- if(strncmp(argv[count], "--mqttname", 10) == 0 || strncmp(argv[count], "-n", 2) == 0) {
- std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
- fflush(stdout);
- if(count + 1 < argc) {
- haspDevice.set_hostname(argv[count + 1]);
- settings["mqtt"]["name"] = argv[count + 1];
- } else {
- showhelp = true;
- }
- }
-
- if(strncmp(argv[count], "--mqtthost", 10) == 0) {
- std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
- fflush(stdout);
- if(count + 1 < argc) {
- settings["mqtt"]["host"] = argv[count + 1];
- } else {
- showhelp = true;
- }
- }
-
- if(strncmp(argv[count], "--mqttport", 10) == 0) {
- std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
- fflush(stdout);
- if(count + 1 < argc) {
- settings["mqtt"]["port"] = atoi(argv[count + 1]);
- } else {
- showhelp = true;
- }
- }
-
- if(strncmp(argv[count], "--mqttuser", 10) == 0) {
- std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
- fflush(stdout);
- if(count + 1 < argc) {
- settings["mqtt"]["user"] = argv[count + 1];
- } else {
- showhelp = true;
- }
- }
-
- if(strncmp(argv[count], "--mqttpass", 10) == 0) {
- std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
- fflush(stdout);
- if(count + 1 < argc) {
- settings["mqtt"]["pass"] = argv[count + 1];
- } else {
- showhelp = true;
- }
- }
- }
- }
-
- if(showhelp) {
- usage("openHASP", haspDevice.get_version());
-
-#if defined(WINDOWS)
- WriteConsole(std_out, "bye\n\n", 3, NULL, NULL);
- std::cout << std::endl << std::flush;
- fflush(stdout);
- FreeConsole();
- exit(0);
-#endif
- return 0;
- }
-
- char buffer[2048];
- serializeJson(settings, buffer, sizeof(buffer));
- std::cout << buffer << std::endl << std::flush;
- fflush(stdout);
- mqttSetConfig(settings["mqtt"]);
- // printf("%s %d\n", __FILE__, __LINE__);
- // fflush(stdout);
-
- debugPrintHaspHeader(stdout);
- LOG_INFO(TAG_MAIN, "resolution %d x %d", tft_width, tft_height);
- LOG_INFO(TAG_MAIN, "pre setup");
-
- setup();
-
- LOG_TRACE(TAG_MAIN, "loop started");
- while(isRunning) {
- loop();
- }
- LOG_TRACE(TAG_MAIN, "main loop completed");
-
-#if defined(WINDOWS)
- WriteConsole(std_out, "bye\n\n", 3, NULL, NULL);
- std::cout << std::endl << std::flush;
- fflush(stdout);
- FreeConsole();
- exit(0);
-#endif
-
- return 0;
-}
-
-#endif
diff --git a/src/mqtt/hasp_mqtt.h b/src/mqtt/hasp_mqtt.h
index 63e9ed9e..f5d57196 100644
--- a/src/mqtt/hasp_mqtt.h
+++ b/src/mqtt/hasp_mqtt.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_MQTT_H
diff --git a/src/mqtt/hasp_mqtt_esp.cpp b/src/mqtt/hasp_mqtt_esp.cpp
index 74488f85..9fbac1e0 100644
--- a/src/mqtt/hasp_mqtt_esp.cpp
+++ b/src/mqtt/hasp_mqtt_esp.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
@@ -465,7 +465,7 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
void mqttSetup()
{
queue = xQueueCreate(64, sizeof(mqtt_message_t));
- //esp_crt_bundle_set(rootca_crt_bundle_start);
+ //esp_crt_bundle_set(rootca_crt_bundle_start, rootca_crt_bundle_end-rootca_crt_bundle_start);
arduino_esp_crt_bundle_set(rootca_crt_bundle_start);
mqttStart();
}
diff --git a/src/mqtt/hasp_mqtt_ha.cpp b/src/mqtt/hasp_mqtt_ha.cpp
index bf6edb1c..cc0e0130 100644
--- a/src/mqtt/hasp_mqtt_ha.cpp
+++ b/src/mqtt/hasp_mqtt_ha.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "ArduinoJson.h"
@@ -16,7 +16,7 @@
#define RETAINED true
-#if defined(WINDOWS) || defined(POSIX)
+#if HASP_TARGET_PC
extern std::string mqttNodeTopic;
extern std::string mqttGroupTopic;
#else
@@ -35,7 +35,7 @@ const char FP_MQTT_HA_NAME[] PROGMEM = "name";
const char FP_MQTT_HA_MODEL[] PROGMEM = "mdl";
const char FP_MQTT_HA_MANUFACTURER[] PROGMEM = "mf";
-#if !(defined(WINDOWS) || defined(POSIX))
+#if HASP_TARGET_ARDUINO
#include "hal/hasp_hal.h"
diff --git a/src/mqtt/hasp_mqtt_ha.h b/src/mqtt/hasp_mqtt_ha.h
index a49e1830..37abbed3 100644
--- a/src/mqtt/hasp_mqtt_ha.h
+++ b/src/mqtt/hasp_mqtt_ha.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_MQTT_HA_H
diff --git a/src/mqtt/hasp_mqtt_paho_async.cpp b/src/mqtt/hasp_mqtt_paho_async.cpp
index b56783fa..6c4e35f2 100644
--- a/src/mqtt/hasp_mqtt_paho_async.cpp
+++ b/src/mqtt/hasp_mqtt_paho_async.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/* Multi threaded asynchronous paho client */
@@ -10,6 +10,15 @@
#if HASP_USE_MQTT_ASYNC > 0
#ifdef HASP_USE_PAHO
+#if !HASP_USE_CONFIG
+const char FP_CONFIG_HOST[] PROGMEM = "host";
+const char FP_CONFIG_PORT[] PROGMEM = "port";
+const char FP_CONFIG_NAME[] PROGMEM = "name";
+const char FP_CONFIG_USER[] PROGMEM = "user";
+const char FP_CONFIG_PASS[] PROGMEM = "pass";
+const char FP_CONFIG_GROUP[] PROGMEM = "group";
+#endif
+
/*******************************************************************************
* Copyright (c) 2012, 2020 IBM Corp.
*
@@ -38,7 +47,7 @@
#include "hasp_mqtt.h" // functions to implement here
#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload
-#include "hasp_debug.h" // for logging
+#include "hasp_debug.h" // for logging
#if !defined(_WIN32)
#include
@@ -50,78 +59,131 @@
#include
#endif
-#define ADDRESS "10.4.0.5:1883"
-#define CLIENTID "ExampleClientSub"
-#define TOPIC "hasp/plate35/"
+// #define ADDRESS "10.4.0.5:1883"
+// #define CLIENTID "ExampleClientSub"
+// #define TOPIC "hasp/plate35/"
#define QOS 1
#define TIMEOUT 10000L
-const char* mqttNodeTopic = TOPIC;
-const char* mqttGroupTopic = TOPIC;
-// char mqttNodeTopic[24];
-// char mqttGroupTopic[24];
+std::string mqttNodeTopic;
+std::string mqttGroupTopic;
+std::string mqttLwtTopic;
bool mqttEnabled = false;
bool mqttHAautodiscover = true;
+uint32_t mqttPublishCount;
+uint32_t mqttReceiveCount;
+uint32_t mqttFailedCount;
std::recursive_mutex dispatch_mtx;
std::recursive_mutex publish_mtx;
-char mqttServer[MAX_HOSTNAME_LENGTH] = MQTT_HOSTNAME;
-char mqttUser[MAX_USERNAME_LENGTH] = MQTT_USERNAME;
-char mqttPassword[MAX_PASSWORD_LENGTH] = MQTT_PASSWORD;
-// char mqttNodeName[16] = MQTT_NODENAME;
-char mqttGroupName[16] = MQTT_GROUPNAME;
-uint16_t mqttPort = MQTT_PORT;
+std::string mqttServer = MQTT_HOSTNAME;
+std::string mqttUsername = MQTT_USERNAME;
+std::string mqttPassword = MQTT_PASSWORD;
+std::string mqttGroupName = MQTT_GROUPNAME;
+uint16_t mqttPort = MQTT_PORT;
MQTTAsync mqtt_client;
-int disc_finished = 0;
-int subscribed = 0;
-int connected = 0;
+static bool mqttConnecting = false;
+static bool mqttConnected = false;
-static bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain = false);
+int mqttPublish(const char* topic, const char* payload, size_t len, bool retain = false);
/* ===== Paho event callbacks ===== */
-void connlost(void* context, char* cause)
+static void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
- printf("\nConnection lost\n");
- if(cause) printf(" cause: %s\n", cause);
+#if HASP_TARGET_PC
+ dispatch_run_script(NULL, "L:/offline.cmd", TAG_HASP);
+#endif
+ mqttConnecting = false;
+ mqttConnected = false;
+ LOG_ERROR(TAG_MQTT, "Connection failed, return code %d (%s)", response->code, response->message);
+}
- printf("Reconnecting\n");
- mqttStart();
+static void onDisconnect(void* context, MQTTAsync_successData* response)
+{
+#if HASP_TARGET_PC
+ dispatch_run_script(NULL, "L:/offline.cmd", TAG_HASP);
+#endif
+ mqttConnecting = false;
+ mqttConnected = false;
+}
+
+static void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
+{
+ mqttConnecting = false;
+ mqttConnected = false;
+ LOG_ERROR(TAG_MQTT, "Disconnection failed, return code %d (%s)", response->code, response->message);
+}
+
+static void onSendFailure(void* context, MQTTAsync_failureData* response)
+{
+ LOG_ERROR(TAG_MQTT, "Send failed, return code %d (%s)", response->code, response->message);
+}
+
+static void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
+{
+ LOG_ERROR(TAG_MQTT, "Subscribe failed, return code %d (%s)", response->code, response->message);
+}
+
+static void connlost(void* context, char* cause)
+{
+#if HASP_TARGET_PC
+ dispatch_run_script(NULL, "L:/offline.cmd", TAG_HASP);
+#endif
+ LOG_WARNING(TAG_MQTT, F(D_MQTT_DISCONNECTED ": %s"), cause);
+ mqttConnecting = false;
+ mqttConnected = false;
}
// Receive incoming messages
static void mqtt_message_cb(char* topic, char* payload, size_t length)
{ // Handle incoming commands from MQTT
if(length + 1 >= MQTT_MAX_PACKET_SIZE) {
+ mqttFailedCount++;
LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), (uint32_t)length);
return;
} else {
+ mqttReceiveCount++;
payload[length] = '\0';
}
LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload);
- if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic
+ if(topic == strstr(topic, mqttNodeTopic.c_str())) { // startsWith mqttNodeTopic
// Node topic
- topic += strlen(mqttNodeTopic); // shorten topic
+ topic += mqttNodeTopic.length(); // shorten topic
- } else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic
+ } else if(topic == strstr(topic, mqttGroupTopic.c_str())) { // startsWith mqttGroupTopic
// Group topic
- topic += strlen(mqttGroupTopic); // shorten topic
+ topic += mqttGroupTopic.length(); // shorten topic
dispatch_mtx.lock();
- dispatch_topic_payload(topic, (const char*)payload);
+ dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
dispatch_mtx.unlock();
return;
+#ifdef HASP_USE_BROADCAST
+ } else if(topic == strstr_P(topic, PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST
+ "/"))) { // /" MQTT_TOPIC_BROADCAST "/ discovery topic
+
+ // /" MQTT_TOPIC_BROADCAST "/ topic
+ topic += strlen(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/"); // shorten topic
+ dispatch_mtx.lock();
+ dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
+ dispatch_mtx.unlock();
+ return;
+#endif
+
#ifdef HASP_USE_HA
} else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic
if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) {
- dispatch_current_state();
+ dispatch_mtx.lock();
+ dispatch_current_state(TAG_MQTT);
+ dispatch_mtx.unlock();
mqtt_ha_register_auto_discovery();
}
return;
@@ -138,11 +200,8 @@ static void mqtt_message_cb(char* topic, char* payload, size_t length)
if(!strcasecmp_P((char*)payload, PSTR("offline"))) {
{
char msg[8];
- char tmp_topic[strlen(mqttNodeTopic) + 8];
- snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_LWT), mqttNodeTopic);
snprintf_P(msg, sizeof(msg), PSTR("online"));
-
- mqttPublish(tmp_topic, msg, true);
+ mqttPublish(mqttLwtTopic.c_str(), msg, strlen(msg), true);
}
} else {
@@ -150,175 +209,151 @@ static void mqtt_message_cb(char* topic, char* payload, size_t length)
}
} else {
dispatch_mtx.lock();
- dispatch_topic_payload(topic, (const char*)payload);
+ dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
dispatch_mtx.unlock();
}
}
-int msgarrvd(void* context, char* topicName, int topicLen, MQTTAsync_message* message)
+static int mqtt_message_arrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message)
{
- // printf("MQT RCV >> ");
- // printf("%s => %.*s (%d)\n", topicName, message->payloadlen, (char *)message->payload, message->payloadlen);
-
char msg[message->payloadlen + 1];
memcpy(msg, (char*)message->payload, message->payloadlen);
msg[message->payloadlen] = '\0';
- mqtt_message_cb(topicName, (char*)message->payload, message->payloadlen);
+ mqtt_message_cb(topicName, msg, message->payloadlen);
MQTTAsync_freeMessage(&message);
MQTTAsync_free(topicName);
- return 1;
+ return 1; // the message was received properly
}
-void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
-{
- printf("Disconnect failed, rc %d\n", response->code);
- disc_finished = 1;
-}
-
-void onDisconnect(void* context, MQTTAsync_successData* response)
-{
- printf("Successful disconnection\n");
- disc_finished = 1;
- connected = 0;
-}
-
-void onSubscribe(void* context, MQTTAsync_successData* response)
-{
- printf("Subscribe succeeded %d\n", response->token);
- subscribed = 1;
-}
-
-void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
-{
- printf("Subscribe failed, rc %d\n", response->code);
-}
-
-void onConnectFailure(void* context, MQTTAsync_failureData* response)
-{
- connected = 0;
- printf("Connect failed, rc %d\n", response->code);
-}
-
-void mqtt_subscribe(void* context, const char* topic)
+static void mqtt_subscribe(void* context, const char* topic)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
int rc;
- printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n", topic, CLIENTID, QOS);
- opts.onSuccess = onSubscribe;
opts.onFailure = onSubscribeFailure;
opts.context = client;
if((rc = MQTTAsync_subscribe(client, topic, QOS, &opts)) != MQTTASYNC_SUCCESS) {
- printf("Failed to start subscribe, return code %d\n", rc);
+ LOG_WARNING(TAG_MQTT, D_BULLET D_MQTT_NOT_SUBSCRIBED, topic); // error code rc
+ } else {
+ LOG_VERBOSE(TAG_MQTT, D_BULLET D_MQTT_SUBSCRIBED, topic);
}
}
-void onConnect(void* context, MQTTAsync_successData* response)
-{
- MQTTAsync client = (MQTTAsync)context;
- connected = 1;
-
- printf("Successful connection\n");
-
- mqtt_subscribe(context, TOPIC MQTT_TOPIC_COMMAND "/#");
- mqtt_subscribe(context, TOPIC MQTT_TOPIC_COMMAND);
- mqtt_subscribe(context, TOPIC "light");
- mqtt_subscribe(context, TOPIC "dim");
-
- mqttPublish(TOPIC MQTT_TOPIC_LWT, "online", false);
-
- mqtt_send_object_state(0, 0, "connected");
- std::cout << std::endl;
-}
-
-void onSendFailure(void* context, MQTTAsync_failureData* response)
-{
- MQTTAsync client = (MQTTAsync)context;
- MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
- int rc;
-
- printf("Message send failed token %d error code %d\n", response->token, response->code);
- opts.onSuccess = onDisconnect;
- opts.onFailure = onDisconnectFailure;
- opts.context = client;
- if((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS) {
- printf("Failed to start disconnect, return code %d\n", rc);
- // exit(EXIT_FAILURE);
- }
-}
-
-void onSend(void* context, MQTTAsync_successData* response)
-{
- MQTTAsync client = (MQTTAsync)context;
- MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
- int rc;
-
- // printf("Message with token value %d delivery confirmed\n", response->token);
-
- // opts.onSuccess = onDisconnect;
- // opts.onFailure = onDisconnectFailure;
- // opts.context = client;
- // if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
- // {
- // printf("Failed to start disconnect, return code %d\n", rc);
- // exit(EXIT_FAILURE);
- // }
-}
-
/* ===== Local HASP MQTT functions ===== */
-static bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
+int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
{
- if(mqttIsConnected()) {
- MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
- MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
- int rc;
+ if(!mqttEnabled) return MQTT_ERR_DISABLED;
- opts.onSuccess = onSend;
- opts.onFailure = onSendFailure;
- opts.context = mqtt_client;
- pubmsg.payload = (char*)payload;
- pubmsg.payloadlen = (int)strlen(payload);
- pubmsg.qos = QOS;
- pubmsg.retained = 0;
- dispatch_mtx.lock();
- if((rc = MQTTAsync_sendMessage(mqtt_client, topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS) {
- dispatch_mtx.unlock();
- LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), topic, payload);
- } else {
- dispatch_mtx.unlock();
- LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), topic, payload);
- return true;
- }
- } else {
- LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED));
+ if(!mqttIsConnected()) {
+ mqttFailedCount++;
+ return MQTT_ERR_NO_CONN;
+ }
+
+ MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
+ MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
+
+ opts.onFailure = onSendFailure;
+ opts.context = mqtt_client;
+ pubmsg.payload = (char*)payload;
+ pubmsg.payloadlen = (int)strlen(payload);
+ pubmsg.qos = QOS;
+ pubmsg.retained = 0;
+
+ dispatch_mtx.lock();
+ int rc = MQTTAsync_sendMessage(mqtt_client, topic, &pubmsg, &opts);
+
+ if(rc != MQTTASYNC_SUCCESS) {
+ dispatch_mtx.unlock();
+ mqttFailedCount++;
+ LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " '%s' => %s"), topic, payload);
+ return MQTT_ERR_PUB_FAIL;
+ } else {
+ dispatch_mtx.unlock();
+ mqttPublishCount++;
+ // LOG_TRACE(TAG_MQTT_PUB, F("'%s' => %s OK"), topic, payload);
+ return MQTT_ERR_OK;
}
- return false;
}
/* ===== Public HASP MQTT functions ===== */
bool mqttIsConnected()
{
- return connected == 1;
+ return mqttConnected; // MQTTAsync_isConnected(mqtt_client); // <- deadlocking on Linux
}
-void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload)
+int mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload)
{
- char tmp_topic[strlen(mqttNodeTopic) + 20];
- printf(("%s" MQTT_TOPIC_STATE "/%s\n"), mqttNodeTopic, subtopic);
- snprintf_P(tmp_topic, sizeof(tmp_topic), ("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic, subtopic);
- mqttPublish(tmp_topic, payload, false);
+ char tmp_topic[mqttNodeTopic.length() + 20];
+ snprintf_P(tmp_topic, sizeof(tmp_topic), ("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic.c_str(), subtopic);
+ return mqttPublish(tmp_topic, payload, strlen(payload), false);
}
-void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
+int mqtt_send_discovery(const char* payload, size_t len)
{
- char tmp_topic[strlen(mqttNodeTopic) + 20];
- snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/p%ub%u"), mqttNodeTopic, pageid, btnid);
- mqttPublish(tmp_topic, payload, false);
+ char tmp_topic[128];
+ snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR(MQTT_PREFIX "/" MQTT_TOPIC_DISCOVERY "/%s"),
+ haspDevice.get_hardware_id());
+ return mqttPublish(tmp_topic, payload, len, false);
+}
+
+// int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
+// {
+// char tmp_topic[mqttNodeTopic.length() + 20];
+// snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/p%ub%u"), mqttNodeTopic.c_str(), pageid,
+// btnid);
+// return mqttPublish(tmp_topic, payload, strlen(payload), false);
+// }
+
+static void onConnect(void* context, MQTTAsync_successData* response)
+{
+ mqttConnecting = false;
+ mqttConnected = true;
+ MQTTAsync client = (MQTTAsync)context;
+ std::string topic;
+
+ LOG_VERBOSE(TAG_MQTT, D_MQTT_CONNECTED, mqttServer.c_str(), haspDevice.get_hostname());
+
+ topic = mqttGroupTopic + MQTT_TOPIC_COMMAND "/#";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+
+ topic = mqttNodeTopic + MQTT_TOPIC_COMMAND "/#";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+
+ topic = mqttGroupTopic + "config/#";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+
+ topic = mqttNodeTopic + "config/#";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+
+#if defined(HASP_USE_CUSTOM)
+ topic = mqttGroupTopic + MQTT_TOPIC_CUSTOM "/#";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+
+ topic = mqttNodeTopic + MQTT_TOPIC_CUSTOM "/#";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+#endif
+
+#ifdef HASP_USE_BROADCAST
+ topic = MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/" MQTT_TOPIC_COMMAND "/#";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+#endif
+
+ /* Home Assistant auto-configuration */
+#ifdef HASP_USE_HA
+ topic = "homeassistant/status";
+ mqtt_subscribe(mqtt_client, topic.c_str());
+#endif
+
+ mqttPublish(mqttLwtTopic.c_str(), "online", 6, true);
+
+#if HASP_TARGET_PC
+ dispatch_run_script(NULL, "L:/online.cmd", TAG_HASP);
+#endif
}
void mqttStart()
@@ -328,47 +363,51 @@ void mqttStart()
int rc;
int ch;
- if((rc = MQTTAsync_create(&mqtt_client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) !=
+ if((rc = MQTTAsync_create(&mqtt_client, mqttServer.c_str(), haspDevice.get_hostname(), MQTTCLIENT_PERSISTENCE_NONE,
+ NULL)) != MQTTASYNC_SUCCESS) {
+ LOG_ERROR(TAG_MQTT, "Failed to create client, return code %d", rc);
+ rc = EXIT_FAILURE;
+ return;
+ }
+
+ if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, mqtt_message_arrived, NULL)) !=
MQTTASYNC_SUCCESS) {
- printf("Failed to create client, return code %d\n", rc);
+ LOG_ERROR(TAG_MQTT, "Failed to set callbacks, return code %d", rc);
rc = EXIT_FAILURE;
return;
}
- if((rc = MQTTAsync_setCallbacks(mqtt_client, mqtt_client, connlost, msgarrvd, NULL)) != MQTTASYNC_SUCCESS) {
- printf("Failed to set callbacks, return code %d\n", rc);
- rc = EXIT_FAILURE;
- return;
- }
+ mqttEnabled = mqttServer.length() > 0 && mqttPort > 0;
- conn_opts.will = &will_opts;
- conn_opts.will->message = "offline";
- conn_opts.will->qos = 1;
- conn_opts.will->retained = 0;
- conn_opts.will->topicName = "hasp/plate35/LWT";
+ if(mqttEnabled) {
+ conn_opts.will = &will_opts;
+ conn_opts.will->message = "offline";
+ conn_opts.will->qos = 1;
+ conn_opts.will->retained = 1;
+ conn_opts.will->topicName = mqttLwtTopic.c_str();
- conn_opts.keepAliveInterval = 20;
- conn_opts.cleansession = 1;
- conn_opts.onSuccess = onConnect;
- conn_opts.onFailure = onConnectFailure;
- conn_opts.context = mqtt_client;
+ conn_opts.keepAliveInterval = 20;
+ conn_opts.cleansession = 1;
+ conn_opts.connectTimeout = 2; // seconds
+ conn_opts.retryInterval = 15; // 0 = no retry
+ conn_opts.onSuccess = onConnect;
+ conn_opts.onFailure = onConnectFailure;
+ conn_opts.context = mqtt_client;
- if((rc = MQTTAsync_connect(mqtt_client, &conn_opts)) != MQTTASYNC_SUCCESS) {
- printf("Failed to start connect, return code %d\n", rc);
- rc = EXIT_FAILURE;
- // goto destroy_exit;
+ conn_opts.username = mqttUsername.c_str();
+ conn_opts.password = mqttPassword.c_str();
+
+ mqttConnecting = true;
+ if((rc = MQTTAsync_connect(mqtt_client, &conn_opts)) != MQTTASYNC_SUCCESS) {
+ mqttConnecting = false;
+ LOG_ERROR(TAG_MQTT, "Failed to connect, return code %d", rc);
+ rc = EXIT_FAILURE;
+ // goto destroy_exit;
+ }
} else {
+ rc = EXIT_FAILURE;
+ LOG_WARNING(TAG_MQTT, "Mqtt server not configured");
}
-
- // while (!subscribed && !finished)
- // #if defined(_WIN32)
- // Sleep(100);
- // #else
- // usleep(10000L);
- // #endif
-
- // if (finished)
- // goto exit;
}
void mqttStop()
@@ -378,30 +417,146 @@ void mqttStop()
disc_opts.onSuccess = onDisconnect;
disc_opts.onFailure = onDisconnectFailure;
if((rc = MQTTAsync_disconnect(mqtt_client, &disc_opts)) != MQTTASYNC_SUCCESS) {
- printf("Failed to start disconnect, return code %d\n", rc);
+ LOG_ERROR(TAG_MQTT, "Failed to disconnect, return code %d", rc);
rc = EXIT_FAILURE;
- // goto destroy_exit;
}
- // while (!disc_finished)
- // {
- // #if defined(_WIN32)
- // Sleep(100);
- // #else
- // usleep(10000L);
- // #endif
- // }
-
- // destroy_exit:
- // MQTTAsync_destroy(&client);
- // exit:
- // return rc;
}
-void mqttSetup(){};
+void mqttSetup()
+{
+ mqttNodeTopic = MQTT_PREFIX;
+ mqttNodeTopic += "/";
+ mqttNodeTopic += haspDevice.get_hostname();
+ mqttNodeTopic += "/";
+
+ mqttGroupTopic = MQTT_PREFIX;
+ mqttGroupTopic += "/";
+ mqttGroupTopic += mqttGroupName;
+ mqttGroupTopic += "/";
+
+ mqttLwtTopic = mqttNodeTopic;
+ mqttLwtTopic += MQTT_TOPIC_LWT;
+}
IRAM_ATTR void mqttLoop(){};
-void mqttEvery5Seconds(bool wifiIsConnected){};
+void mqttEvery5Seconds(bool wifiIsConnected)
+{
+ if(!mqttIsConnected() && !mqttConnecting && mqttServer.length() > 0 && mqttPort > 0) {
+ LOG_WARNING(TAG_MQTT, F(D_MQTT_RECONNECTING));
+ mqttStart();
+ }
+};
+
+void mqtt_get_info(JsonDocument& doc)
+{
+ char mqttClientId[64];
+
+ JsonObject info = doc.createNestedObject(F("MQTT"));
+ info[F(D_INFO_SERVER)] = mqttServer;
+ info[F(D_INFO_USERNAME)] = mqttUsername;
+ info[F(D_INFO_CLIENTID)] = haspDevice.get_hostname();
+ info[F(D_INFO_STATUS)] = mqttIsConnected() ? F(D_SERVICE_CONNECTED) : F(D_SERVICE_DISCONNECTED);
+ info[F(D_INFO_RECEIVED)] = mqttReceiveCount;
+ info[F(D_INFO_PUBLISHED)] = mqttPublishCount;
+ info[F(D_INFO_FAILED)] = mqttFailedCount;
+}
+
+bool mqttGetConfig(const JsonObject& settings)
+{
+ bool changed = false;
+
+ if(strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)].as().c_str()) != 0) changed = true;
+ settings[FPSTR(FP_CONFIG_NAME)] = haspDevice.get_hostname();
+
+ if(mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName;
+
+ if(mqttServer != settings[FPSTR(FP_CONFIG_HOST)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_HOST)] = mqttServer;
+
+ if(mqttPort != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_PORT)] = mqttPort;
+
+ if(mqttUsername != settings[FPSTR(FP_CONFIG_USER)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_USER)] = mqttUsername;
+
+ if(mqttPassword != settings[FPSTR(FP_CONFIG_PASS)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_PASS)] = mqttPassword;
+
+ if(changed) configOutput(settings, TAG_MQTT);
+ return changed;
+}
+
+/** Set MQTT Configuration.
+ *
+ * Read the settings from json and sets the application variables.
+ *
+ * @note: data pixel should be formatted to uint32_t RGBA. Imagemagick requirements.
+ *
+ * @param[in] settings JsonObject with the config settings.
+ **/
+bool mqttSetConfig(const JsonObject& settings)
+{
+ // configOutput(settings, TAG_MQTT);
+ bool changed = false;
+
+ if(!settings[FPSTR(FP_CONFIG_PORT)].isNull()) {
+ // changed |= configSet(mqttPort, settings[FPSTR(FP_CONFIG_PORT)], F("mqttPort"));
+ changed |= mqttPort != settings[FPSTR(FP_CONFIG_PORT)];
+ mqttPort = settings[FPSTR(FP_CONFIG_PORT)];
+ }
+
+ if(!settings[FPSTR(FP_CONFIG_NAME)].isNull()) {
+ LOG_VERBOSE(TAG_MQTT, "%s => %s", FP_CONFIG_NAME, settings[FPSTR(FP_CONFIG_NAME)].as());
+ changed |= strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)]) != 0;
+ // strncpy(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)], sizeof(mqttNodeName));
+ haspDevice.set_hostname(settings[FPSTR(FP_CONFIG_NAME)].as());
+ }
+ // Prefill node name
+ // if(strlen(haspDevice.get_hostname()) == 0) {
+ // char mqttNodeName[64];
+ // std::string mac = halGetMacAddress(3, "");
+ // mac.toLowerCase();
+ // snprintf_P(mqttNodeName, sizeof(mqttNodeName), PSTR(D_MQTT_DEFAULT_NAME), mac.c_str());
+ // haspDevice.set_hostname(mqttNodeName);
+ // changed = true;
+ // }
+
+ if(!settings[FPSTR(FP_CONFIG_GROUP)].isNull()) {
+ changed |= mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)];
+ mqttGroupName = settings[FPSTR(FP_CONFIG_GROUP)].as();
+ }
+
+ if(mqttGroupName.length() == 0) {
+ mqttGroupName = "plates";
+ changed = true;
+ }
+
+ if(!settings[FPSTR(FP_CONFIG_HOST)].isNull()) {
+ LOG_VERBOSE(TAG_MQTT, "%s => %s", FP_CONFIG_HOST, settings[FPSTR(FP_CONFIG_HOST)].as());
+ changed |= mqttServer != settings[FPSTR(FP_CONFIG_HOST)];
+ mqttServer = settings[FPSTR(FP_CONFIG_HOST)].as();
+ }
+
+ if(!settings[FPSTR(FP_CONFIG_USER)].isNull()) {
+ changed |= mqttUsername != settings[FPSTR(FP_CONFIG_USER)];
+ mqttUsername = settings[FPSTR(FP_CONFIG_USER)].as();
+ }
+
+ if(!settings[FPSTR(FP_CONFIG_PASS)].isNull() &&
+ settings[FPSTR(FP_CONFIG_PASS)].as() != D_PASSWORD_MASK) {
+ changed |= mqttPassword != settings[FPSTR(FP_CONFIG_PASS)];
+ mqttPassword = settings[FPSTR(FP_CONFIG_PASS)].as();
+ }
+
+ mqttNodeTopic = MQTT_PREFIX;
+ mqttNodeTopic += haspDevice.get_hostname();
+ mqttGroupTopic = MQTT_PREFIX;
+ mqttGroupTopic += mqttGroupName;
+
+ return changed;
+}
#endif // HASP_USE_PAHO
#endif // USE_MQTT
diff --git a/src/mqtt/hasp_mqtt_paho_single.cpp b/src/mqtt/hasp_mqtt_paho_single.cpp
index 0811e29d..653a884f 100644
--- a/src/mqtt/hasp_mqtt_paho_single.cpp
+++ b/src/mqtt/hasp_mqtt_paho_single.cpp
@@ -1,19 +1,21 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
/* Single threaded synchronous paho client */
#include "hasplib.h"
-#if HASP_USE_MQTT > 0
+#if HASP_USE_MQTT > 0 && !HASP_USE_MQTT_ASYNC
#ifdef HASP_USE_PAHO
+#if !HASP_USE_CONFIG
const char FP_CONFIG_HOST[] PROGMEM = "host";
const char FP_CONFIG_PORT[] PROGMEM = "port";
const char FP_CONFIG_NAME[] PROGMEM = "name";
const char FP_CONFIG_USER[] PROGMEM = "user";
const char FP_CONFIG_PASS[] PROGMEM = "pass";
const char FP_CONFIG_GROUP[] PROGMEM = "group";
+#endif
/*******************************************************************************
* Copyright (c) 2012, 2020 IBM Corp.
@@ -411,6 +413,32 @@ void mqtt_get_info(JsonDocument& doc)
info[F(D_INFO_FAILED)] = mqttFailedCount;
}
+bool mqttGetConfig(const JsonObject& settings)
+{
+ bool changed = false;
+
+ if(strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)].as().c_str()) != 0) changed = true;
+ settings[FPSTR(FP_CONFIG_NAME)] = haspDevice.get_hostname();
+
+ if(mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName;
+
+ if(mqttServer != settings[FPSTR(FP_CONFIG_HOST)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_HOST)] = mqttServer;
+
+ if(mqttPort != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_PORT)] = mqttPort;
+
+ if(mqttUsername != settings[FPSTR(FP_CONFIG_USER)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_USER)] = mqttUsername;
+
+ if(mqttPassword != settings[FPSTR(FP_CONFIG_PASS)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_PASS)] = mqttPassword;
+
+ if(changed) configOutput(settings, TAG_MQTT);
+ return changed;
+}
+
/** Set MQTT Configuration.
*
* Read the settings from json and sets the application variables.
diff --git a/src/mqtt/hasp_mqtt_pubsubclient.cpp b/src/mqtt/hasp_mqtt_pubsubclient.cpp
index 8821fc59..29e11b2f 100644
--- a/src/mqtt/hasp_mqtt_pubsubclient.cpp
+++ b/src/mqtt/hasp_mqtt_pubsubclient.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
diff --git a/src/sys/gpio/hasp_gpio.cpp b/src/sys/gpio/hasp_gpio.cpp
index b27e3594..0094f80b 100644
--- a/src/sys/gpio/hasp_gpio.cpp
+++ b/src/sys/gpio/hasp_gpio.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "lv_conf.h" // For timing defines
diff --git a/src/sys/gpio/hasp_gpio.h b/src/sys/gpio/hasp_gpio.h
index 43a68376..df093048 100644
--- a/src/sys/gpio/hasp_gpio.h
+++ b/src/sys/gpio/hasp_gpio.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_GPIO_H
diff --git a/src/sys/net/hasp_ethernet_esp32.cpp b/src/sys/net/hasp_ethernet_esp32.cpp
index 0ece6cb7..5c435437 100644
--- a/src/sys/net/hasp_ethernet_esp32.cpp
+++ b/src/sys/net/hasp_ethernet_esp32.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
diff --git a/src/sys/net/hasp_ethernet_esp32.h b/src/sys/net/hasp_ethernet_esp32.h
index d3359a2c..401e2249 100644
--- a/src/sys/net/hasp_ethernet_esp32.h
+++ b/src/sys/net/hasp_ethernet_esp32.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_ETHERNET_ESP32_H
diff --git a/src/sys/net/hasp_ethernet_stm32.cpp b/src/sys/net/hasp_ethernet_stm32.cpp
index 6923cba4..26203575 100644
--- a/src/sys/net/hasp_ethernet_stm32.cpp
+++ b/src/sys/net/hasp_ethernet_stm32.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
diff --git a/src/sys/net/hasp_ethernet_stm32.h b/src/sys/net/hasp_ethernet_stm32.h
index 10064158..0bf1c4c7 100644
--- a/src/sys/net/hasp_ethernet_stm32.h
+++ b/src/sys/net/hasp_ethernet_stm32.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_ETHERNET_STM32_H
diff --git a/src/sys/net/hasp_network.cpp b/src/sys/net/hasp_network.cpp
index 5b20ad4a..88fd9d11 100644
--- a/src/sys/net/hasp_network.cpp
+++ b/src/sys/net/hasp_network.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
@@ -14,6 +14,11 @@ uint16_t network_reconnect_counter = 0;
#if HASP_USE_ETHERNET > 0 || HASP_USE_WIFI > 0
+bool network_is_connected()
+{
+ return current_network_state;
+}
+
void network_disconnected()
{
@@ -23,6 +28,9 @@ void network_disconnected()
// if(!current_network_state) return; // we were not connected
current_network_state = false; // now we are disconnected
+#if HASP_USE_WIREGUARD
+ wg_network_disconnected();
+#endif
network_reconnect_counter++;
// LOG_VERBOSE(TAG_NETW, F("Connected = %s"),
// WiFi.status() == WL_CONNECTED ? PSTR(D_NETWORK_ONLINE) : PSTR(D_NETWORK_OFFLINE));
@@ -32,10 +40,15 @@ void network_connected()
{
if(current_network_state) return; // already connected
+#if HASP_USE_WIREGUARD
+ wg_network_connected();
+#endif
+
current_network_state = true; // now we are connected
network_reconnect_counter = 0;
LOG_VERBOSE(TAG_NETW, F("Connected = %s"),
WiFi.status() == WL_CONNECTED ? PSTR(D_NETWORK_ONLINE) : PSTR(D_NETWORK_OFFLINE));
+
}
void network_run_scripts()
@@ -101,6 +114,10 @@ void networkSetup()
#if HASP_USE_WIFI > 0
wifiSetup();
#endif
+
+#if HASP_USE_WIREGUARD > 0
+ wg_setup();
+#endif
}
IRAM_ATTR void networkLoop(void)
@@ -178,10 +195,20 @@ void network_get_statusupdate(char* buffer, size_t len)
#if HASP_USE_WIFI > 0
wifi_get_statusupdate(buffer, len);
#endif
+
+#if HASP_USE_WIREGUARD > 0
+ size_t l = strlen(buffer);
+ wg_get_statusupdate(buffer + l, len - l);
+#endif
}
void network_get_ipaddress(char* buffer, size_t len)
{
+#if HASP_USE_WIREGUARD > 0
+ if (wg_get_ipaddress(buffer, len))
+ return;
+#endif
+
#if HASP_USE_ETHERNET > 0
#if defined(ARDUINO_ARCH_ESP32)
#if HASP_USE_ETHSPI > 0
@@ -222,6 +249,10 @@ void network_get_info(JsonDocument& doc)
#if HASP_USE_WIFI > 0
wifi_get_info(doc);
#endif
+
+#if HASP_USE_WIREGUARD > 0
+ wg_get_info(doc);
+#endif
}
#endif
diff --git a/src/sys/net/hasp_network.h b/src/sys/net/hasp_network.h
index 83f9b7b2..95891fb8 100644
--- a/src/sys/net/hasp_network.h
+++ b/src/sys/net/hasp_network.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_NETWORK_H
@@ -11,6 +11,7 @@ bool networkEvery5Seconds(void);
// bool networkEverySecond(void);
void networkStart(void);
void networkStop(void);
+bool network_is_connected();
/* ===== Special Event Processors ===== */
void network_connected();
diff --git a/src/sys/net/hasp_time.cpp b/src/sys/net/hasp_time.cpp
index 37beca4e..3a193049 100644
--- a/src/sys/net/hasp_time.cpp
+++ b/src/sys/net/hasp_time.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include
@@ -18,6 +18,7 @@
#include "Preferences.h"
#include "nvs.h"
#include "nvs_flash.h"
+#include "esp_sntp.h"
#endif
#if defined(ARDUINO_ARCH_ESP32)
@@ -26,6 +27,11 @@ String mytz((char*)0);
String ntp1((char*)0);
String ntp2((char*)0);
String ntp3((char*)0);
+
+void timeSyncCallback(struct timeval* tv)
+{
+ LOG_VERBOSE(TAG_TIME, "NTP Synced: %s", ctime(&tv->tv_sec));
+}
#endif
void timeSetup()
@@ -41,15 +47,19 @@ void timeSetup()
String zone((char*)0);
zone = preferences.getString("zone", TIMEZONE);
- mytz = time_zone_to_possix(zone.c_str());
- ntp1 = preferences.getString("ntp1", NTPSERVER1);
- ntp2 = preferences.getString("ntp2", NTPSERVER2);
- ntp3 = preferences.getString("ntp3", NTPSERVER3);
+ mytz = time_zone_to_possix(zone.c_str());
+ ntp1 = preferences.getString("ntp1", NTPSERVER1);
+ ntp2 = preferences.getString("ntp2", NTPSERVER2);
+ ntp3 = preferences.getString("ntp3", NTPSERVER3);
+ bool enable = preferences.getBool("enable", true);
+ bool dhcp = preferences.getBool("dhcp", true);
LOG_VERBOSE(TAG_TIME, F("%s => %s"), zone.c_str(), mytz.c_str());
LOG_VERBOSE(TAG_TIME, F("NTP: %s %s %s"), ntp1.c_str(), ntp2.c_str(), ntp3.c_str());
+ sntp_set_time_sync_notification_cb(timeSyncCallback);
configTzTime(mytz.c_str(), ntp1.c_str(), ntp2.c_str(), ntp3.c_str());
+ sntp_servermode_dhcp(enable && dhcp ? 1 : 0);
preferences.end();
#endif
}
@@ -100,9 +110,7 @@ String time_zone_to_possix(const char* timezone)
case TZ_ASIA_RIYADH:
case TZ_ETC_GMT__3:
case TZ_EUROPE_ISTANBUL:
- case TZ_EUROPE_KIROV:
case TZ_EUROPE_MINSK:
- case TZ_EUROPE_VOLGOGRAD:
return "<+03>-3";
case TZ_ASIA_TEHRAN:
return "<+0330>-3:30";
@@ -273,9 +281,9 @@ String time_zone_to_possix(const char* timezone)
return "<-03>3";
case TZ_AMERICA_MIQUELON:
return "<-03>3<-02>,M3.2.0,M11.1.0";
- case TZ_AMERICA_GODTHAB:
case TZ_AMERICA_NUUK:
- return "<-03>3<-02>,M3.4.6/22,J365/25";
+ case TZ_AMERICA_GODTHAB:
+ return "<-02>2<-01>,M3.5.0/-1,M10.5.0/0";
case TZ_AMERICA_BOA_VISTA:
case TZ_AMERICA_CAMPO_GRANDE:
case TZ_AMERICA_CARACAS:
@@ -472,10 +480,11 @@ String time_zone_to_possix(const char* timezone)
case TZ_INDIAN_COMORO:
case TZ_INDIAN_MAYOTTE:
return "EAT-3";
- case TZ_AFRICA_CAIRO:
case TZ_AFRICA_TRIPOLI:
case TZ_EUROPE_KALININGRAD:
return "EET-2";
+ case TZ_AFRICA_CAIRO:
+ return "EET-2EEST,M4.5.5/0,M10.5.4/24";
case TZ_EUROPE_CHISINAU:
return "EET-2EEST,M3.5.0,M10.5.0/3";
case TZ_ASIA_BEIRUT:
@@ -496,7 +505,7 @@ String time_zone_to_possix(const char* timezone)
return "EET-2EEST,M3.5.0/3,M10.5.0/4";
case TZ_ASIA_GAZA:
case TZ_ASIA_HEBRON:
- return "EET-2EEST,M3.5.6,M10.5.6";
+ return "EET-2EEST,M3.4.4/50,M10.4.4/50";
case TZ_AMERICA_ATIKOKAN:
case TZ_AMERICA_CANCUN:
case TZ_AMERICA_CAYMAN:
@@ -567,8 +576,10 @@ String time_zone_to_possix(const char* timezone)
case TZ_ASIA_PYONGYANG:
case TZ_ASIA_SEOUL:
return "KST-9";
+ case TZ_EUROPE_KIROV:
case TZ_EUROPE_MOSCOW:
case TZ_EUROPE_SIMFEROPOL:
+ case TZ_EUROPE_VOLGOGRAD:
return "MSK-3";
case TZ_AMERICA_CRESTON:
case TZ_AMERICA_DAWSON:
diff --git a/src/sys/net/hasp_time.h b/src/sys/net/hasp_time.h
index 5d1b3e26..0448fd29 100644
--- a/src/sys/net/hasp_time.h
+++ b/src/sys/net/hasp_time.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TIME_H
diff --git a/src/sys/net/hasp_wifi.cpp b/src/sys/net/hasp_wifi.cpp
index 36f69b26..dc6041e7 100644
--- a/src/sys/net/hasp_wifi.cpp
+++ b/src/sys/net/hasp_wifi.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include
diff --git a/src/sys/net/hasp_wifi.h b/src/sys/net/hasp_wifi.h
index 1418efa0..03c98e06 100644
--- a/src/sys/net/hasp_wifi.h
+++ b/src/sys/net/hasp_wifi.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_WIFI_H
diff --git a/src/sys/net/hasp_wireguard.cpp b/src/sys/net/hasp_wireguard.cpp
new file mode 100644
index 00000000..fb485295
--- /dev/null
+++ b/src/sys/net/hasp_wireguard.cpp
@@ -0,0 +1,130 @@
+/* MIT License - Copyright (c) 2023 Jaroslav Kysela
+ For full license information read the LICENSE file in the project folder */
+
+#include "hasplib.h"
+
+#if HASP_USE_WIREGUARD > 0
+
+#include "hal/hasp_hal.h"
+#include "hasp_debug.h"
+#include "hasp_network.h"
+#include "WireGuard-ESP32.h"
+
+char wg_ip[16] = WIREGUARD_IP;
+char wg_private_key[45] = WIREGUARD_PRIVATE_KEY;
+char wg_ep_ip[40] = WIREGUARD_EP_IP;
+uint16_t wg_ep_port = WIREGUARD_EP_PORT;
+char wg_ep_public_key[45] = WIREGUARD_EP_PUBLIC_KEY;
+static WireGuard wg;
+
+void wg_setup()
+{
+ Preferences preferences;
+ nvs_user_begin(preferences, FP_WG, true);
+ String privkey = preferences.getString(FP_CONFIG_PRIVATE_KEY, String(wg_private_key)); // Update from NVS if it exists
+ strncpy(wg_private_key, privkey.c_str(), sizeof(wg_private_key)-1);
+ wg_private_key[sizeof(wg_private_key)-1] = '\0';
+}
+
+int wg_config_valid()
+{
+ return strlen(wg_ip) > 7 && strlen(wg_ep_ip) > 7 &&
+ strlen(wg_private_key) == 44 && strlen(wg_ep_public_key) == 44 &&
+ wg_ep_port > 0;
+}
+
+void wg_network_disconnected()
+{
+ wg.end();
+}
+
+void wg_network_connected()
+{
+ IPAddress local_ip;
+ LOG_VERBOSE(TAG_WG, F("WireGuard connected"));
+ if (local_ip.fromString(wg_ip) && wg_config_valid()) {
+ LOG_INFO(TAG_WG, F("WireGuard begin (%s -> %s:%u)"), wg_ip, wg_ep_ip, wg_ep_port);
+ wg.begin(local_ip, wg_private_key, wg_ep_ip, wg_ep_public_key, wg_ep_port);
+ }
+}
+
+void wg_get_statusupdate(char* buffer, size_t len)
+{
+ snprintf_P(buffer, len, PSTR("\"wg\":\"%s\","), wg.is_initialized() ? "on" : "off");
+}
+
+int wg_get_ipaddress(char* buffer, size_t len)
+{
+ if (wg.is_initialized()) {
+ snprintf(buffer, len, "%s", wg_ip);
+ return 1;
+ }
+ return 0;
+}
+
+void wg_get_info(JsonDocument& doc)
+{
+ JsonObject info = doc.createNestedObject(F(D_INFO_WIREGUARD));
+ info[F(D_INFO_STATUS)] = wg.is_initialized() ? F(D_WG_INITIALIZED) : F(D_WG_BAD_CONFIG);
+ info[F(D_INFO_IP_ADDRESS)] = String(wg_ip);
+ info[F(D_INFO_ENDPOINT_IP)] = String(wg_ep_ip);
+ info[F(D_INFO_ENDPOINT_PORT)] = String(wg_ep_port);
+}
+
+#if HASP_USE_CONFIG > 0
+bool wgGetConfig(const JsonObject& settings)
+{
+ bool changed = false;
+
+ if(strcmp(wg_ip, settings[FPSTR(FP_CONFIG_VPN_IP)].as().c_str()) != 0) changed = true;
+ settings[FPSTR(FP_CONFIG_VPN_IP)] = wg_ip;
+
+ if(strcmp(wg_private_key, settings[FPSTR(FP_CONFIG_PRIVATE_KEY)].as().c_str()) != 0) changed = true;
+ //settings[FPSTR(FP_CONFIG_PRIVATE_KEY)] = wg_private_key;
+ settings[FPSTR(FP_CONFIG_PRIVATE_KEY)] = D_PASSWORD_MASK;
+
+ if(strcmp(wg_ep_ip, settings[FPSTR(FP_CONFIG_HOST)].as().c_str()) != 0) changed = true;
+ settings[FPSTR(FP_CONFIG_HOST)] = wg_ep_ip;
+
+ if(wg_ep_port != settings[FPSTR(FP_CONFIG_PORT)].as()) changed = true;
+ settings[FPSTR(FP_CONFIG_PORT)] = wg_ep_port;
+
+ if(strcmp(wg_ep_public_key, settings[FPSTR(FP_CONFIG_PUBLIC_KEY)].as().c_str()) != 0) changed = true;
+ settings[FPSTR(FP_CONFIG_PUBLIC_KEY)] = wg_ep_public_key;
+
+ if(changed) configOutput(settings, TAG_WG);
+ return changed;
+}
+
+bool wgSetConfig(const JsonObject& settings)
+{
+ Preferences preferences;
+ nvs_user_begin(preferences, "wg", false);
+
+ configOutput(settings, TAG_WG);
+ bool changed = false;
+
+ changed |= configSet((char *)wg_ip, sizeof(wg_ip), settings[FPSTR(FP_CONFIG_VPN_IP)], F("wgIp"));
+ if(!settings[FPSTR(FP_CONFIG_PRIVATE_KEY)].isNull() &&
+ settings[FPSTR(FP_CONFIG_PRIVATE_KEY)].as() != String(FPSTR(D_PASSWORD_MASK))) {
+ changed |= strcmp(wg_private_key, settings[FPSTR(FP_CONFIG_PRIVATE_KEY)]) != 0;
+ strncpy(wg_private_key, settings[FPSTR(FP_CONFIG_PRIVATE_KEY)], sizeof(wg_private_key)-1);
+ wg_private_key[sizeof(wg_private_key)-1] = '\0';
+ nvsUpdateString(preferences, FP_CONFIG_PRIVATE_KEY, settings[FPSTR(FP_CONFIG_PRIVATE_KEY)]);
+ }
+ changed |= configSet((char *)wg_ep_ip, sizeof(wg_ep_ip), settings[FPSTR(FP_CONFIG_HOST)], F("wgEpIp"));
+ changed |= configSet(wg_ep_port, settings[FPSTR(FP_CONFIG_PORT)], F("wgEpPort"));
+ changed |= configSet((char *)wg_ep_public_key, sizeof(wg_ep_public_key), settings[FPSTR(FP_CONFIG_PUBLIC_KEY)], F("wgEpPubKey"));
+
+// may reset device...
+// if (changed && network_is_connected()) {
+// wg.end();
+// wg_network_connected();
+// }
+
+ return changed;
+}
+#endif
+
+
+#endif /* WIREGUARD */
diff --git a/src/sys/net/hasp_wireguard.h b/src/sys/net/hasp_wireguard.h
new file mode 100644
index 00000000..486c711e
--- /dev/null
+++ b/src/sys/net/hasp_wireguard.h
@@ -0,0 +1,40 @@
+/* MIT License - Copyright (c) 2023 Jaroslav Kysela
+ For full license information read the LICENSE file in the project folder */
+
+#ifndef HASP_WIREGUARD_H
+#define HASP_WIREGUARD_H
+
+void wg_setup();
+int wg_config_valid();
+void wg_network_disconnected();
+void wg_network_connected();
+void wg_get_statusupdate(char* buffer, size_t len);
+int wg_get_ipaddress(char* buffer, size_t len);
+void wg_get_info(JsonDocument& doc);
+
+#if HASP_USE_CONFIG > 0
+bool wgGetConfig(const JsonObject& settings);
+bool wgSetConfig(const JsonObject& settings);
+#endif
+
+#ifndef WIREGUARD_IP
+#define WIREGUARD_IP ""
+#endif
+
+#ifndef WIREGUARD_PRIVATE_KEY
+#define WIREGUARD_PRIVATE_KEY ""
+#endif
+
+#ifndef WIREGUARD_EP_IP
+#define WIREGUARD_EP_IP ""
+#endif
+
+#ifndef WIREGUARD_EP_PORT
+#define WIREGUARD_EP_PORT 51820
+#endif
+
+#ifndef WIREGUARD_EP_PUBLIC_KEY
+#define WIREGUARD_EP_PUBLIC_KEY ""
+#endif
+
+#endif
diff --git a/src/sys/svc/hasp_console.cpp b/src/sys/svc/hasp_console.cpp
index 9e7f1632..04ab243f 100644
--- a/src/sys/svc/hasp_console.cpp
+++ b/src/sys/svc/hasp_console.cpp
@@ -1,12 +1,14 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
#if HASP_USE_CONSOLE > 0
+#if HASP_TARGET_ARDUINO
#include "ConsoleInput.h"
#include
+#endif
#include "hasp_debug.h"
#include "hasp_console.h"
@@ -17,15 +19,18 @@
extern hasp_http_config_t http_config;
#endif
+#if HASP_TARGET_ARDUINO
// Create a new Stream that buffers all writes to serialClient
HardwareSerial* bufferedSerialClient = (HardwareSerial*)&HASP_SERIAL;
+ConsoleInput* console;
+#endif
uint8_t consoleLoginState = CONSOLE_UNAUTHENTICATED;
uint16_t serialPort = 0;
uint8_t consoleEnabled = true; // Enable serial debug output
uint8_t consoleLoginAttempt = 0; // Initial attempt
-ConsoleInput* console;
+#if HASP_TARGET_ARDUINO
void console_update_prompt()
{
if(console) console->update(__LINE__);
@@ -101,9 +106,21 @@ static void console_process_line(const char* input)
}
}
}
+#elif HASP_TARGET_PC
+static bool console_running = true;
+static void console_thread(void* arg)
+{
+ while(console_running) {
+ std::string input;
+ std::getline(std::cin, input);
+ dispatch_text_line(input.c_str(), TAG_CONS);
+ }
+}
+#endif
void consoleStart()
{
+#if HASP_TARGET_ARDUINO
LOG_TRACE(TAG_MSGR, F(D_SERVICE_STARTING));
console = new ConsoleInput(bufferedSerialClient, HASP_CONSOLE_BUFFER);
if(console) {
@@ -126,16 +143,27 @@ void consoleStart()
console_logoff();
LOG_ERROR(TAG_CONS, F(D_SERVICE_START_FAILED));
}
+#elif HASP_TARGET_PC
+ LOG_TRACE(TAG_MSGR, F(D_SERVICE_STARTING));
+ haspDevice.run_thread(console_thread, NULL);
+#endif
}
void consoleStop()
{
+#if HASP_TARGET_ARDUINO
console_logoff();
Log.unregisterOutput(0); // serialClient
HASP_SERIAL.end();
-
delete console;
console = NULL;
+#elif HASP_TARGET_PC
+#if defined(WINDOWS)
+
+#elif defined(POSIX)
+
+#endif
+#endif
}
void consoleSetup()
@@ -147,6 +175,7 @@ void consoleSetup()
IRAM_ATTR void consoleLoop()
{
+#if HASP_TARGET_ARDUINO
if(!console) return;
bool update = false;
@@ -168,13 +197,14 @@ IRAM_ATTR void consoleLoop()
case 0:
case -1:
break;
-
+
default: {
update = true;
}
}
}
if(update) console_update_prompt();
+#endif
}
#if HASP_USE_CONFIG > 0
@@ -201,4 +231,4 @@ bool consoleSetConfig(const JsonObject& settings)
}
#endif // HASP_USE_CONFIG
-#endif
\ No newline at end of file
+#endif
diff --git a/src/sys/svc/hasp_console.h b/src/sys/svc/hasp_console.h
index ac2e4223..18834508 100644
--- a/src/sys/svc/hasp_console.h
+++ b/src/sys/svc/hasp_console.h
@@ -1,13 +1,13 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_CONSOLE_H
#define HASP_CONSOLE_H
-#if HASP_USE_CONSOLE > 0
-
#include "hasplib.h"
+#if HASP_USE_CONSOLE > 0
+
/* ===== Default Event Processors ===== */
void consoleSetup();
IRAM_ATTR void consoleLoop(void);
diff --git a/src/sys/svc/hasp_ftp.cpp b/src/sys/svc/hasp_ftp.cpp
index 0e1e8ef3..9b1e11ac 100644
--- a/src/sys/svc/hasp_ftp.cpp
+++ b/src/sys/svc/hasp_ftp.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
diff --git a/src/sys/svc/hasp_ftp.h b/src/sys/svc/hasp_ftp.h
index 11571a95..35f6b69f 100644
--- a/src/sys/svc/hasp_ftp.h
+++ b/src/sys/svc/hasp_ftp.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_FTP_H
diff --git a/src/sys/svc/hasp_http.cpp b/src/sys/svc/hasp_http.cpp
index 046c3831..eba778bb 100644
--- a/src/sys/svc/hasp_http.cpp
+++ b/src/sys/svc/hasp_http.cpp
@@ -1,7 +1,10 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
+
+#if HASP_USE_HTTP > 0
+
#include "ArduinoLog.h"
#define HTTP_LEGACY
@@ -21,7 +24,6 @@
#include "hasp_gui.h"
#include "hasp_debug.h"
-#if HASP_USE_HTTP > 0
#include "sys/net/hasp_network.h"
#include "sys/net/hasp_time.h"
@@ -408,6 +410,10 @@ bool http_save_config()
#if HASP_USE_WIFI > 0
} else if(save == FP_WIFI) {
updated = wifiSetConfig(settings.as());
+#endif
+#if HASP_USE_WIREGUARD > 0
+ } else if(save == FP_WG) {
+ updated = wgSetConfig(settings.as());
#endif
}
}
@@ -561,7 +567,7 @@ static void webHandleApi()
{ // http://plate01/api
if(!http_is_authenticated("api")) return;
- DynamicJsonDocument doc(2048);
+ DynamicJsonDocument doc(max(MAX_CONFIG_JSON_ALLOC_SIZE, 2048));
String contentType = http_get_content_type(F(".json"));
String endpoint((char*)0);
endpoint = webServer.pathArg(0);
@@ -635,6 +641,10 @@ static void webHandleApi()
add_license(obj, "AceButton", "2018", "Brian T. Park", "mit");
obj = doc.createNestedObject();
add_license(obj, "QR Code generator", "", "Project Nayuki", "mit");
+#if HASP_USE_WIREGUARD > 0
+ obj = doc.createNestedObject();
+ add_license(obj, "WireGuard", "2021", "Kenta Ida fugafuga.org, Daniel Hope www.floorsense.nz", "bsd", 1);
+#endif
}
{
char output[HTTP_PAGE_SIZE];
@@ -688,6 +698,11 @@ static void webHandleApi()
settings.createNestedObject(module);
timeGetConfig(settings[module]);
#endif
+#if HASP_USE_WIREGUARD > 0
+ module = FPSTR(FP_WG);
+ settings.createNestedObject(module);
+ wgGetConfig(settings[module]);
+#endif
#if HASP_USE_MQTT > 0
module = FPSTR(FP_MQTT);
settings.createNestedObject(module);
@@ -790,6 +805,11 @@ static void webHandleApiConfig()
timeSetConfig(settings);
} else
#endif
+#if HASP_USE_WIREGUARD > 0
+ if(!strcasecmp(endpoint_key, FP_WG)) {
+ wgSetConfig(settings);
+ } else
+#endif
#if HASP_USE_MQTT > 0
if(!strcasecmp(endpoint_key, FP_MQTT)) {
mqttSetConfig(settings);
@@ -831,6 +851,11 @@ static void webHandleApiConfig()
timeGetConfig(settings);
} else
#endif
+#if HASP_USE_WIREGUARD > 0
+ if(!strcasecmp(endpoint_key, FP_WG)) {
+ wgGetConfig(settings);
+ } else
+#endif
#if HASP_USE_MQTT > 0
if(!strcasecmp(endpoint_key, FP_MQTT)) {
mqttGetConfig(settings);
@@ -897,7 +922,7 @@ static void http_handle_about()
-openHASP
Copyright 2019-2023 Francis Van RoieMIT License
+openHASP
Copyright 2019-2024 Francis Van RoieMIT License
@@ -937,6 +962,8 @@ static void http_handle_info()
| {{ item }} |
Wifi |
| {{ item }} |
+WireGuard |
+ | {{ item }} |
Module |
| {{ item }} |
)";
@@ -1109,7 +1136,7 @@ static inline int handleFilesystemFile(String path)
configFile = FPSTR(FP_HASP_CONFIG_FILE);
if(path.endsWith(configFile.c_str())) { // "//config.json" is also a valid path!
- DynamicJsonDocument settings(2048);
+ DynamicJsonDocument settings(MAX_CONFIG_JSON_ALLOC_SIZE);
DeserializationError error = configParseFile(configFile, settings);
if(error) return 500; // Internal Server Error
@@ -1415,6 +1442,9 @@ static void http_handle_config()
#if HASP_USE_WIFI > 0
html[min(i++, len)] = R"()";
#endif
+#if HASP_USE_WIREGUARD > 0
+ html[min(i++, len)] = R"()";
+#endif
#if HASP_USE_MQTT > 0
html[min(i++, len)] = R"()";
#endif
@@ -2302,6 +2332,50 @@ static void http_handle_wifi()
#endif // HASP_USE_WIFI
+////////////////////////////////////////////////////////////////////////////////////////////////////
+#if HASP_USE_WIREGUARD > 0
+static void http_handle_wireguard()
+{ // http://plate01/config/wireguard
+ if(!http_is_authenticated(F("config/wireguard"))) return;
+
+ const char* html[20];
+ int i = 0;
+ int len = (sizeof(html) / sizeof(html[0])) - 1;
+
+ html[min(i++, len)] = "";
+ html[min(i++, len)] = haspDevice.get_hostname();
+ html[min(i++, len)] = "
";
+ html[min(i++, len)] = R"(
+
+)";
+ html[min(i++, len)] = R"()";
+ http_send_content(html, min(i, len));
+}
+
+#endif // HASP_USE_WIREGUARD
+
static inline int handleFirmwareFile(String path)
{
String contentType((char*)0);
@@ -2715,6 +2789,9 @@ void httpSetup()
#if HASP_USE_WIFI > 0
webServer.on("/config/wifi", http_handle_wifi);
#endif
+#if HASP_USE_WIREGUARD > 0
+ webServer.on("/config/wireguard", http_handle_wireguard);
+#endif
#if HASP_USE_GPIO > 0
webServer.on("/config/gpio", webHandleGpioConfig);
webServer.on("/config/gpio/options", webHandleGpioOutput);
diff --git a/src/sys/svc/hasp_http.h b/src/sys/svc/hasp_http.h
index bdbe13c4..388bb67c 100644
--- a/src/sys/svc/hasp_http.h
+++ b/src/sys/svc/hasp_http.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_HTTP_H
diff --git a/src/sys/svc/hasp_http_async.cpp b/src/sys/svc/hasp_http_async.cpp
index 13d51d20..e4e882ef 100644
--- a/src/sys/svc/hasp_http_async.cpp
+++ b/src/sys/svc/hasp_http_async.cpp
@@ -1,8 +1,11 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
//#include "webServer.h"
#include "hasplib.h"
+
+#if HASP_USE_HTTP_ASYNC > 0
+
#include "ArduinoLog.h"
#if defined(ARDUINO_ARCH_ESP32)
@@ -16,7 +19,6 @@
#include "hasp_gui.h"
#include "hasp_debug.h"
-#if HASP_USE_HTTP_ASYNC > 0
#include "sys/net/hasp_network.h"
/* clang-format off */
@@ -487,7 +489,7 @@ void webHandleAbout(AsyncWebServerRequest* request)
String httpMessage((char*)0);
httpMessage.reserve(HTTP_PAGE_SIZE);
- httpMessage += F("openHASP
Copyright© 2019-2022 Francis Van Roie ");
+ httpMessage += F("openHASP
Copyright© 2019-2024 Francis Van Roie ");
httpMessage += mitLicense;
httpMessage += F("Based on the previous work of the following open source developers.
");
httpMessage += F("HASwitchPlate
Copyright© 2019 Allen Derusha allen@derusha.org");
@@ -934,7 +936,7 @@ int handleFileRead(AsyncWebServerRequest* request, String path)
if(!strncasecmp(file.name(), configFile.c_str(), configFile.length())) {
file.close();
- DynamicJsonDocument settings(8 * 256);
+ DynamicJsonDocument settings(MAX_CONFIG_JSON_ALLOC_SIZE);
DeserializationError error = configParseFile(configFile, settings);
if(error) return 500; // Internal Server Error
@@ -1259,7 +1261,7 @@ void webHandleMqttConfig(AsyncWebServerRequest* request)
////////////////////////////////////////////////////////////////////////////////////////////////////
void webHandleGuiConfig(AsyncWebServerRequest* request)
-{ // http://plate01/config/wifi
+{ // http://plate01/config/gui
if(!httpIsAuthenticated(request, F("config/gui"))) return;
{
diff --git a/src/sys/svc/hasp_mdns.cpp b/src/sys/svc/hasp_mdns.cpp
index 0252fb9c..2e00239d 100644
--- a/src/sys/svc/hasp_mdns.cpp
+++ b/src/sys/svc/hasp_mdns.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
@@ -51,21 +51,32 @@ void mdnsStart()
};*/
if(MDNS.begin(haspDevice.get_hostname())) {
- char value[32];
+ char value[1024]; // 32
char service[12];
char key[12];
char proto[4];
sprintf_P(proto, PSTR("tcp"));
- strcpy_P(service, PSTR("http"));
+ // strcpy_P(service, PSTR("http"));
+ // MDNS.addService(service, proto, 80);
+
+ // strcpy_P(key, PSTR("app_version"));
+ // MDNS.addServiceTxt(service, proto, key, haspDevice.get_version());
+
+ // strcpy_P(key, PSTR("app_name"));
+ // strcpy_P(value, PSTR(D_MANUFACTURER));
+ // MDNS.addServiceTxt(service, proto, key, value);
+
+ strcpy_P(service, PSTR("openhasp"));
MDNS.addService(service, proto, 80);
- strcpy_P(key, PSTR("app_version"));
- MDNS.addServiceTxt(service, proto, key, haspDevice.get_version());
+ StaticJsonDocument<1024> doc;
+ dispatch_get_discovery_data(doc);
- strcpy_P(key, PSTR("app_name"));
- strcpy_P(value, PSTR(D_MANUFACTURER));
- MDNS.addServiceTxt(service, proto, key, value);
+ JsonObject data = doc.as();
+ for(JsonPair i : data) {
+ MDNS.addServiceTxt(service, proto, i.key().c_str(), i.value().as());
+ }
// if(debugTelnetEnabled) {
strcpy_P(service, PSTR("telnet"));
@@ -85,7 +96,7 @@ bool mdns_remove_service(char* service, char* proto)
#endif
#if ESP8266
- return MDNS.removeService(haspDevice.get_hostname(),"_arduino", "_tcp");
+ return MDNS.removeService(haspDevice.get_hostname(), "_arduino", "_tcp");
#endif
}
diff --git a/src/sys/svc/hasp_mdns.h b/src/sys/svc/hasp_mdns.h
index 2f472814..82893e16 100644
--- a/src/sys/svc/hasp_mdns.h
+++ b/src/sys/svc/hasp_mdns.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_MDNS_H
diff --git a/src/sys/svc/hasp_ota.cpp b/src/sys/svc/hasp_ota.cpp
index 48d9fb9e..d42ccf61 100644
--- a/src/sys/svc/hasp_ota.cpp
+++ b/src/sys/svc/hasp_ota.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#ifndef HASP_ARDUINOOTA_PORT
#define HASP_ARDUINOOTA_PORT 3232
@@ -76,14 +77,14 @@ extern const uint8_t rootca_crt_bundle_start[] asm("_binary_data_cert_x509_crt_b
#endif // ARDUINO_ARCH_ESP32
static WiFiClientSecure secureClient;
-std::string otaUrl = "http://ota.netwize.be";
+/*std::string otaUrl = "http://ota.netwize.be";*/
uint16_t arduinoOtaPort = HASP_ARDUINOOTA_PORT;
int8_t otaPrecentageComplete = -1;
bool otaUpdateCheck()
{ // firmware update check
- WiFiClientSecure wifiUpdateClientSecure;
+ /*WiFiClientSecure wifiUpdateClientSecure;
HTTPClient updateClient;
LOG_TRACE(TAG_OTA, F(D_OTA_CHECK_UPDATE), otaUrl.c_str());
@@ -115,7 +116,7 @@ bool otaUpdateCheck()
// }
}
LOG_VERBOSE(TAG_OTA, F(D_OTA_CHECK_COMPLETE));
- }
+ }*/
return true;
}
@@ -210,9 +211,9 @@ void otaSetup(void)
secureClient.setTimeout(12); // timeout argument is defined in seconds
#if HASP_USE_ARDUINOOTA > 0
- if(strlen(otaUrl.c_str())) {
+ /*if(strlen(otaUrl.c_str())) {
LOG_INFO(TAG_OTA, otaUrl.c_str());
- }
+ }*/
if(arduinoOtaPort > 0) {
ArduinoOTA.onStart(ota_on_start);
diff --git a/src/sys/svc/hasp_ota.h b/src/sys/svc/hasp_ota.h
index f338ad6f..be412060 100644
--- a/src/sys/svc/hasp_ota.h
+++ b/src/sys/svc/hasp_ota.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_OTA_H
diff --git a/src/sys/svc/hasp_slave.cpp b/src/sys/svc/hasp_slave.cpp
index f055710e..227492fa 100644
--- a/src/sys/svc/hasp_slave.cpp
+++ b/src/sys/svc/hasp_slave.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
diff --git a/src/sys/svc/hasp_slave.h b/src/sys/svc/hasp_slave.h
index 9fd36749..0a05bc80 100644
--- a/src/sys/svc/hasp_slave.h
+++ b/src/sys/svc/hasp_slave.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TASMOTACLIENT_H
diff --git a/src/sys/svc/hasp_telnet.cpp b/src/sys/svc/hasp_telnet.cpp
index da8f2e85..1f3d8a09 100644
--- a/src/sys/svc/hasp_telnet.cpp
+++ b/src/sys/svc/hasp_telnet.cpp
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2023 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
diff --git a/src/sys/svc/hasp_telnet.h b/src/sys/svc/hasp_telnet.h
index 91324c69..8f9fbd0e 100644
--- a/src/sys/svc/hasp_telnet.h
+++ b/src/sys/svc/hasp_telnet.h
@@ -1,4 +1,4 @@
-/* MIT License - Copyright (c) 2019-2022 Francis Van Roie
+/* MIT License - Copyright (c) 2019-2024 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_TELNET_H
diff --git a/tools/osx_build_extra.py b/tools/osx_build_extra.py
index 3f445946..a36fc387 100644
--- a/tools/osx_build_extra.py
+++ b/tools/osx_build_extra.py
@@ -1,6 +1,7 @@
Import("env")
-env.Replace(CC="gcc-10", CXX="g++-10")
+#env.Replace(CC="gcc-10", CXX="g++-10")
+env.Replace(CC="gcc-13", CXX="g++-13")
env.Replace(BUILD_SCRIPT="tools/osx_build_script.py")
diff --git a/user_setups/darwin_sdl/darwin_sdl_64bits.ini b/user_setups/darwin/darwin_sdl.ini
similarity index 70%
rename from user_setups/darwin_sdl/darwin_sdl_64bits.ini
rename to user_setups/darwin/darwin_sdl.ini
index 25f8d593..b1c4057a 100644
--- a/user_setups/darwin_sdl/darwin_sdl_64bits.ini
+++ b/user_setups/darwin/darwin_sdl.ini
@@ -1,4 +1,4 @@
-[env:darwin_sdl_64bits]
+[env:darwin_sdl]
lib_archive = false
platform = native@^1.1.4
extra_scripts =
@@ -6,7 +6,8 @@ extra_scripts =
tools/linux_build_extra.py
build_flags =
${env.build_flags}
- -D HASP_MODEL="MacOS X App"
+ -D HASP_MODEL="MacOS X App"
+ -D HASP_TARGET_PC=1
; ----- Monitor
-D TFT_WIDTH=240
@@ -25,8 +26,8 @@ build_flags =
-D HASP_USE_SPIFFS=0
-D HASP_USE_LITTLEFS=0
-D HASP_USE_EEPROM=0
- -D HASP_USE_GPIO=1
- -D HASP_USE_CONFIG=0 ; Standalone application, as library
+ -D HASP_USE_GPIO=0
+ -D HASP_USE_CONFIG=1
-D HASP_USE_DEBUG=1
-D HASP_USE_PNGDECODE=1
-D HASP_USE_BMPDECODE=1
@@ -48,8 +49,8 @@ build_flags =
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_VERBOSE_MAKEFILE=TRUE
;-D NO_PERSISTENCE
- -I.pio/libdeps/darwin_sdl_64bits/paho/src
- -I.pio/libdeps/darwin_sdl_64bits/ArduinoJson/src
+ -I.pio/libdeps/darwin_sdl/paho/src
+ -I.pio/libdeps/darwin_sdl/ArduinoJson/src
-I lib/ArduinoJson/src
-I lib/lv_fs_if
!python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))"
@@ -58,8 +59,10 @@ build_flags =
-lm
-lpthread
; MacOS with Homebrew
- -I/usr/local/include
- -L/usr/local/lib
+ ;-I/usr/local/include
+ ;-L/usr/local/lib
+ -I/opt/homebrew/include
+ -L/opt/homebrew/lib
-DTARGET_OS_MAC=1
lib_deps =
@@ -67,7 +70,7 @@ lib_deps =
; lv_drivers@~7.9.1
;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip
https://github.com/eclipse/paho.mqtt.c.git
- bblanchon/ArduinoJson@^6.21.3 ; Json(l) parser
+ bblanchon/ArduinoJson@^6.21.5 ; Json(l) parser
https://github.com/fvanroie/lv_drivers
git+https://github.com/lvgl/lv_lib_png.git#release/v7
@@ -77,25 +80,25 @@ lib_ignore =
ArduinoLog
lv_lib_qrcode
ETHSPI
+ freetype
build_src_filter =
+<*>
-<*.h>
- +<../hal/sdl2>
- +<../.pio/libdeps/darwin_sdl_64bits/paho/src/*.c>
- +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.c>
- +<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTClient.h>
- -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsync.c>
- -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTAsyncUtils.c>
- -<../.pio/libdeps/darwin_sdl_64bits/paho/src/MQTTVersion.c>
- -<../.pio/libdeps/darwin_sdl_64bits/paho/src/SSLSocket.c>
- +
- -
- -
+ +<../.pio/libdeps/darwin_sdl/paho/src/*.c>
+ -<../.pio/libdeps/darwin_sdl/paho/src/MQTTClient.c>
+ +<../.pio/libdeps/darwin_sdl/paho/src/MQTTAsync.c>
+ +<../.pio/libdeps/darwin_sdl/paho/src/MQTTAsyncUtils.c>
+ -<../.pio/libdeps/darwin_sdl/paho/src/MQTTVersion.c>
+ -<../.pio/libdeps/darwin_sdl/paho/src/SSLSocket.c>
+ -
+ +
+ +
-
-
-
+
+ +
-
+
-
@@ -109,4 +112,4 @@ build_src_filter =
+
-
+
- +<../.pio/libdeps/darwin_sdl_64bits/ArduinoJson/src/ArduinoJson.h>
+ +<../.pio/libdeps/darwin_sdl/ArduinoJson/src/ArduinoJson.h>
diff --git a/user_setups/esp32/_esp32.ini b/user_setups/esp32/_esp32.ini
index 93d581ff..aabb2678 100644
--- a/user_setups/esp32/_esp32.ini
+++ b/user_setups/esp32/_esp32.ini
@@ -35,6 +35,7 @@ files =
build_flags =
${env.build_flags}
+ -D HASP_TARGET_ARDUINO=1
-D HTTP_UPLOAD_BUFLEN=1024 ; lower http upload buffer
-D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages
-D HASP_CONSOLE_BUFFER=256 ; maximum length of a console/telnet command
@@ -95,7 +96,7 @@ lib_deps =
git+https://github.com/fvanroie/ConsoleInput.git#dev
; lorol/LittleFS_esp32@^1.0.6 ; for Arduino v1 only
bxparks/AceButton@^1.10.1 ; GPIO button library
- bblanchon/StreamUtils@^1.7.3 ; for EEPromStream and BufferedTelnetClient
+ bblanchon/StreamUtils@^1.8.0 ; for EEPromStream and BufferedTelnetClient
; knolleary/PubSubClient@^2.8.0 ; MQTT client
extra_scripts =
@@ -140,8 +141,10 @@ lib_deps =
extends = esp32
framework = arduino
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.05.01/platform-espressif32.zip
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.08.01/platform-espressif32.zip
-
+; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.08.01/platform-espressif32.zip
+;platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32.zip
+;;;platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.11.01/platform-espressif32.zip
+platform = https://github.com/Jason2866/platform-espressif32/releases/download/2023.10.02/platform-espressif32-2023.10.02.zip
lib_ignore =
${esp32.lib_ignore}
LittleFS_esp32 ; Not needed for Arduino v2
diff --git a/user_setups/esp32/esp32-2432s028.ini b/user_setups/esp32/esp32-2432s028.ini
new file mode 100644
index 00000000..338e60b2
--- /dev/null
+++ b/user_setups/esp32/esp32-2432s028.ini
@@ -0,0 +1,130 @@
+;***************************************************;
+; Sunton ESP32-WROOM custom dev board with ;
+; - ILI9341 TFT SPI 4-WIRE ;
+; - XPT2046 touch controller ;
+;***************************************************;
+
+[esp32-2432s028r]
+extends = arduino_esp32_v2
+board = esp32dev
+upload_speed = 921600
+
+build_flags =
+ ${arduino_esp32_v2.build_flags}
+ ${esp32.no_ps_ram}
+
+;region -- TFT_eSPI build options ------------------------
+ ; -D USER_SETUP_LOADED=1
+ -D LGFX_USE_V1=1
+ -D TFT_RST=-1
+ -D TFT_SCLK=14
+ -D TFT_DC=2
+ -D TFT_CS=15
+ -D TFT_MOSI=13
+ -D TFT_MISO=12
+ -D TFT_BCKL=21
+ -D SUPPORT_TRANSACTIONS
+ -D SPI_READ_FREQUENCY=20000000
+ -D TOUCH_OFFSET_ROTATION=0 ; 1=swap xy, 2=invert x, 4=inverty
+
+ -D ESP32_2432S028R=1
+;endregion
+
+; -- Debugging options -----------------------------
+; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
+
+lib_deps =
+ ${arduino_esp32_v2.lib_deps}
+ ${lovyangfx.lib_deps}
+
+
+[env:esp32-2432s028r_4MB]
+extends = esp32-2432s028r, flash_4mb
+build_flags =
+ ${esp32-2432s028r.build_flags}
+ -D ILI9341_DRIVER=1
+ -D INVERT_COLORS=0
+ -D TFT_ROTATION=0 ; 0=0, 1=90, 2=180 or 3=270 degree
+ -D TFT_WIDTH=240
+ -D TFT_HEIGHT=320
+ -D TOUCH_DRIVER=0x2046 ; XPT2606 Resistive touch panel driver
+ -D HASP_USE_LGFX_TOUCH=1
+ -D TOUCH_CS=33
+ -D TOUCH_SCLK=25
+ -D TOUCH_MOSI=32
+ -D TOUCH_MISO=39
+ -D TOUCH_SDA=-1
+ -D TOUCH_SCL=-1
+ -D TOUCH_IRQ=36
+ -D SPI_FREQUENCY=55000000
+ -D SPI_TOUCH_FREQUENCY=2500000
+
+; -- Debugging options -----------------------------
+; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
+
+lib_deps =
+ ${esp32-2432s028r.lib_deps}
+ ;${tft_espi.lib_deps}
+ ${lovyangfx.lib_deps}
+ ;${goodix.lib_deps}
+
+[env:esp32-2432s028r-st7789_4MB]
+extends = esp32-2432s028r, flash_4mb
+build_flags =
+ ${esp32-2432s028r.build_flags}
+ -D ST7789_DRIVER=1
+ -D INVERT_COLORS=0
+ -D TFT_ROTATION=0 ; 0=0, 1=90, 2=180 or 3=270 degree
+ -D TFT_WIDTH=240
+ -D TFT_HEIGHT=320
+ -D TOUCH_DRIVER=0x2046 ; XPT2606 Resistive touch panel driver
+ -D HASP_USE_LGFX_TOUCH=1
+ -D TOUCH_CS=33
+ -D TOUCH_SCLK=25
+ -D TOUCH_MOSI=32
+ -D TOUCH_MISO=39
+ -D TOUCH_SDA=-1
+ -D TOUCH_SCL=-1
+ -D TOUCH_IRQ=36
+ -D SPI_FREQUENCY=24000000
+ -D SPI_TOUCH_FREQUENCY=2500000
+
+; -- Debugging options -----------------------------
+; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
+
+lib_deps =
+ ${esp32-2432s028r.lib_deps}
+ ;${tft_espi.lib_deps}
+ ${lovyangfx.lib_deps}
+ ;${goodix.lib_deps}
+
+
+[env:esp32-2432s028r-ili9342_4MB]
+extends = esp32-2432s028r, flash_4mb
+build_flags =
+ ${esp32-2432s028r.build_flags}
+ -D ILI9342_DRIVER=1
+ -D INVERT_COLORS=1
+ -D TFT_ROTATION=4 ; 0=0, 1=90, 2=180 or 3=270 degree
+ -D TFT_WIDTH=320
+ -D TFT_HEIGHT=240
+ -D TOUCH_DRIVER=0x2046 ; XPT2606 Resistive touch panel driver
+ -D HASP_USE_LGFX_TOUCH=1
+ -D TOUCH_CS=33
+ -D TOUCH_SCLK=25
+ -D TOUCH_MOSI=32
+ -D TOUCH_MISO=39
+ -D TOUCH_SDA=-1
+ -D TOUCH_SCL=-1
+ -D TOUCH_IRQ=36
+ -D SPI_FREQUENCY=55000000
+ -D SPI_TOUCH_FREQUENCY=2500000
+
+; -- Debugging options -----------------------------
+; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
+
+lib_deps =
+ ${esp32-2432s028r.lib_deps}
+ ;${tft_espi.lib_deps}
+ ${lovyangfx.lib_deps}
+ ;${goodix.lib_deps}
diff --git a/user_setups/esp32/huzzah32-featherwing-24-v2.ini b/user_setups/esp32/huzzah32-featherwing-24-v2.ini
new file mode 100644
index 00000000..8c97b591
--- /dev/null
+++ b/user_setups/esp32/huzzah32-featherwing-24-v2.ini
@@ -0,0 +1,31 @@
+;***************************************************;
+; HUZZAH32 ESP32 with Featherwing TFT 2.4" V2 ;
+; - HUZZAH32 esp32 board ;
+; - ili9341 TFT Featherwing 2.4" V2 ;
+; - TSC2007 touch controller ;
+;***************************************************;
+
+[env:huzzah32-featherwing-24-v2]
+extends = arduino_esp32_v2, flash_4mb
+board = featheresp32
+
+build_flags =
+ -D HASP_MODEL="Adafruit HUZZAH32 ESP32 Featherwing 2.4 V2"
+ ${arduino_esp32_v2.build_flags}
+ ${esp32.no_ps_ram}
+
+;region -- TFT_eSPI build options ------------------------
+ ${lcd.featherwing-24-v2}
+ -D TFT_MISO=19
+ -D TFT_MOSI=18
+ -D TFT_SCLK=5
+ -D TFT_DC=33
+ -D TFT_CS=15
+ -D TFT_RST=-1 ; RST
+ -D TFT_BCKL=21 ; Solder the LITE pad to a PWM enabled pin of the ESP, like GPIO 21
+;endregion
+
+lib_deps =
+ ${arduino_esp32_v2.lib_deps}
+ ${tft_espi.lib_deps}
+ ${tsc2007.lib_deps}
\ No newline at end of file
diff --git a/user_setups/esp32/huzzah32-featherwing-35-v2.ini b/user_setups/esp32/huzzah32-featherwing-35-v2.ini
new file mode 100644
index 00000000..8b17d1bf
--- /dev/null
+++ b/user_setups/esp32/huzzah32-featherwing-35-v2.ini
@@ -0,0 +1,32 @@
+;***************************************************;
+; HUZZAH32 ESP32 with Featherwing TFT 3.5" V2 ;
+; - HUZZAH32 esp32 board ;
+; - HX8357D TFT Featherwing 3.5" V2 ;
+; - TSC2007 touch controller ;
+;***************************************************;
+
+[env:huzzah32-featherwing-35-v2]
+extends = arduino_esp32_v2, flash_4mb
+board = featheresp32
+
+build_flags =
+ -D HASP_MODEL="Adafruit HUZZAH32 ESP32 Featherwing 3.5 V2"
+ ${arduino_esp32_v2.build_flags}
+ ${esp32.no_ps_ram}
+
+ -D LV_INDEV_DEF_READ_PERIOD=30
+;region -- TFT_eSPI build options ------------------------
+ ${lcd.featherwing-35-v2}
+ -D TFT_MISO=19
+ -D TFT_MOSI=18
+ -D TFT_SCLK=5
+ -D TFT_DC=10
+ -D TFT_CS=9
+ -D TFT_RST=-1 ; RST
+ -D TFT_BCKL=21 ; Solder the LITE pad to a PWM enabled pin of the ESP, like GPIO 21
+;endregion
+
+lib_deps =
+ ${arduino_esp32_v2.lib_deps}
+ ${tft_espi.lib_deps}
+ ${tsc2007.lib_deps}
diff --git a/user_setups/esp32/huzzah32-v2-featherwing-24-v2.ini b/user_setups/esp32/huzzah32-v2-featherwing-24-v2.ini
new file mode 100644
index 00000000..457dc5aa
--- /dev/null
+++ b/user_setups/esp32/huzzah32-v2-featherwing-24-v2.ini
@@ -0,0 +1,31 @@
+;***************************************************;
+; HUZZAH32 V2 ESP32 with Featherwing TFT 2.4" V2 ;
+; - HUZZAH32 V2 w/ 2 MB PSRAM board ;
+; - ili9341 TFT Featherwing 2.4" V2 ;
+; - TSC2007 touch controller ;
+;***************************************************;
+
+[env:huzzah32-v2-featherwing-24-v2]
+extends = arduino_esp32_v2, flash_4mb
+board = featheresp32
+
+build_flags =
+ -D HASP_MODEL="Adafruit HUZZAH32 V2 ESP32 Featherwing 2.4 V2"
+ ${arduino_esp32_v2.build_flags}
+ ${esp32.ps_ram}
+
+;region -- TFT_eSPI build options ------------------------
+ ${lcd.featherwing-24-v2}
+ -D TFT_MISO=19
+ -D TFT_MOSI=18
+ -D TFT_SCLK=5
+ -D TFT_DC=33
+ -D TFT_CS=15
+ -D TFT_RST=-1 ; RST
+ -D TFT_BCKL=21 ; Solder the LITE pad to a PWM enabled pin of the ESP, like GPIO 21
+;endregion
+
+lib_deps =
+ ${arduino_esp32_v2.lib_deps}
+ ${tft_espi.lib_deps}
+ ${tsc2007.lib_deps}
\ No newline at end of file
diff --git a/user_setups/esp32/huzzah32-v2-featherwing-35-v2.ini b/user_setups/esp32/huzzah32-v2-featherwing-35-v2.ini
new file mode 100644
index 00000000..1cb762f8
--- /dev/null
+++ b/user_setups/esp32/huzzah32-v2-featherwing-35-v2.ini
@@ -0,0 +1,31 @@
+;***************************************************;
+; HUZZAH32 V2 ESP32 with Featherwing TFT 3.5" V2 ;
+; - HUZZAH32 V2 w/ 2 MB PSRAM board ;
+; - HX8357D TFT Featherwing 3.5" V2 ;
+; - TSC2007 touch controller ;
+;***************************************************;
+
+[env:huzzah32-v2-featherwing-35-v2]
+extends = arduino_esp32_v2, flash_4mb
+board = featheresp32
+
+build_flags =
+ -D HASP_MODEL="Adafruit HUZZAH32 V2 ESP32 Featherwing 3.5 V2"
+ ${arduino_esp32_v2.build_flags}
+ ${esp32.ps_ram}
+ -D LV_INDEV_DEF_READ_PERIOD=30
+;region -- TFT_eSPI build options ------------------------
+ ${lcd.featherwing-35-v2}
+ -D TFT_MISO=19
+ -D TFT_MOSI=18
+ -D TFT_SCLK=5
+ -D TFT_DC=10
+ -D TFT_CS=9
+ -D TFT_RST=-1 ; RST
+ -D TFT_BCKL=21 ; Solder the LITE pad to a PWM enabled pin of the ESP, like GPIO 21
+;endregion
+
+lib_deps =
+ ${arduino_esp32_v2.lib_deps}
+ ${tft_espi.lib_deps}
+ ${tsc2007.lib_deps}
diff --git a/user_setups/esp32/esp32-2832s028.ini b/user_setups/esp32/wz2432r028.ini
similarity index 60%
rename from user_setups/esp32/esp32-2832s028.ini
rename to user_setups/esp32/wz2432r028.ini
index c9a96cc8..9e5c0c36 100644
--- a/user_setups/esp32/esp32-2832s028.ini
+++ b/user_setups/esp32/wz2432r028.ini
@@ -1,12 +1,12 @@
;***************************************************;
-; Sunton ESP32-WROOM custom dev board with ;
+; Wizee WZ2432R028 ESP32-WROOM custom dev board ;
; - ILI9341 TFT SPI 4-WIRE ;
; - XPT2046 touch controller ;
;***************************************************;
-[esp32-2432s028r]
-extends = arduino_esp32_v2
-board = esp32dev
+[env:wz2432r028]
+extends = arduino_esp32_v2, flash_4mb
+board = denky32
upload_speed = 921600
build_flags =
@@ -14,39 +14,22 @@ build_flags =
${esp32.no_ps_ram}
;region -- TFT_eSPI build options ------------------------
- ; -D USER_SETUP_LOADED=1
- -D LGFX_USE_V1=1
+ ${esp32.hspi}
+ -D USER_SETUP_LOADED=1
-D ILI9341_DRIVER=1
-D TFT_ROTATION=0 ; 0=0, 1=90, 2=180 or 3=270 degree
-D TFT_WIDTH=240
-D TFT_HEIGHT=320
- -D TFT_RST=-1
- -D TFT_SCLK=14
+
-D TFT_DC=2
-D TFT_CS=15
+ -D TFT_SCLK=14
-D TFT_MOSI=13
-D TFT_MISO=12
- -D TFT_BCKL=21
+ -D TFT_BCKL=27
-D SUPPORT_TRANSACTIONS
- -D SPI_FREQUENCY=55000000
+ -D SPI_FREQUENCY=65000000
-D SPI_READ_FREQUENCY=20000000
- -D TOUCH_OFFSET_ROTATION=0 ; 1=swap xy, 2=invert x, 4=inverty
-
- -D ESP32_2432S028R=1
-;endregion
-
-; -- Debugging options -----------------------------
-; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-
-lib_deps =
- ${arduino_esp32_v2.lib_deps}
- ${lovyangfx.lib_deps}
-
-
-[env:esp32-2432s028r_4MB]
-extends = esp32-2432s028r, flash_4mb
-build_flags =
- ${esp32-2432s028r.build_flags}
-D TOUCH_DRIVER=0x2046 ; XPT2606 Resistive touch panel driver
-D HASP_USE_LGFX_TOUCH=1
-D TOUCH_CS=33
@@ -60,9 +43,6 @@ build_flags =
; -- Debugging options -----------------------------
; -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
-
lib_deps =
- ${esp32-2432s028r.lib_deps}
- ;${tft_espi.lib_deps}
- ${lovyangfx.lib_deps}
- ;${goodix.lib_deps}
+ ${arduino_esp32_v2.lib_deps}
+ ${tft_espi.lib_deps}
diff --git a/user_setups/esp32c3/_esp32c3.ini b/user_setups/esp32c3/_esp32c3.ini
index 2053ab5d..fcf2fbff 100644
--- a/user_setups/esp32c3/_esp32c3.ini
+++ b/user_setups/esp32c3/_esp32c3.ini
@@ -16,7 +16,6 @@ no_ps_ram =
[arduino_esp32c3_v2]
extends = esp32c3
framework = arduino
-;platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.01.01/platform-espressif32.zip
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.07.00/platform-espressif32.zip
-;platform = espressif32@5.3.0
-
+; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.05.01/platform-espressif32.zip
+; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.08.01/platform-espressif32.zip
+platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32.zip
diff --git a/user_setups/esp32s2/_esp32s2.ini b/user_setups/esp32s2/_esp32s2.ini
index 82f1d9df..907a0f06 100644
--- a/user_setups/esp32s2/_esp32s2.ini
+++ b/user_setups/esp32s2/_esp32s2.ini
@@ -5,6 +5,7 @@ board_build.mcu = esp32s2
build_flags =
${env.build_flags}
+ -D HASP_TARGET_ARDUINO=1
-D HTTP_UPLOAD_BUFLEN=512 ; lower http upload buffer
-D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages
-D HASP_CONSOLE_BUFFER=256 ; maximum length of a console/telnet command
@@ -83,7 +84,8 @@ platform = https://github.com/tasmota/platform-espressif32/releases/download/202
[arduino_esp32s2-solo_v2]
framework = arduino
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.01.01/platform-espressif32.zip
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.07.00/platform-espressif32.zip
+; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32.zip
+platform = https://github.com/Jason2866/platform-espressif32/releases/download/2023.10.02/platform-espressif32-2023.10.02.zip
board_build.embed_files = ${esp32.board_build.embed_files}
board_build.filesystem = littlefs
; ----- crash reporter
diff --git a/user_setups/esp32s2/esp32s2-featherwing-24-v2.ini b/user_setups/esp32s2/esp32s2-featherwing-24-v2.ini
new file mode 100644
index 00000000..cb102e00
--- /dev/null
+++ b/user_setups/esp32s2/esp32s2-featherwing-24-v2.ini
@@ -0,0 +1,40 @@
+;***************************************************;
+; Adafruit ESP32-S2 with Featherwing TFT 2.4" V2 ;
+; - ESP32-S2 w/ 2 MB PSRAM board ;
+; - ili9341 TFT Featherwing 2.4" V2 ;
+; - TSC2007 touch controller ;
+;***************************************************;
+
+[env:esp32s2-featherwing-24-v2]
+extends = esp32s2_4mb_v2
+board = esp32s2
+
+build_flags =
+ ${env.build_flags}
+ ${esp32s2.build_flags}
+ ${esp32.ps_ram}
+ -D HASP_MODEL="Adafruit ESP32-S2 Featherwing 2.4 V2"
+ -D USE_HSPI_PORT
+
+;region -- TFT_eSPI build options ------------------------
+ ${lcd.featherwing-24-v2}
+ -D LGFX_USE_V1=1
+ -D TFT_MISO=19
+ -D TFT_MOSI=18
+ -D TFT_SCLK=5
+ -D TFT_DC=33
+ -D TFT_CS=15
+ -D TFT_RST=-1 ; RST
+ -D TFT_BCKL=21 ; Solder the LITE pad to a PWM enabled pin of the ESP, like GPIO 21
+;endregion
+
+lib_deps =
+ ${env.lib_deps}
+ ${esp32s2.lib_deps}
+ ${lovyangfx.lib_deps}
+ ${tsc2007.lib_deps}
+
+lib_ignore =
+ ${env.lib_ignore}
+ ${esp32s2.lib_ignore}
+ TFT_eSPI
diff --git a/user_setups/esp32s2/esp32s2-featherwing-35-v2.ini b/user_setups/esp32s2/esp32s2-featherwing-35-v2.ini
new file mode 100644
index 00000000..b781f449
--- /dev/null
+++ b/user_setups/esp32s2/esp32s2-featherwing-35-v2.ini
@@ -0,0 +1,40 @@
+;***************************************************;
+; Adafruit ESP32-S2 with Featherwing TFT 3.5" V2 ;
+; - ESP32-S2 w/ 2 MB PSRAM board ;
+; - HX8357D TFT Featherwing 3.5" V2 ;
+; - TSC2007 touch controller ;
+;***************************************************;
+
+[env:esp32s2-featherwing-24-v2]
+extends = esp32s2_4mb_v2
+board = esp32s2
+
+build_flags =
+ ${env.build_flags}
+ ${esp32s2.build_flags}
+ ${esp32.ps_ram}
+ -D HASP_MODEL="Adafruit ESP32-S2 Featherwing 3.5 V2"
+ -D USE_HSPI_PORT
+
+;region -- TFT_eSPI build options ------------------------
+ ${lcd.featherwing-35-v2}
+ -D LGFX_USE_V1=1
+ -D TFT_MISO=19
+ -D TFT_MOSI=18
+ -D TFT_SCLK=5
+ -D TFT_DC=10
+ -D TFT_CS=9
+ -D TFT_RST=-1 ; RST
+ -D TFT_BCKL=21 ; Solder the LITE pad to a PWM enabled pin of the ESP, like GPIO 21
+;endregion
+
+lib_deps =
+ ${env.lib_deps}
+ ${esp32s2.lib_deps}
+ ${tsc2007.lib_deps}
+ ${lovyangfx.lib_deps}
+
+lib_ignore =
+ ${env.lib_ignore}
+ ${esp32s2.lib_ignore}
+ TFT_eSPI
diff --git a/user_setups/esp32s3/_esp32s3.ini b/user_setups/esp32s3/_esp32s3.ini
index ec88eb84..13f7a122 100644
--- a/user_setups/esp32s3/_esp32s3.ini
+++ b/user_setups/esp32s3/_esp32s3.ini
@@ -15,7 +15,7 @@ no_ps_ram =
[arduino_esp32s3_v2]
extends = esp32s3
framework = arduino
-;platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.01.01/platform-espressif32.zip
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.07.00/platform-espressif32.zip
-;platform = espressif32@5.3.0
-
+; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.05.01/platform-espressif32.zip
+; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.08.01/platform-espressif32.zip
+; platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32.zip
+platform = https://github.com/Jason2866/platform-espressif32/releases/download/2023.10.02/platform-espressif32-2023.10.02.zip
\ No newline at end of file
diff --git a/user_setups/esp32s3/esp32-s3-4848S040.ini b/user_setups/esp32s3/esp32-s3-4848S040.ini
new file mode 100644
index 00000000..a07a6bb3
--- /dev/null
+++ b/user_setups/esp32s3/esp32-s3-4848S040.ini
@@ -0,0 +1,86 @@
+;***************************************************;
+; Generic Guition with TFT 3.95" ;
+; - Custom esp32-s3 board ;
+; - st7701s TFT ;
+; - gt911 touch controller ;
+;***************************************************;
+
+[esp32-s3-4848s040]
+extends = arduino_esp32s3_v2
+board = esp32-s3-devkitc-1
+board_build.arduino.memory_type = qio_opi
+
+build_flags =
+ -D HASP_MODEL="ESP32-S3 4848S040"
+ ${arduino_esp32s3_v2.build_flags}
+ ${esp32s3.ps_ram}
+ ;-DARDUINO_USB_CDC_ON_BOOT
+ ;-DUSE_USB_CDC_CONSOLE
+
+;region -- ArduinoGFX build options ------------------------
+ -D HASP_USE_ARDUINOGFX=1
+ -D ST7701_DRIVER=1
+ -D ST7701_4848S040=1
+ -D TFT_WIDTH=480
+ -D TFT_HEIGHT=480
+ ; Bus Settings
+ -D TFT_CS=39
+ -D TFT_SCLK=48
+ -D TFT_MOSI=47
+ -D TFT_DE=18
+ -D TFT_VSYNC=17
+ -D TFT_HSYNC=16
+ -D TFT_PCLK=21
+ -D TFT_R0=11
+ -D TFT_R1=12
+ -D TFT_R2=13
+ -D TFT_R3=14
+ -D TFT_R4=0
+ -D TFT_G0=8
+ -D TFT_G1=20
+ -D TFT_G2=3
+ -D TFT_G3=46
+ -D TFT_G4=9
+ -D TFT_G5=10
+ -D TFT_B0=4
+ -D TFT_B1=5
+ -D TFT_B2=6
+ -D TFT_B3=7
+ -D TFT_B4=15
+ -D TFT_DC=-1
+ -D TFT_MISO=-1
+ -D TFT_RST=-1
+ -D TFT_BUSY=-1
+ -D TFT_BCKL=38
+ ; Panel Settings
+ -D TFT_HSYNC_POLARITY=1
+ -D TFT_HSYNC_FRONT_PORCH=10
+ -D TFT_HSYNC_PULSE_WIDTH=8
+ -D TFT_HSYNC_BACK_PORCH=50
+ -D TFT_VSYNC_POLARITY=1
+ -D TFT_VSYNC_FRONT_PORCH=10
+ -D TFT_VSYNC_PULSE_WIDTH=8
+ -D TFT_VSYNC_BACK_PORCH=20
+ -D TFT_PCLK_ACTIVE_NEG=1
+ -D TFT_PREFER_SPEED=12000000
+ -D TFT_AUTO_FLUSH=1
+ ; Touch Settings
+ -D TOUCH_DRIVER=0x911
+ -D TOUCH_WIDTH=480
+ -D TOUCH_HEIGHT=480
+ -D TOUCH_SDA=19
+ -D TOUCH_SCL=45
+ -D TOUCH_RST=-1
+ -D TOUCH_IRQ=-1
+ -D I2C_TOUCH_FREQUENCY=400000
+ -D I2C_TOUCH_ADDRESS=0x5D ; or 0x14
+ -D I2C_TOUCH_PORT=1
+;endregion
+
+lib_deps =
+ ${arduino_esp32s3_v2.lib_deps}
+ ${arduinogfx.lib_deps}
+ ${goodix.lib_deps}
+
+[env:esp32-s3-4848s040_16MB]
+extends = esp32-s3-4848s040, flash_16mb
\ No newline at end of file
diff --git a/user_setups/esp32s3/sunton-esp32-s3-tft.ini b/user_setups/esp32s3/sunton-esp32-s3-tft.ini
index 7cbb14d8..f9bbe24c 100644
--- a/user_setups/esp32s3/sunton-esp32-s3-tft.ini
+++ b/user_setups/esp32s3/sunton-esp32-s3-tft.ini
@@ -228,15 +228,15 @@ build_flags =
-D TFT_B4=4
; Panel Settings
-D TFT_HSYNC_POLARITY=0
- -D TFT_HSYNC_FRONT_PORCH=240 ; Maximum HSYNC Front Porch
- -D TFT_HSYNC_PULSE_WIDTH=30 ; Typical HSYNC Pulse Width
- -D TFT_HSYNC_BACK_PORCH=16 ; Typical HSYNC Back Porch
+ -D TFT_HSYNC_FRONT_PORCH=8 ; Maximum HSYNC Front Porch / 8 GOOD
+ -D TFT_HSYNC_PULSE_WIDTH=10 ; Typical HSYNC Pulse Width / 10 GOOD
+ -D TFT_HSYNC_BACK_PORCH=43 ; Typical HSYNC Back Porch / 43 GOOD
-D TFT_VSYNC_POLARITY=0
- -D TFT_VSYNC_FRONT_PORCH=32 ; Maximum VSYNC Front Porch
- -D TFT_VSYNC_PULSE_WIDTH=13 ; Typical VSYNC Pulse Width
- -D TFT_VSYNC_BACK_PORCH=10 ; Typical VSYNC Back Porch
+ -D TFT_VSYNC_FRONT_PORCH=8 ; Maximum VSYNC Front Porch / 8 GOOD
+ -D TFT_VSYNC_PULSE_WIDTH=8 ; Typical VSYNC Pulse Width / 8 GOOD
+ -D TFT_VSYNC_BACK_PORCH=12 ; Typical VSYNC Back Porch / 12 GOOD
-D TFT_PCLK_ACTIVE_NEG=1
- -D TFT_PREFER_SPEED=16000000 ; 1/2 of Typical DCLK Frequency
+ -D TFT_PREFER_SPEED=14500000 ; 1/2 of Typical DCLK Frequency / 12000000 GOOD
-D TFT_AUTO_FLUSH=1
; Touch Settings
-D TOUCH_WIDTH=800
@@ -250,4 +250,4 @@ build_flags =
-D I2C_TOUCH_FREQUENCY=400000
lib_deps =
${sunton-esp32-s3-tft.lib_deps}
- ${goodix.lib_deps}
\ No newline at end of file
+ ${goodix.lib_deps}
diff --git a/user_setups/esp8266/_esp8266.ini b/user_setups/esp8266/_esp8266.ini
index ad231166..e9ffe212 100644
--- a/user_setups/esp8266/_esp8266.ini
+++ b/user_setups/esp8266/_esp8266.ini
@@ -12,6 +12,7 @@ board_build.f_cpu = 160000000L ; set frequency to 160MHz
monitor_filters = esp8266_exception_decoder
build_flags=
+ -D HASP_TARGET_ARDUINO=1
-D HTTP_UPLOAD_BUFLEN=512 ; lower http upload buffer
-D MQTT_MAX_PACKET_SIZE=1024 ; longer PubSubClient messages
-D HASP_CONSOLE_BUFFER=160 ; maximum length of a console/telnet command
diff --git a/user_setups/lcd_config.ini b/user_setups/lcd_config.ini
index ce4e272b..8b5df106 100644
--- a/user_setups/lcd_config.ini
+++ b/user_setups/lcd_config.ini
@@ -122,6 +122,18 @@ featherwing-35 =
-D TOUCH_DRIVER=0x0610 ;STMPE610
;-D SUPPORT_TRANSACTIONS ; Default on ESP32
+featherwing-35-v2 =
+ -D HX8357D_DRIVER=1
+ -D TFT_WIDTH=320
+ -D TFT_HEIGHT=480
+ -D TFT_ROTATION=0 ; Use default, see TFT_ROTATION values
+ -D SPI_FREQUENCY=27000000
+ -D SPI_TOUCH_FREQUENCY=2500000
+ -D SPI_READ_FREQUENCY=20000000
+ -D USER_SETUP_LOADED=1
+ -D TOUCH_DRIVER=0x2007 ;TSC2007
+ ;-D SUPPORT_TRANSACTIONS ; Default on ESP32
+
featherwing-24 =
-D ILI9341_DRIVER=1
-D TFT_WIDTH=240
@@ -132,4 +144,15 @@ featherwing-24 =
-D SPI_READ_FREQUENCY=20000000
-D USER_SETUP_LOADED=1
-D TOUCH_DRIVER=0x0610 ;STMPE610
+ ;-D SUPPORT_TRANSACTIONS ; Default on ESP32
+
+featherwing-24-v2 =
+ -D ILI9341_DRIVER=1
+ -D TFT_WIDTH=240
+ -D TFT_HEIGHT=320
+ -D TFT_ROTATION=0 ; Use default, see TFT_ROTATION values
+ -D SPI_FREQUENCY=27000000
+ -D SPI_READ_FREQUENCY=20000000
+ -D USER_SETUP_LOADED=1
+ -D TOUCH_DRIVER=0x2007 ;TSC2007
;-D SUPPORT_TRANSACTIONS ; Default on ESP32
\ No newline at end of file
diff --git a/user_setups/linux/linux_fbdev.ini b/user_setups/linux/linux_fbdev.ini
new file mode 100644
index 00000000..1927c7ab
--- /dev/null
+++ b/user_setups/linux/linux_fbdev.ini
@@ -0,0 +1,101 @@
+[env:linux_fbdev]
+platform = native@^1.1.4
+extra_scripts =
+ tools/linux_build_extra.py
+build_flags =
+ ${env.build_flags}
+ -D HASP_MODEL="Linux App"
+ -D HASP_TARGET_PC=1
+
+ ; ----- Monitor
+ -D TFT_WIDTH=240
+ -D TFT_HEIGHT=320
+ ; SDL drivers options
+ ;-D LV_LVGL_H_INCLUDE_SIMPLE
+ ;-D LV_DRV_NO_CONF
+ -D USE_FBDEV
+ -D USE_EVDEV
+ ; ----- ArduinoJson
+ -D ARDUINOJSON_DECODE_UNICODE=1
+ -D HASP_NUM_PAGES=12
+ -D HASP_USE_SPIFFS=0
+ -D HASP_USE_LITTLEFS=0
+ -D LV_USE_FS_IF=1
+ -D HASP_USE_EEPROM=0
+ -D HASP_USE_GPIO=0
+ -D HASP_USE_CONFIG=1
+ -D HASP_USE_DEBUG=1
+ -D HASP_USE_PNGDECODE=1
+ -D HASP_USE_BMPDECODE=1
+ -D HASP_USE_GIFDECODE=0
+ -D HASP_USE_JPGDECODE=0
+ -D HASP_USE_MQTT=1
+ -D HASP_USE_LVGL_TASK=1
+ -D MQTT_MAX_PACKET_SIZE=2048
+ -D HASP_ATTRIBUTE_FAST_MEM=
+ -D IRAM_ATTR= ; No IRAM_ATTR available
+ -D PROGMEM= ; No PROGMEM available
+ ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO
+ ;-D LV_LOG_PRINTF=1
+ ; Add recursive dirs for hal headers search
+ -D POSIX
+ -D PAHO_MQTT_STATIC
+ -DPAHO_WITH_SSL=TRUE
+ -DPAHO_BUILD_DOCUMENTATION=FALSE
+ -DPAHO_BUILD_SAMPLES=FALSE
+ -DCMAKE_BUILD_TYPE=Release
+ -DCMAKE_VERBOSE_MAKEFILE=TRUE
+ ;-D NO_PERSISTENCE
+ -I.pio/libdeps/linux_fbdev/paho/src
+ -I.pio/libdeps/linux_fbdev/ArduinoJson/src
+
+ ; ----- Statically linked libraries --------------------
+ -lm
+ -lpthread
+
+lib_deps =
+ ${env.lib_deps}
+ ;lv_drivers@~7.9.0
+ ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip
+ https://github.com/eclipse/paho.mqtt.c.git
+ bblanchon/ArduinoJson@^6.21.5 ; Json(l) parser
+ https://github.com/fvanroie/lv_drivers
+
+lib_ignore =
+ paho
+ AXP192
+ ArduinoLog
+ lv_lib_qrcode
+ ETHSPI
+
+build_src_filter =
+ +<*>
+ -<*.h>
+ +<../.pio/libdeps/linux_fbdev/paho/src/*.c>
+ -<../.pio/libdeps/linux_fbdev/paho/src/MQTTClient.c>
+ +<../.pio/libdeps/linux_fbdev/paho/src/MQTTAsync.c>
+ +<../.pio/libdeps/linux_fbdev/paho/src/MQTTAsyncUtils.c>
+ -<../.pio/libdeps/linux_fbdev/paho/src/MQTTVersion.c>
+ -<../.pio/libdeps/linux_fbdev/paho/src/SSLSocket.c>
+ -
+ +
+ +
+ -
+ -
+ -
+ +
+ +
+ -
+ +
+ -
+ +
+ +
+ -
+ -
+ -
+ +
+ +
+ +
+ -
+ +
+ +<../.pio/libdeps/linux_fbdev/ArduinoJson/src/ArduinoJson.h>
diff --git a/user_setups/linux_sdl/linux_sdl_64bits.ini b/user_setups/linux/linux_sdl.ini
similarity index 72%
rename from user_setups/linux_sdl/linux_sdl_64bits.ini
rename to user_setups/linux/linux_sdl.ini
index e49d3447..2445b8b0 100644
--- a/user_setups/linux_sdl/linux_sdl_64bits.ini
+++ b/user_setups/linux/linux_sdl.ini
@@ -1,4 +1,4 @@
-[env:linux_sdl_64bits]
+[env:linux_sdl]
platform = native@^1.1.4
extra_scripts =
tools/sdl2_build_extra.py
@@ -6,6 +6,7 @@ extra_scripts =
build_flags =
${env.build_flags}
-D HASP_MODEL="Linux App"
+ -D HASP_TARGET_PC=1
; ----- Monitor
-D TFT_WIDTH=240
@@ -25,8 +26,8 @@ build_flags =
-D HASP_USE_LITTLEFS=0
-D LV_USE_FS_IF=1
-D HASP_USE_EEPROM=0
- -D HASP_USE_GPIO=1
- -D HASP_USE_CONFIG=0 ; Standalone application, as library
+ -D HASP_USE_GPIO=0
+ -D HASP_USE_CONFIG=1
-D HASP_USE_DEBUG=1
-D HASP_USE_PNGDECODE=1
-D HASP_USE_BMPDECODE=1
@@ -48,8 +49,8 @@ build_flags =
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_VERBOSE_MAKEFILE=TRUE
;-D NO_PERSISTENCE
- -I.pio/libdeps/linux_sdl_64bits/paho/src
- -I.pio/libdeps/linux_sdl_64bits/ArduinoJson/src
+ -I.pio/libdeps/linux_sdl/paho/src
+ -I.pio/libdeps/linux_sdl/ArduinoJson/src
!python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))"
; ----- Statically linked libraries --------------------
@@ -62,7 +63,7 @@ lib_deps =
;lv_drivers@~7.9.0
;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip
https://github.com/eclipse/paho.mqtt.c.git
- bblanchon/ArduinoJson@^6.21.3 ; Json(l) parser
+ bblanchon/ArduinoJson@^6.21.5 ; Json(l) parser
https://github.com/fvanroie/lv_drivers
lib_ignore =
@@ -75,20 +76,20 @@ lib_ignore =
build_src_filter =
+<*>
-<*.h>
- +<../hal/sdl2>
- +<../.pio/libdeps/linux_sdl_64bits/paho/src/*.c>
- +<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTClient.c>
- -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsync.c>
- -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTAsyncUtils.c>
- -<../.pio/libdeps/linux_sdl_64bits/paho/src/MQTTVersion.c>
- -<../.pio/libdeps/linux_sdl_64bits/paho/src/SSLSocket.c>
- +
- -
- -
+ +<../.pio/libdeps/linux_sdl/paho/src/*.c>
+ -<../.pio/libdeps/linux_sdl/paho/src/MQTTClient.c>
+ +<../.pio/libdeps/linux_sdl/paho/src/MQTTAsync.c>
+ +<../.pio/libdeps/linux_sdl/paho/src/MQTTAsyncUtils.c>
+ -<../.pio/libdeps/linux_sdl/paho/src/MQTTVersion.c>
+ -<../.pio/libdeps/linux_sdl/paho/src/SSLSocket.c>
+ -
+ +
+ +
-
-
-
+
+ +
-
+
-
@@ -102,4 +103,4 @@ build_src_filter =
+
-
+
- +<../.pio/libdeps/linux_sdl_64bits/ArduinoJson/src/ArduinoJson.h>
+ +<../.pio/libdeps/linux_sdl/ArduinoJson/src/ArduinoJson.h>
diff --git a/user_setups/stm32f4xx/_stm32f4.ini b/user_setups/stm32f4xx/_stm32f4.ini
index 20a755d3..7ec27e01 100644
--- a/user_setups/stm32f4xx/_stm32f4.ini
+++ b/user_setups/stm32f4xx/_stm32f4.ini
@@ -3,6 +3,7 @@
framework = arduino
platform = ststm32
build_flags=
+ -D HASP_TARGET_ARDUINO=1
-I include/stm32f4
-D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages
-D HASP_CONSOLE_BUFFER=220 ; maximum length of a console/telnet command
@@ -21,4 +22,4 @@ build_flags=
lib_deps =
stm32duino/STM32duino LwIP @ ^2.1.2
- ;https://github.com/stm32duino/LwIP.git
\ No newline at end of file
+ ;https://github.com/stm32duino/LwIP.git
diff --git a/user_setups/stm32f7xx/_stm32f7.ini b/user_setups/stm32f7xx/_stm32f7.ini
index 192119d5..17fa84a6 100644
--- a/user_setups/stm32f7xx/_stm32f7.ini
+++ b/user_setups/stm32f7xx/_stm32f7.ini
@@ -3,6 +3,7 @@
framework = arduino
platform = ststm32
build_flags=
+ -D HASP_TARGET_ARDUINO=1
; -I include/stm32f4
-D MQTT_MAX_PACKET_SIZE=2048 ; longer PubSubClient messages
-D HASP_CONSOLE_BUFFER=220 ; maximum length of a console/telnet command
diff --git a/user_setups/win32/windows_gdi.ini b/user_setups/win32/windows_gdi.ini
new file mode 100644
index 00000000..c887ffd8
--- /dev/null
+++ b/user_setups/win32/windows_gdi.ini
@@ -0,0 +1,131 @@
+[env:windows_gdi]
+platform = native@^1.1.4
+extra_scripts =
+ tools/windows_build_extra.py
+build_flags =
+ ${env.build_flags}
+ -D HASP_MODEL="Windows App"
+ -D HASP_TARGET_PC=1
+
+ ; ----- Monitor
+ -D TFT_WIDTH=240
+ -D TFT_HEIGHT=320
+ ; SDL drivers options
+ ;-D LV_LVGL_H_INCLUDE_SIMPLE
+ ;-D LV_DRV_NO_CONF
+ -D USE_WIN32DRV
+ ; ----- ArduinoJson
+ -D ARDUINOJSON_DECODE_UNICODE=1
+ -D HASP_NUM_PAGES=12
+ -D HASP_USE_SPIFFS=0
+ -D HASP_USE_LITTLEFS=0
+ -D HASP_USE_EEPROM=0
+ -D HASP_USE_GPIO=0
+ -D HASP_USE_CONFIG=1
+ -D HASP_USE_DEBUG=1
+ -D HASP_USE_PNGDECODE=1
+ -D HASP_USE_BMPDECODE=1
+ -D HASP_USE_GIFDECODE=0
+ -D HASP_USE_JPGDECODE=0
+ -D HASP_USE_MQTT=1
+ -D HASP_USE_SYSLOG=0
+ -D HASP_USE_LVGL_TASK=1
+ -D MQTT_MAX_PACKET_SIZE=2048
+ -D HASP_ATTRIBUTE_FAST_MEM=
+ -D IRAM_ATTR= ; No IRAM_ATTR available
+ -D PROGMEM= ; No PROGMEM available
+
+ ; -- FreeType build options ------------------------
+ -D LV_USE_FT_CACHE_MANAGER=1 ; crashes without cache
+ -D LVGL_FREETYPE_MAX_FACES=64 ; max number of FreeType faces in cache
+ -D LVGL_FREETYPE_MAX_SIZES=4 ; max number of sizes in cache
+ -D LVGL_FREETYPE_MAX_BYTES=16384 ; max bytes in cache
+ -D LVGL_FREETYPE_MAX_BYTES_PSRAM=65536 ; max bytes in cache when using PSRAM
+
+ ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO
+ ;-D LV_LOG_PRINTF=1
+ ; Add recursive dirs for hal headers search
+ -D _WIN64
+ -D WINDOWS ; We add this ourselves for code branching in hasp
+ -D WIN32_LEAN_AND_MEAN ; exclude a bunch of Windows header files from windows.h
+ -D PAHO_MQTT_STATIC
+ -DPAHO_WITH_SSL=TRUE
+ -DPAHO_BUILD_DOCUMENTATION=FALSE
+ -DPAHO_BUILD_SAMPLES=FALSE
+ -DCMAKE_BUILD_TYPE=Release
+ -DCMAKE_VERBOSE_MAKEFILE=TRUE
+ ;-D NO_PERSISTENCE
+ -I.pio/libdeps/windows_gdi/paho/src
+ -I.pio/libdeps/windows_gdi/ArduinoJson/src
+ -I lib/lv_fs_if
+ -I lib/lv_datetime
+ -mconsole
+ ; ----- Statically linked libraries --------------------
+ -l"ws2_32" ;windsock2
+ -lrpcrt4
+ -lcrypt32
+ -lmingw32
+ -lm
+ -ldinput8
+ ;-ldxguid
+ ;-ldxerr8
+ ;-luser32
+ -lgdi32
+ -lwinmm
+ -limm32
+ -lole32
+ -loleaut32
+ ;-lshell32
+ -lversion
+ ;-luuid
+ -lsetupapi
+ -lshlwapi
+ ;-lhid
+
+lib_deps =
+ ${env.lib_deps}
+ ;lv_drivers@~7.9.0
+ ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip
+ https://github.com/eclipse/paho.mqtt.c.git
+ bblanchon/ArduinoJson@^6.21.5 ; Json(l) parser
+ https://github.com/fvanroie/lv_drivers
+
+lib_ignore =
+ paho
+ AXP192
+ ArduinoLog
+ lv_lib_qrcode
+ ETHSPI
+
+build_src_filter =
+ +<*>
+ -<*.h>
+ +<../.pio/libdeps/windows_gdi/paho/src/*.c>
+ -<../.pio/libdeps/windows_gdi/paho/src/MQTTClient.c>
+ +<../.pio/libdeps/windows_gdi/paho/src/MQTTAsync.c>
+ +<../.pio/libdeps/windows_gdi/paho/src/MQTTAsyncUtils.c>
+ -<../.pio/libdeps/windows_gdi/paho/src/MQTTVersion.c>
+ -<../.pio/libdeps/windows_gdi/paho/src/SSLSocket.c>
+ -
+ +
+ +
+ -
+ -
+ -
+ +
+ +
+ -
+ +
+ -
+ +
+ +
+ -
+ -
+ -
+ +
+ +
+ +
+ -
+ +
+ +<../.pio/libdeps/windows_gdi/ArduinoJson/src/ArduinoJson.h>
+ +
diff --git a/user_setups/win32/windows_sdl.ini b/user_setups/win32/windows_sdl.ini
new file mode 100644
index 00000000..dfaa7c96
--- /dev/null
+++ b/user_setups/win32/windows_sdl.ini
@@ -0,0 +1,137 @@
+[env:windows_sdl]
+platform = native@^1.1.4
+extra_scripts =
+ tools/sdl2_build_extra.py
+ tools/windows_build_extra.py
+build_flags =
+ ${env.build_flags}
+ -D HASP_MODEL="Windows App"
+ -D HASP_TARGET_PC=1
+
+ ; ----- Monitor
+ -D TFT_WIDTH=240
+ -D TFT_HEIGHT=320
+ ; SDL drivers options
+ ;-D LV_LVGL_H_INCLUDE_SIMPLE
+ ;-D LV_DRV_NO_CONF
+ -D USE_MONITOR
+ -D MONITOR_ZOOM=1 ; can be fractional like 1.5 or 2
+ -D USE_MOUSE
+ -D USE_MOUSEWHEEL
+ -D USE_KEYBOARD
+ ; ----- ArduinoJson
+ -D ARDUINOJSON_DECODE_UNICODE=1
+ -D HASP_NUM_PAGES=12
+ -D HASP_USE_SPIFFS=0
+ -D HASP_USE_LITTLEFS=0
+ -D HASP_USE_EEPROM=0
+ -D HASP_USE_GPIO=0
+ -D HASP_USE_CONFIG=1
+ -D HASP_USE_DEBUG=1
+ -D HASP_USE_PNGDECODE=1
+ -D HASP_USE_BMPDECODE=1
+ -D HASP_USE_GIFDECODE=0
+ -D HASP_USE_JPGDECODE=0
+ -D HASP_USE_MQTT=1
+ -D HASP_USE_SYSLOG=0
+ -D MQTT_MAX_PACKET_SIZE=2048
+ -D HASP_ATTRIBUTE_FAST_MEM=
+ -D IRAM_ATTR= ; No IRAM_ATTR available
+ -D PROGMEM= ; No PROGMEM available
+
+ ; -- FreeType build options ------------------------
+ -D LV_USE_FT_CACHE_MANAGER=1 ; crashes without cache
+ -D LVGL_FREETYPE_MAX_FACES=64 ; max number of FreeType faces in cache
+ -D LVGL_FREETYPE_MAX_SIZES=4 ; max number of sizes in cache
+ -D LVGL_FREETYPE_MAX_BYTES=16384 ; max bytes in cache
+ -D LVGL_FREETYPE_MAX_BYTES_PSRAM=65536 ; max bytes in cache when using PSRAM
+
+ ;-D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO
+ ;-D LV_LOG_PRINTF=1
+ ; Add recursive dirs for hal headers search
+ -D _WIN64
+ -D WINDOWS ; We add this ourselves for code branching in hasp
+ -D WIN32_LEAN_AND_MEAN ; exclude a bunch of Windows header files from windows.h
+ -D PAHO_MQTT_STATIC
+ -DPAHO_WITH_SSL=TRUE
+ -DPAHO_BUILD_DOCUMENTATION=FALSE
+ -DPAHO_BUILD_SAMPLES=FALSE
+ -DCMAKE_BUILD_TYPE=Release
+ -DCMAKE_VERBOSE_MAKEFILE=TRUE
+ ;-D NO_PERSISTENCE
+ -I.pio/libdeps/windows_sdl/paho/src
+ -I.pio/libdeps/windows_sdl/ArduinoJson/src
+ -I lib/lv_fs_if
+ -I lib/lv_datetime
+ !python -c "import os; print(' '.join(['-I {}'.format(i[0].replace('\x5C','/')) for i in os.walk('hal/sdl2')]))"
+ -mconsole
+ ; ----- Statically linked libraries --------------------
+ -l"ws2_32" ;windsock2
+ -lrpcrt4
+ -lcrypt32
+ -lmingw32
+ -lSDL2main
+ -lSDL2
+ -lm
+ -ldinput8
+ ;-ldxguid
+ ;-ldxerr8
+ ;-luser32
+ -lgdi32
+ -lwinmm
+ -limm32
+ -lole32
+ -loleaut32
+ ;-lshell32
+ -lversion
+ ;-luuid
+ -lsetupapi
+ ;-lhid
+
+lib_deps =
+ ${env.lib_deps}
+ ;lv_drivers@~7.9.0
+ ;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip
+ https://github.com/eclipse/paho.mqtt.c.git
+ bblanchon/ArduinoJson@^6.21.5 ; Json(l) parser
+ https://github.com/fvanroie/lv_drivers
+
+lib_ignore =
+ paho
+ AXP192
+ ArduinoLog
+ lv_lib_qrcode
+ ETHSPI
+
+build_src_filter =
+ +<*>
+ -<*.h>
+ +<../.pio/libdeps/windows_sdl/paho/src/*.c>
+ -<../.pio/libdeps/windows_sdl/paho/src/MQTTClient.c>
+ +<../.pio/libdeps/windows_sdl/paho/src/MQTTAsync.c>
+ +<../.pio/libdeps/windows_sdl/paho/src/MQTTAsyncUtils.c>
+ -<../.pio/libdeps/windows_sdl/paho/src/MQTTVersion.c>
+ -<../.pio/libdeps/windows_sdl/paho/src/SSLSocket.c>
+ -
+ +
+ +
+ -
+ -
+ -
+ +
+ +
+ -
+ +
+ -
+ +
+ +
+ -
+ -
+ -
+ +
+ +
+ +
+ -
+ +
+ +<../.pio/libdeps/windows_sdl/ArduinoJson/src/ArduinoJson.h>
+ +
diff --git a/user_setups/win32/windows_sdl_64bits.ini b/user_setups/win32/windows_sdl_64bits.ini
index 9bc1f7c7..b51ecfb4 100644
--- a/user_setups/win32/windows_sdl_64bits.ini
+++ b/user_setups/win32/windows_sdl_64bits.ini
@@ -93,7 +93,7 @@ lib_deps =
;lv_drivers@~7.9.0
;lv_drivers=https://github.com/littlevgl/lv_drivers/archive/7d71907c1d6b02797d066f50984b866e080ebeed.zip
https://github.com/eclipse/paho.mqtt.c.git
- bblanchon/ArduinoJson@^6.21.3 ; Json(l) parser
+ bblanchon/ArduinoJson@^6.21.5 ; Json(l) parser
https://github.com/fvanroie/lv_drivers
lib_ignore =