26 Commits

Author SHA1 Message Date
Proddy
b320d8ded2 Merge pull request #2963 from MichaelDvP/core3
Core3 network fixes
2026-02-16 18:12:33 +01:00
MichaelDvP
0be1b20996 statemachine for network connection replaces onEvent 2026-02-16 10:37:28 +01:00
MichaelDvP
6c55460622 Merge branch 'dev' into core3 2026-02-16 08:34:23 +01:00
MichaelDvP
421da246ed fix SRC seltemp offset for auto mode #2960 2026-02-16 07:51:10 +01:00
MichaelDvP
d627404dc2 skip onEvent for AP, MQTT, NTP 2026-02-16 07:47:13 +01:00
MichaelDvP
148a721e17 read connect seltemp after mode/icon to create HA-climate 2026-02-15 16:49:21 +01:00
proddy
f317123c26 fix standalone 2026-02-15 15:27:11 +01:00
proddy
e4df1887b0 remove 2026-02-15 14:16:55 +01:00
proddy
34142c3e85 use Tasmota everywhere 2026-02-15 14:16:50 +01:00
proddy
6e7f8bdf02 add -DNO_TLS_SUPPORT 2026-02-15 14:16:27 +01:00
proddy
3dd9fcfb58 update 2026-02-15 14:16:04 +01:00
proddy
35e2954b8b fix lint errors 2026-02-15 14:15:55 +01:00
proddy
59aa63db0f package update 2026-02-15 14:15:43 +01:00
proddy
7a41a190f8 support s3 2026-02-15 14:15:13 +01:00
proddy
6741232450 WIP: ESP-IDF Core 3 migration - mbedtls SSL, module library, board configs, MQTT and network updates 2026-02-15 13:53:13 +01:00
MichaelDvP
a811670c5a 3.8.2-dev.6, changelog 2026-02-15 12:03:33 +01:00
MichaelDvP
72f08a86cf fix SRC climate, #2960 2026-02-15 12:03:07 +01:00
MichaelDvP
27c471f45f set model for ems-esp devices, #2958 2026-02-15 12:02:36 +01:00
MichaelDvP
e303972d26 update AsyncWebserver and pkg 2026-02-15 12:01:50 +01:00
MichaelDvP
97bb03d703 add missing check for number mode change 2026-02-15 12:01:10 +01:00
Proddy
e9f77c1bde Merge pull request #2954 from MichaelDvP/dev
fix brand in HA
2026-02-12 17:54:41 +01:00
MichaelDvP
81cba6c0a8 fix brand in HA 2026-02-12 17:41:10 +01:00
Proddy
89029df25e Merge pull request #2953 from MichaelDvP/dev
customize device brand #2784
2026-02-12 13:19:46 +01:00
MichaelDvP
3463b6818d update testdata 2026-02-12 12:14:13 +01:00
MichaelDvP
349843e666 Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev 2026-02-12 12:02:45 +01:00
MichaelDvP
96ae3bbbba customze device brand #2784 2026-02-12 12:01:39 +01:00
78 changed files with 30395 additions and 663 deletions

View File

@@ -7,10 +7,12 @@ For more details go to [emsesp.org](https://emsesp.org/).
## Added
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
## Fixed
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936)
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
## Changed

View File

@@ -63,8 +63,9 @@ CXX_STANDARD := -std=gnu++17
#----------------------------------------------------------------------
# Defined Symbols
#----------------------------------------------------------------------
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
DEFINES += -DARDUINOJSON_ENABLE -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
DEFINES += -DEMSESP_STANDALONE -DEMSESP_TEST -DEMSESP_DEBUG -DEMC_RX_BUFFER_SIZE=1500
DEFINES += -DNO_TLS_SUPPORT
DEFINES += $(ARGS)
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32S3\"
@@ -79,6 +80,10 @@ SYMBOLS := $(CURDIR)/$(BUILD)/$(TARGET).out
CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null)
CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null)
# Exclude files not needed for standalone build, if they exist
CSOURCES := $(filter-out src/core/ModuleLibrary.c,$(CSOURCES))
CXXSOURCES := $(filter-out src/core/ModuleLibrary.cpp,$(CXXSOURCES))
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))

View File

@@ -5,7 +5,7 @@
},
"core": "esp32",
"extra_flags": [
"-DTASMOTA_SDK",
"-DNO_TLS_SUPPORT",
"-DARDUINO_LOLIN_C3_MINI",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_CDC_ON_BOOT=1"

View File

@@ -6,7 +6,7 @@
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DTASMOTA_SDK",
"-DNO_TLS_SUPPORT",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0"
],

View File

@@ -21,7 +21,7 @@
"arduino",
"espidf"
],
"name": "Espressif ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
"name": "Tasmota ESP32-S3 32M Flash OPI PSRAM, 4608KB Code/OTA, 2MB FS",
"upload": {
"flash_size": "32MB",
"maximum_ram_size": 327680,

View File

@@ -1,7 +1,7 @@
{
"build": {
"core": "esp32",
"extra_flags": "-DTASMOTA_SDK",
"extra_flags": "-DNO_TLS_SUPPORT",
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
@@ -19,7 +19,7 @@
"arduino",
"espidf"
],
"name": "Espressif ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
"name": "Tasmota ESP32 16M Flash, 4608KB Code/OTA, 2MB FS",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,

View File

@@ -19,7 +19,7 @@
"arduino",
"espidf"
],
"name": "Espressif ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
"name": "Tasmota ESP32 16M Flash DIO PSRAM, 4608KB Code/OTA, 2MB FS",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,

View File

@@ -1,7 +1,7 @@
{
"build": {
"core": "esp32",
"extra_flags": "-DTASMOTA_SDK",
"extra_flags": "-DNO_TLS_SUPPORT",
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",

View File

@@ -38,6 +38,7 @@
"vite.config.ts",
"lib/esp32-psram/**",
"test/test_api/test_api.h",
"lib_standalone/**"
"lib_standalone/**",
"lib/mbedtls_ssl/**"
]
}

View File

@@ -1,5 +1,5 @@
{
"adapter": "react",
"baseLocale": "pl",
"$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json"
"$schema": "https://unpkg.com/typesafe-i18n@5.27.1/schema/typesafe-i18n.json"
}

View File

@@ -26,8 +26,8 @@
"@alova/adapter-xhr": "2.3.1",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^7.3.7",
"@mui/material": "^7.3.7",
"@mui/icons-material": "^7.3.8",
"@mui/material": "^7.3.8",
"@preact/compat": "^18.3.1",
"@table-library/react-table-library": "4.1.15",
"alova": "3.5.0",
@@ -43,7 +43,7 @@
"react-icons": "^5.5.0",
"react-router": "^7.13.0",
"react-toastify": "^11.0.5",
"typesafe-i18n": "^5.26.2",
"typesafe-i18n": "^5.27.1",
"typescript": "^5.9.3"
},
"devDependencies": {
@@ -52,8 +52,8 @@
"@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.10.3",
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/node": "^25.2.2",
"@types/react": "^19.2.13",
"@types/node": "^25.2.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"axe-core": "^4.11.1",
"concurrently": "^9.2.1",
@@ -62,10 +62,10 @@
"prettier": "^3.8.1",
"rollup-plugin-visualizer": "^6.0.5",
"terser": "^5.46.0",
"typescript-eslint": "^8.54.0",
"typescript-eslint": "^8.55.0",
"vite": "^7.3.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^6.1.0"
"vite-tsconfig-paths": "^6.1.1"
},
"packageManager": "pnpm@10.29.2"
"packageManager": "pnpm@10.29.3+sha512.498e1fb4cca5aa06c1dcf2611e6fafc50972ffe7189998c409e90de74566444298ffe43e6cd2acdc775ba1aa7cc5e092a8b7054c811ba8c5770f84693d33d2dc"
}

410
interface/pnpm-lock.yaml generated
View File

@@ -13,22 +13,22 @@ importers:
version: 2.3.1(alova@3.5.0)
'@emotion/react':
specifier: ^11.14.0
version: 11.14.0(@types/react@19.2.13)(react@19.2.4)
version: 11.14.0(@types/react@19.2.14)(react@19.2.4)
'@emotion/styled':
specifier: ^11.14.1
version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)
version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
'@mui/icons-material':
specifier: ^7.3.7
version: 7.3.7(@mui/material@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)
specifier: ^7.3.8
version: 7.3.8(@mui/material@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
'@mui/material':
specifier: ^7.3.7
version: 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
specifier: ^7.3.8
version: 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@preact/compat':
specifier: ^18.3.1
version: 18.3.1(preact@10.28.3)
'@table-library/react-table-library':
specifier: 4.1.15
version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
alova:
specifier: 3.5.0
version: 3.5.0
@@ -69,8 +69,8 @@ importers:
specifier: ^11.0.5
version: 11.0.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
typesafe-i18n:
specifier: ^5.26.2
version: 5.26.2(typescript@5.9.3)
specifier: ^5.27.1
version: 5.27.1(typescript@5.9.3)
typescript:
specifier: ^5.9.3
version: 5.9.3
@@ -83,19 +83,19 @@ importers:
version: 10.0.1(eslint@10.0.0)
'@preact/preset-vite':
specifier: ^2.10.3
version: 2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))
version: 2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))
'@trivago/prettier-plugin-sort-imports':
specifier: ^6.0.2
version: 6.0.2(prettier@3.8.1)
'@types/node':
specifier: ^25.2.2
version: 25.2.2
specifier: ^25.2.3
version: 25.2.3
'@types/react':
specifier: ^19.2.13
version: 19.2.13
specifier: ^19.2.14
version: 19.2.14
'@types/react-dom':
specifier: ^19.2.3
version: 19.2.3(@types/react@19.2.13)
version: 19.2.3(@types/react@19.2.14)
axe-core:
specifier: ^4.11.1
version: 4.11.1
@@ -118,17 +118,17 @@ importers:
specifier: ^5.46.0
version: 5.46.0
typescript-eslint:
specifier: ^8.54.0
version: 8.54.0(eslint@10.0.0)(typescript@5.9.3)
specifier: ^8.55.0
version: 8.55.0(eslint@10.0.0)(typescript@5.9.3)
vite:
specifier: ^7.3.1
version: 7.3.1(@types/node@25.2.2)(terser@5.46.0)
version: 7.3.1(@types/node@25.2.3)(terser@5.46.0)
vite-plugin-imagemin:
specifier: ^0.6.1
version: 0.6.1(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))
version: 0.6.1(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))
vite-tsconfig-paths:
specifier: ^6.1.0
version: 6.1.0(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))
specifier: ^6.1.1
version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))
packages:
@@ -508,13 +508,9 @@ packages:
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
engines: {node: '>=18.18'}
'@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22}
'@isaacs/brace-expansion@5.0.1':
resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==}
engines: {node: 20 || >=22}
'@isaacs/cliui@9.0.0':
resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==}
engines: {node: '>=18'}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -535,27 +531,27 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@mui/core-downloads-tracker@7.3.7':
resolution: {integrity: sha512-8jWwS6FweMkpyRkrJooamUGe1CQfO1yJ+lM43IyUJbrhHW/ObES+6ry4vfGi8EKaldHL3t3BG1bcLcERuJPcjg==}
'@mui/core-downloads-tracker@7.3.8':
resolution: {integrity: sha512-s9UHZo7QJVly7gNArEZkbbsimHqJZhElgBpXIJdehZ4OWXt+CCr0SBDgUCDJnQrqpd1dWK2dLq5rmO4mCBmI3w==}
'@mui/icons-material@7.3.7':
resolution: {integrity: sha512-3Q+ulAqG+A1+R4ebgoIs7AccaJhIGy+Xi/9OnvX376jQ6wcy+rz4geDGrxQxCGzdjOQr4Z3NgyFSZCz4T999lA==}
'@mui/icons-material@7.3.8':
resolution: {integrity: sha512-88sWg/UJc1X82OMO+ISR4E3P58I3BjFVg0qkmDu7OWlN8VijneZD3ylFA+ImxuPjMHW3SHosfSJYy1fztoz0fw==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@mui/material': ^7.3.7
'@mui/material': ^7.3.8
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
'@types/react':
optional: true
'@mui/material@7.3.7':
resolution: {integrity: sha512-6bdIxqzeOtBAj2wAsfhWCYyMKPLkRO9u/2o5yexcL0C3APqyy91iGSWgT3H7hg+zR2XgE61+WAu12wXPON8b6A==}
'@mui/material@7.3.8':
resolution: {integrity: sha512-QKd1RhDXE1hf2sQDNayA9ic9jGkEgvZOf0tTkJxlBPG8ns8aS4rS8WwYURw2x5y3739p0HauUXX9WbH7UufFLw==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
'@emotion/styled': ^11.3.0
'@mui/material-pigment-css': ^7.3.7
'@mui/material-pigment-css': ^7.3.8
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
react: ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -569,8 +565,8 @@ packages:
'@types/react':
optional: true
'@mui/private-theming@7.3.7':
resolution: {integrity: sha512-w7r1+CYhG0syCAQUWAuV5zSaU2/67WA9JXUderdb7DzCIJdp/5RmJv6L85wRjgKCMsxFF0Kfn0kPgPbPgw/jdw==}
'@mui/private-theming@7.3.8':
resolution: {integrity: sha512-du5dlPZ9XL3xW2apHoGDXBI+QLtyVJGrXNCfcNYfP/ojkz1RQ0rRV6VG9Rkm1DqEFRG8mjjTL7zmE1Bvn1eR4A==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -579,8 +575,8 @@ packages:
'@types/react':
optional: true
'@mui/styled-engine@7.3.7':
resolution: {integrity: sha512-y/QkNXv6cF6dZ5APztd/dFWfQ6LHKPx3skyYO38YhQD4+Cxd6sFAL3Z38WMSSC8LQz145Mpp3CcLrSCLKPwYAg==}
'@mui/styled-engine@7.3.8':
resolution: {integrity: sha512-JHAeXQzS0tJ+Fq3C6J4TVDsW+yKhO4uuxuiLaopNStJeQYBIUCXpKYyUCcgXym4AmhbznQnv9RlHywSH6b0FOg==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@emotion/react': ^11.4.1
@@ -592,8 +588,8 @@ packages:
'@emotion/styled':
optional: true
'@mui/system@7.3.7':
resolution: {integrity: sha512-DovL3k+FBRKnhmatzUMyO5bKkhMLlQ9L7Qw5qHrre3m8zCZmE+31NDVBFfqrbrA7sq681qaEIHdkWD5nmiAjyQ==}
'@mui/system@7.3.8':
resolution: {integrity: sha512-hoFRj4Zw2Km8DPWZp/nKG+ao5Jw5LSk2m/e4EGc6M3RRwXKEkMSG4TgtfVJg7dS2homRwtdXSMW+iRO0ZJ4+IA==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@emotion/react': ^11.5.0
@@ -608,16 +604,16 @@ packages:
'@types/react':
optional: true
'@mui/types@7.4.10':
resolution: {integrity: sha512-0+4mSjknSu218GW3isRqoxKRTOrTLd/vHi/7UC4+wZcUrOAqD9kRk7UQRL1mcrzqRoe7s3UT6rsRpbLkW5mHpQ==}
'@mui/types@7.4.11':
resolution: {integrity: sha512-fZ2xO9D08IKOxO2oUBi1nnVKH6oJUD+64cnv4YAaFoC0E5+i1+S5AHbNqqvZlYYsbPEQ6qEVwuBqY3jl5W4G+Q==}
peerDependencies:
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
'@types/react':
optional: true
'@mui/utils@7.3.7':
resolution: {integrity: sha512-+YjnjMRnyeTkWnspzoxRdiSOgkrcpTikhNPoxOZW0APXx+urHtUoXJ9lbtCZRCA5a4dg5gSbd19alL1DvRs5fg==}
'@mui/utils@7.3.8':
resolution: {integrity: sha512-kZRcE2620CBGr+XI8YMmwPj6WIPwSF7uMJjvSfqd8zXVvlz0MCJbzRRUGNf8NgflCLthdji2DdS643TeyJ3+nA==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -901,8 +897,8 @@ packages:
resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==}
deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed.
'@types/node@25.2.2':
resolution: {integrity: sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==}
'@types/node@25.2.3':
resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==}
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -920,8 +916,8 @@ packages:
peerDependencies:
'@types/react': '*'
'@types/react@19.2.13':
resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==}
'@types/react@19.2.14':
resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
'@types/responselike@1.0.3':
resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
@@ -929,63 +925,63 @@ packages:
'@types/svgo@2.6.4':
resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
'@typescript-eslint/eslint-plugin@8.54.0':
resolution: {integrity: sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==}
'@typescript-eslint/eslint-plugin@8.55.0':
resolution: {integrity: sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.54.0
'@typescript-eslint/parser': ^8.55.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/parser@8.54.0':
resolution: {integrity: sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==}
'@typescript-eslint/parser@8.55.0':
resolution: {integrity: sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.54.0':
resolution: {integrity: sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==}
'@typescript-eslint/project-service@8.55.0':
resolution: {integrity: sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/scope-manager@8.54.0':
resolution: {integrity: sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==}
'@typescript-eslint/scope-manager@8.55.0':
resolution: {integrity: sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.54.0':
resolution: {integrity: sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==}
'@typescript-eslint/tsconfig-utils@8.55.0':
resolution: {integrity: sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/type-utils@8.54.0':
resolution: {integrity: sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==}
'@typescript-eslint/type-utils@8.55.0':
resolution: {integrity: sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/types@8.54.0':
resolution: {integrity: sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==}
'@typescript-eslint/types@8.55.0':
resolution: {integrity: sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.54.0':
resolution: {integrity: sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==}
'@typescript-eslint/typescript-estree@8.55.0':
resolution: {integrity: sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/utils@8.54.0':
resolution: {integrity: sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==}
'@typescript-eslint/utils@8.55.0':
resolution: {integrity: sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/visitor-keys@8.54.0':
resolution: {integrity: sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==}
'@typescript-eslint/visitor-keys@8.55.0':
resolution: {integrity: sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
acorn-jsx@5.3.2:
@@ -1062,6 +1058,10 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
balanced-match@4.0.2:
resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==}
engines: {node: 20 || >=22}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -1101,6 +1101,10 @@ packages:
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
brace-expansion@5.0.2:
resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==}
engines: {node: 20 || >=22}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
@@ -1155,8 +1159,8 @@ packages:
resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==}
engines: {node: '>=0.10.0'}
caniuse-lite@1.0.30001769:
resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==}
caniuse-lite@1.0.30001770:
resolution: {integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==}
caw@2.0.1:
resolution: {integrity: sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==}
@@ -2077,6 +2081,10 @@ packages:
resolution: {integrity: sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==}
engines: {node: '>= 4'}
jackspeak@4.2.3:
resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==}
engines: {node: 20 || >=22}
javascript-natural-sort@0.7.1:
resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==}
@@ -2247,8 +2255,8 @@ packages:
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
engines: {node: '>=4'}
minimatch@10.1.2:
resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==}
minimatch@10.2.0:
resolution: {integrity: sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==}
engines: {node: 20 || >=22}
minimatch@3.1.2:
@@ -2945,14 +2953,14 @@ packages:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
typesafe-i18n@5.26.2:
resolution: {integrity: sha512-2QAriFmiY5JwUAJtG7yufoE/XZ1aFBY++wj7YFS2yo89a3jLBfKoWSdq5JfQYk1V2BS7V2c/u+KEcaCQoE65hw==}
typesafe-i18n@5.27.1:
resolution: {integrity: sha512-749uWo2ZXETT//kWjVYPm8QPYR8xLh8G0wLfoAyCAtAmysX67uCaAyLjAjAWojL6fuJpE5B6yIjwvO9orXzUPg==}
hasBin: true
peerDependencies:
typescript: '>=3.5.1'
typescript-eslint@8.54.0:
resolution: {integrity: sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==}
typescript-eslint@8.55.0:
resolution: {integrity: sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -3015,8 +3023,8 @@ packages:
peerDependencies:
vite: 5.x || 6.x || 7.x
vite-tsconfig-paths@6.1.0:
resolution: {integrity: sha512-kpd3sY9glHIDaq4V/Tlc1Y8WaKtutoc3B525GHxEVKWX42FKfQsXvjFOemu1I8VIN8pNbrMLWVTbW79JaRUxKg==}
vite-tsconfig-paths@6.1.1:
resolution: {integrity: sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==}
peerDependencies:
vite: '*'
@@ -3289,7 +3297,7 @@ snapshots:
'@emotion/memoize@0.9.0': {}
'@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4)':
'@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@emotion/babel-plugin': 11.13.5
@@ -3301,7 +3309,7 @@ snapshots:
hoist-non-react-statics: 3.3.2
react: 19.2.4
optionalDependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
transitivePeerDependencies:
- supports-color
@@ -3315,18 +3323,18 @@ snapshots:
'@emotion/sheet@1.4.0': {}
'@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)':
'@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@emotion/babel-plugin': 11.13.5
'@emotion/is-prop-valid': 1.4.0
'@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4)
'@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4)
'@emotion/serialize': 1.3.3
'@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4)
'@emotion/utils': 1.4.2
react: 19.2.4
optionalDependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
transitivePeerDependencies:
- supports-color
@@ -3432,7 +3440,7 @@ snapshots:
dependencies:
'@eslint/object-schema': 3.0.1
debug: 4.4.3
minimatch: 10.1.2
minimatch: 10.2.0
transitivePeerDependencies:
- supports-color
@@ -3466,11 +3474,7 @@ snapshots:
'@humanwhocodes/retry@0.4.3': {}
'@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.1':
dependencies:
'@isaacs/balanced-match': 4.0.1
'@isaacs/cliui@9.0.0': {}
'@jridgewell/gen-mapping@0.3.13':
dependencies:
@@ -3496,25 +3500,25 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@mui/core-downloads-tracker@7.3.7': {}
'@mui/core-downloads-tracker@7.3.8': {}
'@mui/icons-material@7.3.7(@mui/material@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)':
'@mui/icons-material@7.3.8(@mui/material@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@mui/material': 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@mui/material': 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react: 19.2.4
optionalDependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
'@mui/material@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
'@mui/material@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@mui/core-downloads-tracker': 7.3.7
'@mui/system': 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)
'@mui/types': 7.4.10(@types/react@19.2.13)
'@mui/utils': 7.3.7(@types/react@19.2.13)(react@19.2.4)
'@mui/core-downloads-tracker': 7.3.8
'@mui/system': 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
'@mui/types': 7.4.11(@types/react@19.2.14)
'@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4)
'@popperjs/core': 2.11.8
'@types/react-transition-group': 4.4.12(@types/react@19.2.13)
'@types/react-transition-group': 4.4.12(@types/react@19.2.14)
clsx: 2.1.1
csstype: 3.2.3
prop-types: 15.8.1
@@ -3523,20 +3527,20 @@ snapshots:
react-is: 19.2.4
react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)
'@types/react': 19.2.13
'@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
'@types/react': 19.2.14
'@mui/private-theming@7.3.7(@types/react@19.2.13)(react@19.2.4)':
'@mui/private-theming@7.3.8(@types/react@19.2.14)(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@mui/utils': 7.3.7(@types/react@19.2.13)(react@19.2.4)
'@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4)
prop-types: 15.8.1
react: 19.2.4
optionalDependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
'@mui/styled-engine@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(react@19.2.4)':
'@mui/styled-engine@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@emotion/cache': 11.14.0
@@ -3546,42 +3550,42 @@ snapshots:
prop-types: 15.8.1
react: 19.2.4
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)
'@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
'@mui/system@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)':
'@mui/system@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@mui/private-theming': 7.3.7(@types/react@19.2.13)(react@19.2.4)
'@mui/styled-engine': 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(react@19.2.4)
'@mui/types': 7.4.10(@types/react@19.2.13)
'@mui/utils': 7.3.7(@types/react@19.2.13)(react@19.2.4)
'@mui/private-theming': 7.3.8(@types/react@19.2.14)(react@19.2.4)
'@mui/styled-engine': 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)
'@mui/types': 7.4.11(@types/react@19.2.14)
'@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4)
clsx: 2.1.1
csstype: 3.2.3
prop-types: 15.8.1
react: 19.2.4
optionalDependencies:
'@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)
'@types/react': 19.2.13
'@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4)
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
'@types/react': 19.2.14
'@mui/types@7.4.10(@types/react@19.2.13)':
'@mui/types@7.4.11(@types/react@19.2.14)':
dependencies:
'@babel/runtime': 7.28.6
optionalDependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
'@mui/utils@7.3.7(@types/react@19.2.13)(react@19.2.4)':
'@mui/utils@7.3.8(@types/react@19.2.14)(react@19.2.4)':
dependencies:
'@babel/runtime': 7.28.6
'@mui/types': 7.4.10(@types/react@19.2.13)
'@mui/types': 7.4.11(@types/react@19.2.14)
'@types/prop-types': 15.7.15
clsx: 2.1.1
prop-types: 15.8.1
react: 19.2.4
react-is: 19.2.4
optionalDependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
'@noble/hashes@1.8.0': {}
@@ -3607,18 +3611,18 @@ snapshots:
dependencies:
preact: 10.28.3
'@preact/preset-vite@2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))':
'@preact/preset-vite@2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0)
'@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0)
'@prefresh/vite': 2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))
'@prefresh/vite': 2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))
'@rollup/pluginutils': 5.3.0(rollup@4.57.1)
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.0)
debug: 4.4.3
picocolors: 1.1.1
vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0)
vite-prerender-plugin: 0.5.12(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))
vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0)
vite-prerender-plugin: 0.5.12(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))
transitivePeerDependencies:
- preact
- rollup
@@ -3632,7 +3636,7 @@ snapshots:
'@prefresh/utils@1.2.1': {}
'@prefresh/vite@2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))':
'@prefresh/vite@2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))':
dependencies:
'@babel/core': 7.29.0
'@prefresh/babel-plugin': 0.5.2
@@ -3640,7 +3644,7 @@ snapshots:
'@prefresh/utils': 1.2.1
'@rollup/pluginutils': 4.2.1
preact: 10.28.3
vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0)
vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0)
transitivePeerDependencies:
- supports-color
@@ -3734,9 +3738,9 @@ snapshots:
'@sindresorhus/is@0.7.0': {}
'@table-library/react-table-library@4.1.15(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
'@table-library/react-table-library@4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
'@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4)
'@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4)
clsx: 1.1.1
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@@ -3766,7 +3770,7 @@ snapshots:
'@types/glob@7.2.0':
dependencies:
'@types/minimatch': 6.0.0
'@types/node': 25.2.2
'@types/node': 25.2.3
'@types/imagemin-gifsicle@7.0.4':
dependencies:
@@ -3795,19 +3799,19 @@ snapshots:
'@types/imagemin@7.0.1':
dependencies:
'@types/node': 25.2.2
'@types/node': 25.2.3
'@types/json-schema@7.0.15': {}
'@types/keyv@3.1.4':
dependencies:
'@types/node': 25.2.2
'@types/node': 25.2.3
'@types/minimatch@6.0.0':
dependencies:
minimatch: 10.1.2
minimatch: 10.2.0
'@types/node@25.2.2':
'@types/node@25.2.3':
dependencies:
undici-types: 7.16.0
@@ -3815,34 +3819,34 @@ snapshots:
'@types/prop-types@15.7.15': {}
'@types/react-dom@19.2.3(@types/react@19.2.13)':
'@types/react-dom@19.2.3(@types/react@19.2.14)':
dependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
'@types/react-transition-group@4.4.12(@types/react@19.2.13)':
'@types/react-transition-group@4.4.12(@types/react@19.2.14)':
dependencies:
'@types/react': 19.2.13
'@types/react': 19.2.14
'@types/react@19.2.13':
'@types/react@19.2.14':
dependencies:
csstype: 3.2.3
'@types/responselike@1.0.3':
dependencies:
'@types/node': 25.2.2
'@types/node': 25.2.3
'@types/svgo@2.6.4':
dependencies:
'@types/node': 25.2.2
'@types/node': 25.2.3
'@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3)':
'@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.54.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.54.0
'@typescript-eslint/type-utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.54.0
'@typescript-eslint/parser': 8.55.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.55.0
'@typescript-eslint/type-utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.55.0
eslint: 10.0.0
ignore: 7.0.5
natural-compare: 1.4.0
@@ -3851,41 +3855,41 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.54.0(eslint@10.0.0)(typescript@5.9.3)':
'@typescript-eslint/parser@8.55.0(eslint@10.0.0)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.54.0
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.54.0
'@typescript-eslint/scope-manager': 8.55.0
'@typescript-eslint/types': 8.55.0
'@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.55.0
debug: 4.4.3
eslint: 10.0.0
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.54.0(typescript@5.9.3)':
'@typescript-eslint/project-service@8.55.0(typescript@5.9.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3)
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3)
'@typescript-eslint/types': 8.55.0
debug: 4.4.3
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.54.0':
'@typescript-eslint/scope-manager@8.55.0':
dependencies:
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/visitor-keys': 8.54.0
'@typescript-eslint/types': 8.55.0
'@typescript-eslint/visitor-keys': 8.55.0
'@typescript-eslint/tsconfig-utils@8.54.0(typescript@5.9.3)':
'@typescript-eslint/tsconfig-utils@8.55.0(typescript@5.9.3)':
dependencies:
typescript: 5.9.3
'@typescript-eslint/type-utils@8.54.0(eslint@10.0.0)(typescript@5.9.3)':
'@typescript-eslint/type-utils@8.55.0(eslint@10.0.0)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/types': 8.55.0
'@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3)
debug: 4.4.3
eslint: 10.0.0
ts-api-utils: 2.4.0(typescript@5.9.3)
@@ -3893,14 +3897,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.54.0': {}
'@typescript-eslint/types@8.55.0': {}
'@typescript-eslint/typescript-estree@8.54.0(typescript@5.9.3)':
'@typescript-eslint/typescript-estree@8.55.0(typescript@5.9.3)':
dependencies:
'@typescript-eslint/project-service': 8.54.0(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3)
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/visitor-keys': 8.54.0
'@typescript-eslint/project-service': 8.55.0(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3)
'@typescript-eslint/types': 8.55.0
'@typescript-eslint/visitor-keys': 8.55.0
debug: 4.4.3
minimatch: 9.0.5
semver: 7.7.4
@@ -3910,20 +3914,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.54.0(eslint@10.0.0)(typescript@5.9.3)':
'@typescript-eslint/utils@8.55.0(eslint@10.0.0)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.1(eslint@10.0.0)
'@typescript-eslint/scope-manager': 8.54.0
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.55.0
'@typescript-eslint/types': 8.55.0
'@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3)
eslint: 10.0.0
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.54.0':
'@typescript-eslint/visitor-keys@8.55.0':
dependencies:
'@typescript-eslint/types': 8.54.0
'@typescript-eslint/types': 8.55.0
eslint-visitor-keys: 4.2.1
acorn-jsx@5.3.2(acorn@8.15.0):
@@ -3986,6 +3990,10 @@ snapshots:
balanced-match@1.0.2: {}
balanced-match@4.0.2:
dependencies:
jackspeak: 4.2.3
base64-js@1.5.1: {}
baseline-browser-mapping@2.9.19: {}
@@ -4039,6 +4047,10 @@ snapshots:
dependencies:
balanced-match: 1.0.2
brace-expansion@5.0.2:
dependencies:
balanced-match: 4.0.2
braces@3.0.3:
dependencies:
fill-range: 7.1.1
@@ -4046,7 +4058,7 @@ snapshots:
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.9.19
caniuse-lite: 1.0.30001769
caniuse-lite: 1.0.30001770
electron-to-chromium: 1.5.286
node-releases: 2.0.27
update-browserslist-db: 1.2.3(browserslist@4.28.1)
@@ -4105,7 +4117,7 @@ snapshots:
camelcase@2.1.1: {}
caniuse-lite@1.0.30001769: {}
caniuse-lite@1.0.30001770: {}
caw@2.0.1:
dependencies:
@@ -4581,7 +4593,7 @@ snapshots:
imurmurhash: 0.1.4
is-glob: 4.0.3
json-stable-stringify-without-jsonify: 1.0.1
minimatch: 10.1.2
minimatch: 10.2.0
natural-compare: 1.4.0
optionator: 0.9.4
transitivePeerDependencies:
@@ -5116,6 +5128,10 @@ snapshots:
has-to-string-tag-x: 1.4.1
is-object: 1.0.2
jackspeak@4.2.3:
dependencies:
'@isaacs/cliui': 9.0.0
javascript-natural-sort@0.7.1: {}
jpegtran-bin@5.0.2:
@@ -5274,9 +5290,9 @@ snapshots:
mimic-response@1.0.1: {}
minimatch@10.1.2:
minimatch@10.2.0:
dependencies:
'@isaacs/brace-expansion': 5.0.1
brace-expansion: 5.0.2
minimatch@3.1.2:
dependencies:
@@ -5931,16 +5947,16 @@ snapshots:
es-errors: 1.3.0
is-typed-array: 1.1.15
typesafe-i18n@5.26.2(typescript@5.9.3):
typesafe-i18n@5.27.1(typescript@5.9.3):
dependencies:
typescript: 5.9.3
typescript-eslint@8.54.0(eslint@10.0.0)(typescript@5.9.3):
typescript-eslint@8.55.0(eslint@10.0.0)(typescript@5.9.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/parser': 8.54.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/eslint-plugin': 8.55.0(@typescript-eslint/parser@8.55.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/parser': 8.55.0(eslint@10.0.0)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3)
eslint: 10.0.0
typescript: 5.9.3
transitivePeerDependencies:
@@ -5986,7 +6002,7 @@ snapshots:
spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1
vite-plugin-imagemin@0.6.1(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)):
vite-plugin-imagemin@0.6.1(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)):
dependencies:
'@types/imagemin': 7.0.1
'@types/imagemin-gifsicle': 7.0.4
@@ -6011,11 +6027,11 @@ snapshots:
imagemin-webp: 6.1.0
jpegtran-bin: 6.0.1
pathe: 0.2.0
vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0)
vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0)
transitivePeerDependencies:
- supports-color
vite-prerender-plugin@0.5.12(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)):
vite-prerender-plugin@0.5.12(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)):
dependencies:
kolorist: 1.8.0
magic-string: 0.30.21
@@ -6023,19 +6039,19 @@ snapshots:
simple-code-frame: 1.3.0
source-map: 0.7.6
stack-trace: 1.0.0-pre2
vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0)
vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0)
vite-tsconfig-paths@6.1.0(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)):
vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)):
dependencies:
debug: 4.4.3
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.9.3)
vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0)
vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0)
transitivePeerDependencies:
- supports-color
- typescript
vite@7.3.1(@types/node@25.2.2)(terser@5.46.0):
vite@7.3.1(@types/node@25.2.3)(terser@5.46.0):
dependencies:
esbuild: 0.27.3
fdir: 6.5.0(picomatch@4.0.3)
@@ -6044,7 +6060,7 @@ snapshots:
rollup: 4.57.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 25.2.2
'@types/node': 25.2.3
fsevents: 2.3.3
terser: 5.46.0

View File

@@ -111,13 +111,14 @@ const Customizations = () => {
const [selectedDeviceTypeNameURL, setSelectedDeviceTypeNameURL] =
useState<string>(''); // needed for API URL
const [selectedDeviceName, setSelectedDeviceName] = useState<string>('');
const [selectedDeviceBrand, setSelectedDeviceBrand] = useState<string>('');
const { send: sendResetCustomizations } = useRequest(resetCustomizations(), {
immediate: false
});
const { send: sendDeviceName } = useRequest(
(data: { id: number; name: string }) => writeDeviceName(data),
(data: { id: number; name: string; brand: string }) => writeDeviceName(data),
{
immediate: false
}
@@ -267,6 +268,7 @@ const Customizations = () => {
if (device) {
setSelectedDeviceTypeNameURL(device.url || '');
setSelectedDeviceName(device.n);
setSelectedDeviceBrand(device.b);
}
setNumChanges(0);
setRestartNeeded(false);
@@ -442,7 +444,11 @@ const Customizations = () => {
}, [devices, deviceEntities, selectedDevice, sendCustomizationEntities, LL]);
const renameDevice = useCallback(async () => {
await sendDeviceName({ id: selectedDevice, name: selectedDeviceName })
await sendDeviceName({
id: selectedDevice,
name: selectedDeviceName,
brand: selectedDeviceBrand
})
.then(() => {
toast.success(LL.UPDATED_OF(LL.NAME(1)));
})
@@ -453,7 +459,14 @@ const Customizations = () => {
setRename(false);
await fetchCoreData();
});
}, [selectedDevice, selectedDeviceName, sendDeviceName, LL, fetchCoreData]);
}, [
selectedDevice,
selectedDeviceName,
selectedDeviceBrand,
sendDeviceName,
LL,
fetchCoreData
]);
const renderDeviceList = () => (
<>
@@ -462,15 +475,26 @@ const Customizations = () => {
</Box>
<Box display="flex" flexWrap="wrap" alignItems="center" gap={2}>
{rename ? (
<TextField
name="device"
label={LL.EMS_DEVICE()}
fullWidth
variant="outlined"
value={selectedDeviceName}
onChange={(e) => setSelectedDeviceName(e.target.value)}
margin="normal"
/>
<>
<TextField
name="device"
label={LL.EMS_DEVICE()}
style={{ minWidth: '48%' }}
variant="outlined"
value={selectedDeviceName}
onChange={(e) => setSelectedDeviceName(e.target.value)}
margin="normal"
/>
<TextField
name="brand"
label={LL.BRAND()}
style={{ minWidth: '48%' }}
variant="outlined"
value={selectedDeviceBrand}
onChange={(e) => setSelectedDeviceBrand(e.target.value)}
margin="normal"
/>
</>
) : (
<TextField
name="device"

View File

@@ -60,18 +60,16 @@ const SystemMonitor = () => {
const { statusMessage, isUploading, progressValue } = useMemo(() => {
const status = data?.status;
let message = '';
if (status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING) {
message = LL.WAIT_FIRMWARE();
} else if (status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART) {
message = LL.APPLICATION_RESTARTING();
} else if (status === SystemStatusCodes.SYSTEM_STATUS_NORMAL) {
message = LL.RESTARTING_PRE();
} else if (status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD) {
message = 'Upload Failed';
} else {
message = LL.RESTARTING_POST();
}
const message =
status && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING
? LL.WAIT_FIRMWARE()
: status === SystemStatusCodes.SYSTEM_STATUS_PENDING_RESTART
? LL.APPLICATION_RESTARTING()
: status === SystemStatusCodes.SYSTEM_STATUS_NORMAL
? LL.RESTARTING_PRE()
: status === SystemStatusCodes.SYSTEM_STATUS_ERROR_UPLOAD
? 'Upload Failed'
: LL.RESTARTING_POST();
const uploading =
status !== undefined && status >= SystemStatusCodes.SYSTEM_STATUS_UPLOADING;

View File

@@ -23,6 +23,6 @@ export const saveFile = (
}, 100);
} catch (error) {
console.error('Failed to save file:', error);
throw new Error(`Unable to save file: ${filename}${extension}`);
throw new Error(`Unable to save file: ${filename}${extension}`, { cause: error });
}
};

View File

@@ -148,9 +148,7 @@
#elif defined(ARDUINO_ARCH_ESP32)
#include <driver/rtc_io.h>
#include <soc/gpio_struct.h>
#if ESP_IDF_VERSION_MAJOR >= 5
#include "soc/gpio_periph.h"
#endif // ESP_IDF_VERSION_MAJOR >= 5
#define PIN_TO_BASEREG(pin) (0)
#define PIN_TO_BITMASK(pin) (pin)
#define IO_REG_TYPE uint32_t

View File

@@ -12,7 +12,9 @@
// Include all library components
#include "esp32-psram/AllocatorPSRAM.h" // PSRAM-backed vector
#include "esp32-psram/VectorPSRAM.h" // PSRAM-backed vector
#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector
#if CONFIG_IDF_TARGET_ESP32
#include "esp32-psram/VectorHIMEM.h" // HIMEM-backed vector (ESP32 only)
#endif
// #include "esp32-psram/InMemoryFile.h" // File interface using vectors
// #include "esp32-psram/PSRAM.h" // PSRAM file system
// #include "esp32-psram/HIMEM.h" // HIMEM file system

View File

@@ -1,5 +1,8 @@
#pragma once
// HIMEM is only available on original ESP32
#if CONFIG_IDF_TARGET_ESP32
#include <algorithm>
#include <limits>
#include <memory>
@@ -360,3 +363,5 @@ class HimemBlock {
};
} // namespace esp32_psram
#endif // CONFIG_IDF_TARGET_ESP32

View File

@@ -238,7 +238,9 @@ using RingBufferStreamPSRAM = RingBufferStream<VectorPSRAM<uint8_t>>;
/**
* @brief Type alias for a RingBufferStream that uses HIMEM-backed vector storage
*/
#if CONFIG_IDF_TARGET_ESP32
using RingBufferStreamHIMEM = RingBufferStream<VectorHIMEM<uint8_t>>;
#endif
/**
* @brief Type alias for a RingBufferStream that uses std::vector storage

View File

@@ -209,8 +209,10 @@ using TypedRingBufferRAM = TypedRingBuffer<T, std::vector<T>>;
/**
* @brief Type alias for a typed ring buffer that uses HIMEM-backed vector storage
*/
#if CONFIG_IDF_TARGET_ESP32
template<typename T>
using TypedRingBufferHIMEM = TypedRingBuffer<T, VectorHIMEM<T>>;
#endif
/**
* @brief Type alias for a typed ring buffer that uses PSRAM-backed vector storage

View File

@@ -1,5 +1,8 @@
#pragma once
// HIMEM is only available on original ESP32
#if CONFIG_IDF_TARGET_ESP32
#include "HimemBlock.h"
namespace esp32_psram {
@@ -526,4 +529,6 @@ void swap(VectorHIMEM<T>& lhs, VectorHIMEM<T>& rhs) noexcept {
lhs.swap(rhs);
}
} // namespace esp32_psram
} // namespace esp32_psram
#endif // CONFIG_IDF_TARGET_ESP32

View File

@@ -66,14 +66,10 @@ the LICENSE file.
#endif
#if EMC_USE_MEMPOOL
#ifndef EMC_NUM_POOL_ELEMENTS
#define EMC_NUM_POOL_ELEMENTS 32
#endif
#ifndef EMC_SIZE_POOL_ELEMENTS
#define EMC_SIZE_POOL_ELEMENTS 128
#endif
#ifndef EMC_NUM_POOL_ELEMENTS
#define EMC_NUM_POOL_ELEMENTS 32
#endif
#ifndef EMC_SIZE_POOL_ELEMENTS
#define EMC_SIZE_POOL_ELEMENTS 128
#endif
#ifndef TASMOTA_SDK
#define EMC_CLIENT_SECURE
#endif

View File

@@ -6,66 +6,157 @@ For a copy, see <https://opensource.org/licenses/MIT> or
the LICENSE file.
*/
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#ifndef NO_TLS_SUPPORT
#include "ClientSecureSync.h"
#include <lwip/sockets.h> // socket options
#include "mbedtls_ssl.h" // triggers compilation of mbedtls SSL module (stripped from Tasmota libmbedtls.a)
#include <cstring>
#include <lwip/sockets.h>
#include <fcntl.h>
namespace espMqttClientInternals {
ClientSecureSync::ClientSecureSync()
: client() {
// empty
: _tls(nullptr)
, _cfg{}
, _connected(false) {
}
ClientSecureSync::~ClientSecureSync() {
stop();
}
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
if (ret) {
#if defined(ARDUINO_ARCH_ESP8266)
client.setNoDelay(true);
#elif defined(ARDUINO_ARCH_ESP32)
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
int val = true;
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
#endif
}
return ret;
char host[16];
sprintf(host, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
return connect(host, port);
}
bool ClientSecureSync::connect(const char* host, uint16_t port) {
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
if (ret) {
#if defined(ARDUINO_ARCH_ESP8266)
client.setNoDelay(true);
#elif defined(ARDUINO_ARCH_ESP32)
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
int val = true;
client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
#endif
}
return ret;
bool ClientSecureSync::connect(const char * host, uint16_t port) {
stop(); // clean up any previous connection
_tls = esp_tls_init();
if (!_tls) {
return false;
}
if (esp_tls_conn_new_sync(host, strlen(host), port, &_cfg, _tls) <= 0) {
esp_tls_conn_destroy(_tls);
_tls = nullptr;
return false;
}
_connected = true;
// Set TCP_NODELAY and non-blocking mode on the underlying socket
int fd = -1;
if (esp_tls_get_conn_sockfd(_tls, &fd) == ESP_OK && fd >= 0) {
int val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
// Make socket non-blocking so reads don't stall the MQTT event loop
int flags = fcntl(fd, F_GETFL, 0);
if (flags >= 0) {
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
}
return true;
}
size_t ClientSecureSync::write(const uint8_t* buf, size_t size) {
return client.write(buf, size);
size_t ClientSecureSync::write(const uint8_t * buf, size_t size) {
if (!_tls || !_connected) {
return 0;
}
// Write all data, retrying on WANT_WRITE (non-blocking socket)
size_t written = 0;
while (written < size) {
int ret = esp_tls_conn_write(_tls, buf + written, size - written);
if (ret > 0) {
written += ret;
} else if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ) {
continue; // retry
} else {
_connected = false;
break;
}
}
return written;
}
int ClientSecureSync::read(uint8_t* buf, size_t size) {
return client.read(buf, size);
int ClientSecureSync::read(uint8_t * buf, size_t size) {
if (!_tls || !_connected) {
return -1;
}
int ret = esp_tls_conn_read(_tls, buf, size);
if (ret > 0) {
return ret;
}
if (ret == ESP_TLS_ERR_SSL_WANT_READ || ret == ESP_TLS_ERR_SSL_WANT_WRITE) {
return -1; // no data available yet, still connected
}
// Connection closed or error
_connected = false;
return -1;
}
void ClientSecureSync::stop() {
client.stop();
if (_tls) {
esp_tls_conn_destroy(_tls);
_tls = nullptr;
}
_connected = false;
}
bool ClientSecureSync::connected() {
return client.connected();
return _connected && _tls != nullptr;
}
bool ClientSecureSync::disconnected() {
return !client.connected();
return !connected();
}
} // namespace espMqttClientInternals
void ClientSecureSync::setCACert(const char * rootCA) {
_cfg.cacert_pem_buf = reinterpret_cast<const unsigned char *>(rootCA);
_cfg.cacert_pem_bytes = strlen(rootCA) + 1;
}
void ClientSecureSync::setCertificate(const char * clientCert) {
_cfg.clientcert_pem_buf = reinterpret_cast<const unsigned char *>(clientCert);
_cfg.clientcert_pem_bytes = strlen(clientCert) + 1;
}
void ClientSecureSync::setPrivateKey(const char * privateKey) {
_cfg.clientkey_pem_buf = reinterpret_cast<const unsigned char *>(privateKey);
_cfg.clientkey_pem_bytes = strlen(privateKey) + 1;
}
void ClientSecureSync::setPreSharedKey(const char * pskIdent, const char * psKey) {
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
_psk.hint = pskIdent;
size_t key_len = strlen(psKey) / 2;
if (key_len > sizeof(_psk_key)) {
key_len = sizeof(_psk_key);
}
for (size_t i = 0; i < key_len; i++) {
sscanf(psKey + 2 * i, "%2hhx", &_psk_key[i]);
}
_psk.key = _psk_key;
_psk.key_size = key_len;
_cfg.psk_hint_key = &_psk;
#endif
}
void ClientSecureSync::setInsecure() {
_cfg.cacert_pem_buf = nullptr;
_cfg.cacert_pem_bytes = 0;
_cfg.crt_bundle_attach = nullptr;
_cfg.use_global_ca_store = false;
_cfg.skip_common_name = true;
}
} // namespace espMqttClientInternals
#endif

View File

@@ -8,15 +8,9 @@ the LICENSE file.
#pragma once
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
#ifndef NO_TLS_SUPPORT
// Added for EMS-ESP
#include "../Config.h"
#if defined(EMC_CLIENT_SECURE)
#include <WiFiClientSecure.h> // includes IPAddress
#else
#include <WiFiClient.h>
#endif
#include "esp_tls.h"
#include "Transport.h"
namespace espMqttClientInternals {
@@ -24,6 +18,7 @@ namespace espMqttClientInternals {
class ClientSecureSync : public Transport {
public:
ClientSecureSync();
~ClientSecureSync();
bool connect(IPAddress ip, uint16_t port) override;
bool connect(const char * host, uint16_t port) override;
size_t write(const uint8_t * buf, size_t size) override;
@@ -31,14 +26,24 @@ class ClientSecureSync : public Transport {
void stop() override;
bool connected() override;
bool disconnected() override;
// added for EMS-ESP
#if defined(EMC_CLIENT_SECURE)
WiFiClientSecure client;
#else
WiFiClient client;
// TLS configuration (call before connect)
void setCACert(const char * rootCA);
void setCertificate(const char * clientCert);
void setPrivateKey(const char * privateKey);
void setPreSharedKey(const char * pskIdent, const char * psKey);
void setInsecure();
private:
esp_tls_t * _tls;
esp_tls_cfg_t _cfg;
bool _connected;
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
psk_hint_key_t _psk;
unsigned char _psk_key[64];
#endif
};
} // namespace espMqttClientInternals
#endif
#endif

View File

@@ -78,36 +78,36 @@ espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
}
espMqttClientSecure & espMqttClientSecure::setInsecure() {
#if defined(EMC_CLIENT_SECURE)
_client.client.setInsecure();
#ifndef NO_TLS_SUPPORT
_client.setInsecure();
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setCACert(rootCA);
#ifndef NO_TLS_SUPPORT
_client.setCACert(rootCA);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setCertificate(clientCa);
#ifndef NO_TLS_SUPPORT
_client.setCertificate(clientCa);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setPrivateKey(privateKey);
#ifndef NO_TLS_SUPPORT
_client.setPrivateKey(privateKey);
#endif
return *this;
}
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
#if defined(EMC_CLIENT_SECURE)
_client.client.setPreSharedKey(pskIdent, psKey);
#ifndef NO_TLS_SUPPORT
_client.setPreSharedKey(pskIdent, psKey);
#endif
return *this;
}

View File

@@ -0,0 +1,40 @@
Import("env")
import os
# The Tasmota platform builds with CONFIG_MBEDTLS_TLS_DISABLED=y, stripping the
# SSL/TLS module from libmbedtls.a. We compile it from source and re-enable the
# necessary config macros for a minimal TLS 1.2 client.
try:
platform = env.PioPlatform()
framework_dir = platform.get_package_dir("framework-arduinoespressif32")
mcu = env.BoardConfig().get("build.mcu", "esp32")
base = os.path.join(framework_dir, "tools", "esp32-arduino-libs", mcu, "include", "mbedtls")
paths = [
os.path.join(base, "mbedtls", "library"),
os.path.join(base, "mbedtls", "include"),
os.path.join(base, "port", "include"),
]
for p in paths:
if os.path.isdir(p):
env.Append(CPPPATH=[p])
# Re-enable mbedtls TLS 1.2 client support (disabled by Tasmota sdkconfig)
env.Append(CPPDEFINES=[
# Core TLS
"CONFIG_MBEDTLS_TLS_ENABLED",
"CONFIG_MBEDTLS_TLS_CLIENT",
"CONFIG_MBEDTLS_SSL_PROTO_TLS1_2",
("CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN", "16384"),
# Key exchange methods (at least one required)
"CONFIG_MBEDTLS_KEY_EXCHANGE_RSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA",
"CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA",
# Optional but useful
"CONFIG_MBEDTLS_SSL_RENEGOTIATION",
"CONFIG_MBEDTLS_SSL_ALPN",
])
except Exception:
pass

View File

@@ -0,0 +1,10 @@
{
"name": "mbedtls_ssl",
"version": "3.6.5",
"description": "mbedtls SSL/TLS module compiled from source (Tasmota platform strips this from libmbedtls.a)",
"platforms": ["espressif32"],
"build": {
"extraScript": "configure.py",
"libArchive": false
}
}

View File

@@ -0,0 +1,684 @@
/**
* \file alignment.h
*
* \brief Utility code for dealing with unaligned memory accesses
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_LIBRARY_ALIGNMENT_H
#define MBEDTLS_LIBRARY_ALIGNMENT_H
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
/*
* Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory
* accesses are known to be efficient.
*
* All functions defined here will behave correctly regardless, but might be less
* efficient when this is not defined.
*/
#if defined(__ARM_FEATURE_UNALIGNED) \
|| defined(MBEDTLS_ARCH_IS_X86) || defined(MBEDTLS_ARCH_IS_X64) \
|| defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
/*
* __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
* (and later versions) for Arm v7 and later; all x86 platforms should have
* efficient unaligned access.
*
* https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment
* specifies that on Windows-on-Arm64, unaligned access is safe (except for uncached
* device memory).
*/
#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
#endif
#if defined(__IAR_SYSTEMS_ICC__) && \
(defined(MBEDTLS_ARCH_IS_ARM64) || defined(MBEDTLS_ARCH_IS_ARM32) \
|| defined(__ICCRX__) || defined(__ICCRL78__) || defined(__ICCRISCV__))
#pragma language=save
#pragma language=extended
#define MBEDTLS_POP_IAR_LANGUAGE_PRAGMA
/* IAR recommend this technique for accessing unaligned data in
* https://www.iar.com/knowledge/support/technical-notes/compiler/accessing-unaligned-data
* This results in a single load / store instruction (if unaligned access is supported).
* According to that document, this is only supported on certain architectures.
*/
#define UINT_UNALIGNED
typedef uint16_t __packed mbedtls_uint16_unaligned_t;
typedef uint32_t __packed mbedtls_uint32_unaligned_t;
typedef uint64_t __packed mbedtls_uint64_unaligned_t;
#elif defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 40504) && \
((MBEDTLS_GCC_VERSION < 60300) || (!defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)))
/*
* gcc may generate a branch to memcpy for calls like `memcpy(dest, src, 4)` rather than
* generating some LDR or LDRB instructions (similar for stores).
*
* This is architecture dependent: x86-64 seems fine even with old gcc; 32-bit Arm
* is affected. To keep it simple, we enable for all architectures.
*
* For versions of gcc < 5.4.0 this issue always happens.
* For gcc < 6.3.0, this issue happens at -O0
* For all versions, this issue happens iff unaligned access is not supported.
*
* For gcc 4.x, this implementation will generate byte-by-byte loads even if unaligned access is
* supported, which is correct but not optimal.
*
* For performance (and code size, in some cases), we want to avoid the branch and just generate
* some inline load/store instructions since the access is small and constant-size.
*
* The manual states:
* "The packed attribute specifies that a variable or structure field should have the smallest
* possible alignment—one byte for a variable"
* https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Variable-Attributes.html
*
* Previous implementations used __attribute__((__aligned__(1)), but had issues with a gcc bug:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94662
*
* Tested with several versions of GCC from 4.5.0 up to 13.2.0
* We don't enable for older than 4.5.0 as this has not been tested.
*/
#define UINT_UNALIGNED_STRUCT
typedef struct {
uint16_t x;
} __attribute__((packed)) mbedtls_uint16_unaligned_t;
typedef struct {
uint32_t x;
} __attribute__((packed)) mbedtls_uint32_unaligned_t;
typedef struct {
uint64_t x;
} __attribute__((packed)) mbedtls_uint64_unaligned_t;
#endif
/*
* We try to force mbedtls_(get|put)_unaligned_uintXX to be always inline, because this results
* in code that is both smaller and faster. IAR and gcc both benefit from this when optimising
* for size.
*/
/**
* Read the unsigned 16 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint16_t mbedtls_get_unaligned_uint16(const void *p)
{
uint16_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = *p16;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
r = p16->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 16 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 2 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
*p16 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
p16->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 32 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint32_t mbedtls_get_unaligned_uint32(const void *p)
{
uint32_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = *p32;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
r = p32->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 32 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 4 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
*p32 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
p32->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
/**
* Read the unsigned 64 bits integer from the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \return Data at the given address
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline uint64_t mbedtls_get_unaligned_uint64(const void *p)
{
uint64_t r;
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = *p64;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
r = p64->x;
#else
memcpy(&r, p, sizeof(r));
#endif
return r;
}
/**
* Write the unsigned 64 bits integer to the given address, which need not
* be aligned.
*
* \param p pointer to 8 bytes of data
* \param x data to write
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
static inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x)
{
#if defined(UINT_UNALIGNED)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
*p64 = x;
#elif defined(UINT_UNALIGNED_STRUCT)
mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
p64->x = x;
#else
memcpy(p, &x, sizeof(x));
#endif
}
#if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA)
#pragma language=restore
#endif
/** Byte Reading Macros
*
* Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
* byte from x, where byte 0 is the least significant byte.
*/
#define MBEDTLS_BYTE_0(x) ((uint8_t) ((x) & 0xff))
#define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >> 8) & 0xff))
#define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff))
#define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff))
#define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff))
#define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff))
#define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff))
#define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff))
/*
* Detect GCC built-in byteswap routines
*/
#if defined(__GNUC__) && defined(__GNUC_PREREQ)
#if __GNUC_PREREQ(4, 8)
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif /* __GNUC_PREREQ(4,8) */
#if __GNUC_PREREQ(4, 3)
#define MBEDTLS_BSWAP32 __builtin_bswap32
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif /* __GNUC_PREREQ(4,3) */
#endif /* defined(__GNUC__) && defined(__GNUC_PREREQ) */
/*
* Detect Clang built-in byteswap routines
*/
#if defined(__clang__) && defined(__has_builtin)
#if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 __builtin_bswap16
#endif /* __has_builtin(__builtin_bswap16) */
#if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 __builtin_bswap32
#endif /* __has_builtin(__builtin_bswap32) */
#if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 __builtin_bswap64
#endif /* __has_builtin(__builtin_bswap64) */
#endif /* defined(__clang__) && defined(__has_builtin) */
/*
* Detect MSVC built-in byteswap routines
*/
#if defined(_MSC_VER)
#if !defined(MBEDTLS_BSWAP16)
#define MBEDTLS_BSWAP16 _byteswap_ushort
#endif
#if !defined(MBEDTLS_BSWAP32)
#define MBEDTLS_BSWAP32 _byteswap_ulong
#endif
#if !defined(MBEDTLS_BSWAP64)
#define MBEDTLS_BSWAP64 _byteswap_uint64
#endif
#endif /* defined(_MSC_VER) */
/* Detect armcc built-in byteswap routine */
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32)
#if defined(__ARM_ACLE) /* ARM Compiler 6 - earlier versions don't need a header */
#include <arm_acle.h>
#endif
#define MBEDTLS_BSWAP32 __rev
#endif
/* Detect IAR built-in byteswap routine */
#if defined(__IAR_SYSTEMS_ICC__)
#if defined(__ARM_ACLE)
#include <arm_acle.h>
#define MBEDTLS_BSWAP16(x) ((uint16_t) __rev16((uint32_t) (x)))
#define MBEDTLS_BSWAP32 __rev
#define MBEDTLS_BSWAP64 __revll
#endif
#endif
/*
* Where compiler built-ins are not present, fall back to C code that the
* compiler may be able to detect and transform into the relevant bswap or
* similar instruction.
*/
#if !defined(MBEDTLS_BSWAP16)
static inline uint16_t mbedtls_bswap16(uint16_t x)
{
return
(x & 0x00ff) << 8 |
(x & 0xff00) >> 8;
}
#define MBEDTLS_BSWAP16 mbedtls_bswap16
#endif /* !defined(MBEDTLS_BSWAP16) */
#if !defined(MBEDTLS_BSWAP32)
static inline uint32_t mbedtls_bswap32(uint32_t x)
{
return
(x & 0x000000ff) << 24 |
(x & 0x0000ff00) << 8 |
(x & 0x00ff0000) >> 8 |
(x & 0xff000000) >> 24;
}
#define MBEDTLS_BSWAP32 mbedtls_bswap32
#endif /* !defined(MBEDTLS_BSWAP32) */
#if !defined(MBEDTLS_BSWAP64)
static inline uint64_t mbedtls_bswap64(uint64_t x)
{
return
(x & 0x00000000000000ffULL) << 56 |
(x & 0x000000000000ff00ULL) << 40 |
(x & 0x0000000000ff0000ULL) << 24 |
(x & 0x00000000ff000000ULL) << 8 |
(x & 0x000000ff00000000ULL) >> 8 |
(x & 0x0000ff0000000000ULL) >> 24 |
(x & 0x00ff000000000000ULL) >> 40 |
(x & 0xff00000000000000ULL) >> 56;
}
#define MBEDTLS_BSWAP64 mbedtls_bswap64
#endif /* !defined(MBEDTLS_BSWAP64) */
#if !defined(__BYTE_ORDER__)
#if defined(__LITTLE_ENDIAN__)
/* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */
#define MBEDTLS_IS_BIG_ENDIAN 0
#elif defined(__BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
static const uint16_t mbedtls_byte_order_detector = { 0x100 };
#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
#endif
#else
#if (__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__)
#define MBEDTLS_IS_BIG_ENDIAN 1
#else
#define MBEDTLS_IS_BIG_ENDIAN 0
#endif
#endif /* !defined(__BYTE_ORDER__) */
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint32((data) + (offset)) \
: MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
)
/**
* Put in memory a 32 bits unsigned integer in big-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 32 bits integer corresponding to four bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the four bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the four bytes to build the 32 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT32_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
: mbedtls_get_unaligned_uint32((data) + (offset)) \
)
/**
* Put in memory a 32 bits unsigned integer in little-endian order.
*
* \param n 32 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 32
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 32 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT32_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n))); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
: mbedtls_get_unaligned_uint16((data) + (offset)) \
)
/**
* Put in memory a 16 bits unsigned integer in little-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
}
/**
* Get the unsigned 16 bits integer corresponding to two bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the two bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the two bytes to build the 16 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT16_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint16((data) + (offset)) \
: MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
)
/**
* Put in memory a 16 bits unsigned integer in big-endian order.
*
* \param n 16 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 16
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 16 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT16_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
} \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_BE(data, offset) \
( \
((uint32_t) (data)[(offset)] << 16) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2]) \
)
/**
* Put in memory a 24 bits unsigned integer in big-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_BE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_2(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_0(n); \
}
/**
* Get the unsigned 24 bits integer corresponding to three bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the three bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the three bytes to build the 24 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT24_LE(data, offset) \
( \
((uint32_t) (data)[(offset)]) \
| ((uint32_t) (data)[(offset) + 1] << 8) \
| ((uint32_t) (data)[(offset) + 2] << 16) \
)
/**
* Put in memory a 24 bits unsigned integer in little-endian order.
*
* \param n 24 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 24
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 24 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT24_LE(n, data, offset) \
{ \
(data)[(offset)] = MBEDTLS_BYTE_0(n); \
(data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
(data)[(offset) + 2] = MBEDTLS_BYTE_2(n); \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* big-endian order (MSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and most significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_BE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? mbedtls_get_unaligned_uint64((data) + (offset)) \
: MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
)
/**
* Put in memory a 64 bits unsigned integer in big-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the most significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_BE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
}
/**
* Get the unsigned 64 bits integer corresponding to eight bytes in
* little-endian order (LSB first).
*
* \param data Base address of the memory to get the eight bytes from.
* \param offset Offset from \p data of the first and least significant
* byte of the eight bytes to build the 64 bits unsigned
* integer from.
*/
#define MBEDTLS_GET_UINT64_LE(data, offset) \
((MBEDTLS_IS_BIG_ENDIAN) \
? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
: mbedtls_get_unaligned_uint64((data) + (offset)) \
)
/**
* Put in memory a 64 bits unsigned integer in little-endian order.
*
* \param n 64 bits unsigned integer to put in memory.
* \param data Base address of the memory where to put the 64
* bits unsigned integer in.
* \param offset Offset from \p data where to put the least significant
* byte of the 64 bits unsigned integer \p n.
*/
#define MBEDTLS_PUT_UINT64_LE(n, data, offset) \
{ \
if (MBEDTLS_IS_BIG_ENDIAN) \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
} \
else \
{ \
mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
} \
}
#endif /* MBEDTLS_LIBRARY_ALIGNMENT_H */

View File

@@ -0,0 +1,453 @@
/**
* \file common.h
*
* \brief Utility macros for internal use in the library
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_LIBRARY_COMMON_H
#define MBEDTLS_LIBRARY_COMMON_H
#include "mbedtls/build_info.h"
#include "alignment.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stddef.h>
#if defined(__ARM_NEON)
#include <arm_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
#include <arm64_neon.h>
#define MBEDTLS_HAVE_NEON_INTRINSICS
#endif
/** Helper to define a function as static except when building invasive tests.
*
* If a function is only used inside its own source file and should be
* declared `static` to allow the compiler to optimize for code size,
* but that function has unit tests, define it with
* ```
* MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... }
* ```
* and declare it in a header in the `library/` directory with
* ```
* #if defined(MBEDTLS_TEST_HOOKS)
* int mbedtls_foo(...);
* #endif
* ```
*/
#if defined(MBEDTLS_TEST_HOOKS)
#define MBEDTLS_STATIC_TESTABLE
#else
#define MBEDTLS_STATIC_TESTABLE static
#endif
#if defined(MBEDTLS_TEST_HOOKS)
extern void (*mbedtls_test_hook_test_fail)(const char *test, int line, const char *file);
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) \
do { \
if ((!(TEST)) && ((*mbedtls_test_hook_test_fail) != NULL)) \
{ \
(*mbedtls_test_hook_test_fail)( #TEST, __LINE__, __FILE__); \
} \
} while (0)
#else
#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST)
#endif /* defined(MBEDTLS_TEST_HOOKS) */
/** \def ARRAY_LENGTH
* Return the number of elements of a static or stack array.
*
* \param array A value of array (not pointer) type.
*
* \return The number of elements of the array.
*/
/* A correct implementation of ARRAY_LENGTH, but which silently gives
* a nonsensical result if called with a pointer rather than an array. */
#define ARRAY_LENGTH_UNSAFE(array) \
(sizeof(array) / sizeof(*(array)))
#if defined(__GNUC__)
/* Test if arg and &(arg)[0] have the same type. This is true if arg is
* an array but not if it's a pointer. */
#define IS_ARRAY_NOT_POINTER(arg) \
(!__builtin_types_compatible_p(__typeof__(arg), \
__typeof__(&(arg)[0])))
/* A compile-time constant with the value 0. If `const_expr` is not a
* compile-time constant with a nonzero value, cause a compile-time error. */
#define STATIC_ASSERT_EXPR(const_expr) \
(0 && sizeof(struct { unsigned int STATIC_ASSERT : 1 - 2 * !(const_expr); }))
/* Return the scalar value `value` (possibly promoted). This is a compile-time
* constant if `value` is. `condition` must be a compile-time constant.
* If `condition` is false, arrange to cause a compile-time error. */
#define STATIC_ASSERT_THEN_RETURN(condition, value) \
(STATIC_ASSERT_EXPR(condition) ? 0 : (value))
#define ARRAY_LENGTH(array) \
(STATIC_ASSERT_THEN_RETURN(IS_ARRAY_NOT_POINTER(array), \
ARRAY_LENGTH_UNSAFE(array)))
#else
/* If we aren't sure the compiler supports our non-standard tricks,
* fall back to the unsafe implementation. */
#define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array)
#endif
/** Allow library to access its structs' private members.
*
* Although structs defined in header files are publicly available,
* their members are private and should not be accessed by the user.
*/
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
/**
* \brief Securely zeroize a buffer then free it.
*
* Similar to making consecutive calls to
* \c mbedtls_platform_zeroize() and \c mbedtls_free(), but has
* code size savings, and potential for optimisation in the future.
*
* Guaranteed to be a no-op if \p buf is \c NULL and \p len is 0.
*
* \param buf Buffer to be zeroized then freed.
* \param len Length of the buffer in bytes
*/
void mbedtls_zeroize_and_free(void *buf, size_t len);
/** Return an offset into a buffer.
*
* This is just the addition of an offset to a pointer, except that this
* function also accepts an offset of 0 into a buffer whose pointer is null.
* (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
* A null pointer is a valid buffer pointer when the size is 0, for example
* as the result of `malloc(0)` on some platforms.)
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline unsigned char *mbedtls_buffer_offset(
unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/** Return an offset into a read-only buffer.
*
* Similar to mbedtls_buffer_offset(), but for const pointers.
*
* \param p Pointer to a buffer of at least n bytes.
* This may be \p NULL if \p n is zero.
* \param n An offset in bytes.
* \return Pointer to offset \p n in the buffer \p p.
* Note that this is only a valid pointer if the size of the
* buffer is at least \p n + 1.
*/
static inline const unsigned char *mbedtls_buffer_offset_const(
const unsigned char *p, size_t n)
{
return p == NULL ? NULL : p + n;
}
/* Always inline mbedtls_xor() for similar reasons as mbedtls_xor_no_simd(). */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_HAVE_NEON_INTRINSICS) && \
(!(defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_GCC_VERSION < 70300))
/* Old GCC versions generate a warning here, so disable the NEON path for these compilers */
for (; (i + 16) <= n; i += 16) {
uint8x16_t v1 = vld1q_u8(a + i);
uint8x16_t v2 = vld1q_u8(b + i);
uint8x16_t x = veorq_u8(v1, v2);
vst1q_u8(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 16.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 16 == 0) {
return;
}
#endif
#elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Always inline mbedtls_xor_no_simd() as we see significant perf regressions when it does not get
* inlined (e.g., observed about 3x perf difference in gcm_mult_largetable with gcc 7 - 12) */
#if defined(__IAR_SYSTEMS_ICC__)
#pragma inline = forced
#elif defined(__GNUC__)
__attribute__((always_inline))
#endif
/**
* Perform a fast block XOR operation, such that
* r[i] = a[i] ^ b[i] where 0 <= i < n
*
* In some situations, this can perform better than mbedtls_xor() (e.g., it's about 5%
* better in AES-CBC).
*
* \param r Pointer to result (buffer of at least \p n bytes). \p r
* may be equal to either \p a or \p b, but behaviour when
* it overlaps in other ways is undefined.
* \param a Pointer to input (buffer of at least \p n bytes)
* \param b Pointer to input (buffer of at least \p n bytes)
* \param n Number of bytes to process.
*
* \note Depending on the situation, it may be faster to use either mbedtls_xor() or
* mbedtls_xor_no_simd() (these are functionally equivalent).
* If the result is used immediately after the xor operation in non-SIMD code (e.g, in
* AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
* registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
* the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
* For targets without SIMD support, they will behave the same.
*/
static inline void mbedtls_xor_no_simd(unsigned char *r,
const unsigned char *a,
const unsigned char *b,
size_t n)
{
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
#if defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
/* This codepath probably only makes sense on architectures with 64-bit registers */
for (; (i + 8) <= n; i += 8) {
uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
mbedtls_put_unaligned_uint64(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
/* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
* where n is a constant multiple of 8.
* For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
* constant, and is a very small perf regression if n is not a compile-time constant. */
if (n % 8 == 0) {
return;
}
#endif
#else
for (; (i + 4) <= n; i += 4) {
uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
mbedtls_put_unaligned_uint32(r + i, x);
}
#if defined(__IAR_SYSTEMS_ICC__)
if (n % 4 == 0) {
return;
}
#endif
#endif
#endif
for (; i < n; i++) {
r[i] = a[i] ^ b[i];
}
}
/* Fix MSVC C99 compatible issue
* MSVC support __func__ from visual studio 2015( 1900 )
* Use MSVC predefine macro to avoid name check fail.
*/
#if (defined(_MSC_VER) && (_MSC_VER <= 1900))
#define /*no-check-names*/ __func__ __FUNCTION__
#endif
/* Define `asm` for compilers which don't define it. */
/* *INDENT-OFF* */
#ifndef asm
#if defined(__IAR_SYSTEMS_ICC__)
#define asm __asm
#else
#define asm __asm__
#endif
#endif
/* *INDENT-ON* */
/*
* Define the constraint used for read-only pointer operands to aarch64 asm.
*
* This is normally the usual "r", but for aarch64_32 (aka ILP32,
* as found in watchos), "p" is required to avoid warnings from clang.
*
* Note that clang does not recognise '+p' or '=p', and armclang
* does not recognise 'p' at all. Therefore, to update a pointer from
* aarch64 assembly, it is necessary to use something like:
*
* uintptr_t uptr = (uintptr_t) ptr;
* asm( "ldr x4, [%x0], #8" ... : "+r" (uptr) : : )
* ptr = (void*) uptr;
*
* Note that the "x" in "%x0" is neccessary; writing "%0" will cause warnings.
*/
#if defined(__aarch64__) && defined(MBEDTLS_HAVE_ASM)
#if UINTPTR_MAX == 0xfffffffful
/* ILP32: Specify the pointer operand slightly differently, as per #7787. */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "p"
#elif UINTPTR_MAX == 0xfffffffffffffffful
/* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */
#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r"
#else
#error "Unrecognised pointer size for aarch64"
#endif
#endif
/* Always provide a static assert macro, so it can be used unconditionally.
* It does nothing on systems where we don't know how to define a static assert.
*/
/* Can't use the C11-style `defined(static_assert)` on FreeBSD, since it
* defines static_assert even with -std=c99, but then complains about it.
*/
#if defined(static_assert) && !defined(__FreeBSD__)
#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#else
/* Make sure `MBEDTLS_STATIC_ASSERT(expr, msg);` is valid both inside and
* outside a function. We choose a struct declaration, which can be repeated
* any number of times and does not need a matching definition. */
#define MBEDTLS_STATIC_ASSERT(expr, msg) \
struct ISO_C_does_not_allow_extra_semicolon_outside_of_a_function
#endif
#if defined(__has_builtin)
#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
#else
#define MBEDTLS_HAS_BUILTIN(x) 0
#endif
/* Define compiler branch hints */
#if MBEDTLS_HAS_BUILTIN(__builtin_expect)
#define MBEDTLS_LIKELY(x) __builtin_expect(!!(x), 1)
#define MBEDTLS_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define MBEDTLS_LIKELY(x) x
#define MBEDTLS_UNLIKELY(x) x
#endif
/* MBEDTLS_ASSUME may be used to provide additional information to the compiler
* which can result in smaller code-size. */
#if MBEDTLS_HAS_BUILTIN(__builtin_assume)
/* clang provides __builtin_assume */
#define MBEDTLS_ASSUME(x) __builtin_assume(x)
#elif MBEDTLS_HAS_BUILTIN(__builtin_unreachable)
/* gcc and IAR can use __builtin_unreachable */
#define MBEDTLS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
#elif defined(_MSC_VER)
/* Supported by MSVC since VS 2005 */
#define MBEDTLS_ASSUME(x) __assume(x)
#else
#define MBEDTLS_ASSUME(x) do { } while (0)
#endif
/* For gcc -Os, override with -O2 for a given function.
*
* This will not affect behaviour for other optimisation settings, e.g. -O0.
*/
#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__OPTIMIZE_SIZE__)
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE __attribute__((optimize("-O2")))
#else
#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE
#endif
/* Suppress compiler warnings for unused functions and variables. */
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__has_attribute)
# if __has_attribute(unused)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__GNUC__)
# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__IAR_SYSTEMS_ICC__) && defined(__VER__)
/* IAR does support __attribute__((unused)), but only if the -e flag (extended language support)
* is given; the pragma always works.
* Unfortunately the pragma affects the rest of the file where it is used, but this is harmless.
* Check for version 5.2 or later - this pragma may be supported by earlier versions, but I wasn't
* able to find documentation).
*/
# if (__VER__ >= 5020000)
# define MBEDTLS_MAYBE_UNUSED _Pragma("diag_suppress=Pe177")
# endif
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(_MSC_VER)
# define MBEDTLS_MAYBE_UNUSED __pragma(warning(suppress:4189))
#endif
#if !defined(MBEDTLS_MAYBE_UNUSED)
# define MBEDTLS_MAYBE_UNUSED
#endif
/* GCC >= 15 has a warning 'unterminated-string-initialization' which complains if you initialize
* a string into an array without space for a terminating NULL character. In some places in the
* codebase this behaviour is intended, so we add the macro MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
* to suppress the warning in these places.
*/
#if defined(__has_attribute)
#if __has_attribute(nonstring)
#define MBEDTLS_HAS_ATTRIBUTE_NONSTRING
#endif /* __has_attribute(nonstring) */
#endif /* __has_attribute */
#if defined(MBEDTLS_HAS_ATTRIBUTE_NONSTRING)
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING __attribute__((nonstring))
#else
#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
#endif /* MBEDTLS_HAS_ATTRIBUTE_NONSTRING */
#endif /* MBEDTLS_LIBRARY_COMMON_H */

View File

@@ -0,0 +1,579 @@
/**
* Constant-time functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H
#define MBEDTLS_CONSTANT_TIME_INTERNAL_H
#include <stdint.h>
#include <stddef.h>
#include "common.h"
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
/* The constant-time interface provides various operations that are likely
* to result in constant-time code that does not branch or use conditional
* instructions for secret data (for secret pointers, this also applies to
* the data pointed to).
*
* It has three main parts:
*
* - boolean operations
* These are all named mbedtls_ct_<type>_<operation>.
* They operate over <type> and return mbedtls_ct_condition_t.
* All arguments are considered secret.
* example: bool x = y | z => x = mbedtls_ct_bool_or(y, z)
* example: bool x = y == z => x = mbedtls_ct_uint_eq(y, z)
*
* - conditional data selection
* These are all named mbedtls_ct_<type>_if and mbedtls_ct_<type>_if_else_0
* All arguments are considered secret.
* example: size_t a = x ? b : c => a = mbedtls_ct_size_if(x, b, c)
* example: unsigned a = x ? b : 0 => a = mbedtls_ct_uint_if_else_0(x, b)
*
* - block memory operations
* Only some arguments are considered secret, as documented for each
* function.
* example: if (x) memcpy(...) => mbedtls_ct_memcpy_if(x, ...)
*
* mbedtls_ct_condition_t must be treated as opaque and only created and
* manipulated via the functions in this header. The compiler should never
* be able to prove anything about its value at compile-time.
*
* mbedtls_ct_uint_t is an unsigned integer type over which constant time
* operations may be performed via the functions in this header. It is as big
* as the larger of size_t and mbedtls_mpi_uint, i.e. it is safe to cast
* to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other
* not-larger integer types).
*
* For Arm (32-bit, 64-bit and Thumb), x86 and x86-64, assembly implementations
* are used to ensure that the generated code is constant time. For other
* architectures, it uses a plain C fallback designed to yield constant-time code
* (this has been observed to be constant-time on latest gcc, clang and MSVC
* as of May 2023).
*
* For readability, the static inline definitions are separated out into
* constant_time_impl.h.
*/
#if (SIZE_MAX > 0xffffffffffffffffULL)
/* Pointer size > 64-bit */
typedef size_t mbedtls_ct_condition_t;
typedef size_t mbedtls_ct_uint_t;
typedef ptrdiff_t mbedtls_ct_int_t;
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(SIZE_MAX))
#elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64)
/* 32-bit < pointer size <= 64-bit, or 64-bit MPI */
typedef uint64_t mbedtls_ct_condition_t;
typedef uint64_t mbedtls_ct_uint_t;
typedef int64_t mbedtls_ct_int_t;
#define MBEDTLS_CT_SIZE_64
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT64_MAX))
#else
/* Pointer size <= 32-bit, and no 64-bit MPIs */
typedef uint32_t mbedtls_ct_condition_t;
typedef uint32_t mbedtls_ct_uint_t;
typedef int32_t mbedtls_ct_int_t;
#define MBEDTLS_CT_SIZE_32
#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT32_MAX))
#endif
#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(0))
/* ============================================================================
* Boolean operations
*/
/** Convert a number into a mbedtls_ct_condition_t.
*
* \param x Number to convert.
*
* \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0
*
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x);
/** Boolean "not equal" operation.
*
* Functionally equivalent to:
*
* \p x != \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
/** Boolean "equals" operation.
*
* Functionally equivalent to:
*
* \p x == \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "less than" operation.
*
* Functionally equivalent to:
*
* \p x < \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
/** Boolean "greater than" operation.
*
* Functionally equivalent to:
*
* \p x > \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "greater or equal" operation.
*
* Functionally equivalent to:
*
* \p x >= \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x >= \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean "less than or equal" operation.
*
* Functionally equivalent to:
*
* \p x <= \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x <= \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
/** Boolean not-equals operation.
*
* Functionally equivalent to:
*
* \p x != \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \note This is more efficient than mbedtls_ct_uint_ne if both arguments are
* mbedtls_ct_condition_t.
*
* \return MBEDTLS_CT_TRUE if \p x != \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "and" operation.
*
* Functionally equivalent to:
*
* \p x && \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x && \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "or" operation.
*
* Functionally equivalent to:
*
* \p x || \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
*
* \return MBEDTLS_CT_TRUE if \p x || \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
mbedtls_ct_condition_t y);
/** Boolean "not" operation.
*
* Functionally equivalent to:
*
* ! \p x
*
* \param x The value to invert
*
* \return MBEDTLS_CT_FALSE if \p x, otherwise MBEDTLS_CT_TRUE.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x);
/* ============================================================================
* Data selection operations
*/
/** Choose between two size_t values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
size_t if1,
size_t if0);
/** Choose between two unsigned values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,
unsigned if1,
unsigned if0);
/** Choose between two mbedtls_ct_condition_t values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_if(mbedtls_ct_condition_t condition,
mbedtls_ct_condition_t if1,
mbedtls_ct_condition_t if0);
#if defined(MBEDTLS_BIGNUM_C)
/** Choose between two mbedtls_mpi_uint values.
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
mbedtls_mpi_uint if1, \
mbedtls_mpi_uint if0);
#endif
/** Choose between an unsigned value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_uint_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1);
/** Choose between an mbedtls_ct_condition_t and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_bool_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline mbedtls_ct_condition_t mbedtls_ct_bool_if_else_0(mbedtls_ct_condition_t condition,
mbedtls_ct_condition_t if1);
/** Choose between a size_t value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_size_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1);
#if defined(MBEDTLS_BIGNUM_C)
/** Choose between an mbedtls_mpi_uint value and 0.
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_mpi_uint_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition,
mbedtls_mpi_uint if1);
#endif
/** Constant-flow char selection
*
* \param low Secret. Bottom of range
* \param high Secret. Top of range
* \param c Secret. Value to compare to range
* \param t Secret. Value to return, if in range
*
* \return \p t if \p low <= \p c <= \p high, 0 otherwise.
*/
static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
unsigned char high,
unsigned char c,
unsigned char t);
/** Choose between two error values. The values must be in the range [-32767..0].
*
* Functionally equivalent to:
*
* condition ? if1 : if0.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
static inline int mbedtls_ct_error_if(mbedtls_ct_condition_t condition, int if1, int if0);
/** Choose between an error value and 0. The error value must be in the range [-32767..0].
*
* Functionally equivalent to:
*
* condition ? if1 : 0.
*
* Functionally equivalent to mbedtls_ct_error_if(condition, if1, 0) but
* results in smaller code size.
*
* \param condition Condition to test.
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
*
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
static inline int mbedtls_ct_error_if_else_0(mbedtls_ct_condition_t condition, int if1);
/* ============================================================================
* Block memory operations
*/
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
/** Conditionally set a block of memory to zero.
*
* Regardless of the condition, every byte will be read once and written to
* once.
*
* \param condition Secret. Condition to test.
* \param buf Secret. Pointer to the start of the buffer.
* \param len Number of bytes to set to zero.
*
* \warning Unlike mbedtls_platform_zeroize, this does not have the same guarantees
* about not being optimised away if the memory is never read again.
*/
void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len);
/** Shift some data towards the left inside a buffer.
*
* Functionally equivalent to:
*
* memmove(start, start + offset, total - offset);
* memset(start + (total - offset), 0, offset);
*
* Timing independence comes at the expense of performance.
*
* \param start Secret. Pointer to the start of the buffer.
* \param total Total size of the buffer.
* \param offset Secret. Offset from which to copy \p total - \p offset bytes.
*/
void mbedtls_ct_memmove_left(void *start,
size_t total,
size_t offset);
#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
/** Conditional memcpy.
*
* Functionally equivalent to:
*
* if (condition) {
* memcpy(dest, src1, len);
* } else {
* if (src2 != NULL)
* memcpy(dest, src2, len);
* }
*
* It will always read len bytes from src1.
* If src2 != NULL, it will always read len bytes from src2.
* If src2 == NULL, it will instead read len bytes from dest (as if src2 == dest).
*
* \param condition The condition
* \param dest Secret. Destination pointer.
* \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE).
* This may be equal to \p dest, but may not overlap in other ways.
* \param src2 Secret (contents only - may branch to determine if this parameter is NULL).
* Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). May be NULL.
* This may be equal to \p dest, but may not overlap it in other ways. It may overlap with \p src1.
* \param len Number of bytes to copy.
*/
void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
unsigned char *dest,
const unsigned char *src1,
const unsigned char *src2,
size_t len
);
/** Copy data from a secret position.
*
* Functionally equivalent to:
*
* memcpy(dst, src + offset, len)
*
* This function copies \p len bytes from \p src + \p offset to
* \p dst, with a code flow and memory access pattern that does not depend on
* \p offset, but only on \p offset_min, \p offset_max and \p len.
*
* \note This function reads from \p dest, but the value that
* is read does not influence the result and this
* function's behavior is well-defined regardless of the
* contents of the buffers. This may result in false
* positives from static or dynamic analyzers, especially
* if \p dest is not initialized.
*
* \param dest Secret. The destination buffer. This must point to a writable
* buffer of at least \p len bytes.
* \param src Secret. The base of the source buffer. This must point to a
* readable buffer of at least \p offset_max + \p len
* bytes. Shouldn't overlap with \p dest
* \param offset Secret. The offset in the source buffer from which to copy.
* This must be no less than \p offset_min and no greater
* than \p offset_max.
* \param offset_min The minimal value of \p offset.
* \param offset_max The maximal value of \p offset.
* \param len The number of bytes to copy.
*/
void mbedtls_ct_memcpy_offset(unsigned char *dest,
const unsigned char *src,
size_t offset,
size_t offset_min,
size_t offset_max,
size_t len);
/* Documented in include/mbedtls/constant_time.h. a and b are secret.
int mbedtls_ct_memcmp(const void *a,
const void *b,
size_t n);
*/
#if defined(MBEDTLS_NIST_KW_C)
/** Constant-time buffer comparison without branches.
*
* Similar to mbedtls_ct_memcmp, except that the result only depends on part of
* the input data - differences in the head or tail are ignored. Functionally equivalent to:
*
* memcmp(a + skip_head, b + skip_head, size - skip_head - skip_tail)
*
* Time taken depends on \p n, but not on \p skip_head or \p skip_tail .
*
* Behaviour is undefined if ( \p skip_head + \p skip_tail) > \p n.
*
* \param a Secret. Pointer to the first buffer, containing at least \p n bytes. May not be NULL.
* \param b Secret. Pointer to the second buffer, containing at least \p n bytes. May not be NULL.
* \param n The number of bytes to examine (total size of the buffers).
* \param skip_head Secret. The number of bytes to treat as non-significant at the start of the buffer.
* These bytes will still be read.
* \param skip_tail Secret. The number of bytes to treat as non-significant at the end of the buffer.
* These bytes will still be read.
*
* \return Zero if the contents of the two buffers are the same, otherwise non-zero.
*/
int mbedtls_ct_memcmp_partial(const void *a,
const void *b,
size_t n,
size_t skip_head,
size_t skip_tail);
#endif
/* Include the implementation of static inline functions above. */
#include "constant_time_impl.h"
#endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */

View File

@@ -0,0 +1,172 @@
/**
* \file debug_internal.h
*
* \brief Internal part of the public "debug.h".
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_DEBUG_INTERNAL_H
#define MBEDTLS_DEBUG_INTERNAL_H
#include "mbedtls/debug.h"
/**
* \brief Print a message to the debug output. This function is always used
* through the MBEDTLS_SSL_DEBUG_MSG() macro, which supplies the ssl
* context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the message has occurred in
* \param line line number the message has occurred at
* \param format format specifier, in printf format
* \param ... variables used by the format specifier
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_msg(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *format, ...) MBEDTLS_PRINTF_ATTRIBUTE(5, 6);
/**
* \brief Print the return value of a function to the debug output. This
* function is always used through the MBEDTLS_SSL_DEBUG_RET() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text the name of the function that returned the error
* \param ret the return code value
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_ret(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, int ret);
/**
* \brief Output a buffer of size len bytes to the debug output. This function
* is always used through the MBEDTLS_SSL_DEBUG_BUF() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the buffer being dumped. Normally the
* variable or buffer name
* \param buf the buffer to be outputted
* \param len length of the buffer
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_buf(const mbedtls_ssl_context *ssl, int level,
const char *file, int line, const char *text,
const unsigned char *buf, size_t len);
#if defined(MBEDTLS_BIGNUM_C)
/**
* \brief Print a MPI variable to the debug output. This function is always
* used through the MBEDTLS_SSL_DEBUG_MPI() macro, which supplies the
* ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the MPI being output. Normally the
* variable name
* \param X the MPI variable
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_mpi *X);
#endif
#if defined(MBEDTLS_ECP_LIGHT)
/**
* \brief Print an ECP point to the debug output. This function is always
* used through the MBEDTLS_SSL_DEBUG_ECP() macro, which supplies the
* ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the ECP point being output. Normally the
* variable name
* \param X the ECP point
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_ecp(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_ecp_point *X);
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C) && !defined(MBEDTLS_X509_REMOVE_INFO)
/**
* \brief Print a X.509 certificate structure to the debug output. This
* function is always used through the MBEDTLS_SSL_DEBUG_CRT() macro,
* which supplies the ssl context, file and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param text a name or label for the certificate being output
* \param crt X.509 certificate structure
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_print_crt(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const char *text, const mbedtls_x509_crt *crt);
#endif
/* Note: the MBEDTLS_ECDH_C guard here is mandatory because this debug function
only works for the built-in implementation. */
#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED) && \
defined(MBEDTLS_ECDH_C)
typedef enum {
MBEDTLS_DEBUG_ECDH_Q,
MBEDTLS_DEBUG_ECDH_QP,
MBEDTLS_DEBUG_ECDH_Z,
} mbedtls_debug_ecdh_attr;
/**
* \brief Print a field of the ECDH structure in the SSL context to the debug
* output. This function is always used through the
* MBEDTLS_SSL_DEBUG_ECDH() macro, which supplies the ssl context, file
* and line number parameters.
*
* \param ssl SSL context
* \param level error level of the debug message
* \param file file the error has occurred in
* \param line line number the error has occurred in
* \param ecdh the ECDH context
* \param attr the identifier of the attribute being output
*
* \attention This function is intended for INTERNAL usage within the
* library only.
*/
void mbedtls_debug_printf_ecdh(const mbedtls_ssl_context *ssl, int level,
const char *file, int line,
const mbedtls_ecdh_context *ecdh,
mbedtls_debug_ecdh_attr attr);
#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDH_OR_ECDHE_ANY_ENABLED &&
MBEDTLS_ECDH_C */
#endif /* MBEDTLS_DEBUG_INTERNAL_H */

View File

@@ -0,0 +1,9 @@
/*
* Stub header to trigger PlatformIO Library Dependency Finder.
*
* The Tasmota Arduino platform ships a stripped libmbedtls.a that is missing
* the core SSL/TLS implementation (mbedtls_ssl_read, mbedtls_ssl_write, etc.).
* This library compiles the official mbedtls 3.6.5 SSL source files so that
* esp_tls and other components that depend on mbedtls SSL can link.
*/
#pragma once

View File

@@ -0,0 +1,26 @@
/**
* Translation between MD and PSA identifiers (algorithms, errors).
*
* Note: this internal module will go away when everything becomes based on
* PSA Crypto; it is a helper for the transition period.
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_MD_PSA_H
#define MBEDTLS_MD_PSA_H
#include "common.h"
#include "mbedtls/md.h"
#include "psa/crypto.h"
/** Convert PSA status to MD error code.
*
* \param status PSA status.
*
* \return The corresponding MD error code,
*/
int mbedtls_md_error_from_psa(psa_status_t status);
#endif /* MBEDTLS_MD_PSA_H */

View File

@@ -0,0 +1,100 @@
/**
* \file psa_util_internal.h
*
* \brief Internal utility functions for use of PSA Crypto.
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_PSA_UTIL_INTERNAL_H
#define MBEDTLS_PSA_UTIL_INTERNAL_H
/* Include the public header so that users only need one include. */
#include "mbedtls/psa_util.h"
#include "psa/crypto.h"
#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
/*************************************************************************
* FFDH
************************************************************************/
#define MBEDTLS_PSA_MAX_FFDH_PUBKEY_LENGTH \
PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS)
/*************************************************************************
* ECC
************************************************************************/
#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH \
PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
#define MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH \
PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
/*************************************************************************
* Error translation
************************************************************************/
typedef struct {
/* Error codes used by PSA crypto are in -255..-128, fitting in 16 bits. */
int16_t psa_status;
/* Error codes used by Mbed TLS are in one of the ranges
* -127..-1 (low-level) or -32767..-4096 (high-level with a low-level
* code optionally added), fitting in 16 bits. */
int16_t mbedtls_error;
} mbedtls_error_pair_t;
#if defined(MBEDTLS_MD_LIGHT)
extern const mbedtls_error_pair_t psa_to_md_errors[4];
#endif
#if defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)
extern const mbedtls_error_pair_t psa_to_cipher_errors[4];
#endif
#if defined(MBEDTLS_LMS_C)
extern const mbedtls_error_pair_t psa_to_lms_errors[3];
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
extern const mbedtls_error_pair_t psa_to_ssl_errors[7];
#endif
#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY) || \
defined(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC)
extern const mbedtls_error_pair_t psa_to_pk_rsa_errors[8];
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO) && \
defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY)
extern const mbedtls_error_pair_t psa_to_pk_ecdsa_errors[7];
#endif
/* Generic fallback function for error translation,
* when the received state was not module-specific. */
int psa_generic_status_to_mbedtls(psa_status_t status);
/* This function iterates over provided local error translations,
* and if no match was found - calls the fallback error translation function. */
int psa_status_to_mbedtls(psa_status_t status,
const mbedtls_error_pair_t *local_translations,
size_t local_errors_num,
int (*fallback_f)(psa_status_t));
/* The second out of three-stage error handling functions of the pk module,
* acts as a fallback after RSA / ECDSA error translation, and if no match
* is found, it itself calls psa_generic_status_to_mbedtls. */
int psa_pk_status_to_mbedtls(psa_status_t status);
/* Utility macro to shorten the defines of error translator in modules. */
#define PSA_TO_MBEDTLS_ERR_LIST(status, error_list, fallback_f) \
psa_status_to_mbedtls(status, error_list, \
sizeof(error_list)/sizeof(error_list[0]), \
fallback_f)
#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
#endif /* MBEDTLS_PSA_UTIL_INTERNAL_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
/**
* TLS 1.2 and 1.3 client-side functions
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_SSL_CLIENT_H
#define MBEDTLS_SSL_CLIENT_H
#include "common.h"
#if defined(MBEDTLS_SSL_TLS_C)
#include "ssl_misc.h"
#endif
#include <stddef.h>
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_write_client_hello(mbedtls_ssl_context *ssl);
#endif /* MBEDTLS_SSL_CLIENT_H */

View File

@@ -0,0 +1,83 @@
/**
* \file ssl_debug_helpers.h
*
* \brief Automatically generated helper functions for debugging
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#ifndef MBEDTLS_SSL_DEBUG_HELPERS_H
#define MBEDTLS_SSL_DEBUG_HELPERS_H
#include "common.h"
#if defined(MBEDTLS_DEBUG_C)
#include "mbedtls/ssl.h"
#include "ssl_misc.h"
const char *mbedtls_ssl_states_str(mbedtls_ssl_states in);
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
const char *mbedtls_ssl_early_data_status_str(mbedtls_ssl_early_data_status in);
const char *mbedtls_ssl_early_data_state_str(mbedtls_ssl_early_data_state in);
#endif
const char *mbedtls_ssl_protocol_version_str(mbedtls_ssl_protocol_version in);
const char *mbedtls_tls_prf_types_str(mbedtls_tls_prf_types in);
const char *mbedtls_ssl_key_export_type_str(mbedtls_ssl_key_export_type in);
const char *mbedtls_ssl_sig_alg_to_str(uint16_t in);
const char *mbedtls_ssl_named_group_to_str(uint16_t in);
const char *mbedtls_ssl_get_extension_name(unsigned int extension_type);
void mbedtls_ssl_print_extensions(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
int hs_msg_type, uint32_t extensions_mask,
const char *extra);
void mbedtls_ssl_print_extension(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
int hs_msg_type, unsigned int extension_type,
const char *extra_msg0, const char *extra_msg1);
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
void mbedtls_ssl_print_ticket_flags(const mbedtls_ssl_context *ssl,
int level, const char *file, int line,
unsigned int flags);
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
#define MBEDTLS_SSL_PRINT_EXTS(level, hs_msg_type, extensions_mask) \
mbedtls_ssl_print_extensions(ssl, level, __FILE__, __LINE__, \
hs_msg_type, extensions_mask, NULL)
#define MBEDTLS_SSL_PRINT_EXT(level, hs_msg_type, extension_type, extra) \
mbedtls_ssl_print_extension(ssl, level, __FILE__, __LINE__, \
hs_msg_type, extension_type, \
extra, NULL)
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
#define MBEDTLS_SSL_PRINT_TICKET_FLAGS(level, flags) \
mbedtls_ssl_print_ticket_flags(ssl, level, __FILE__, __LINE__, flags)
#endif
#else
#define MBEDTLS_SSL_PRINT_EXTS(level, hs_msg_type, extension_mask)
#define MBEDTLS_SSL_PRINT_EXT(level, hs_msg_type, extension_type, extra)
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
#define MBEDTLS_SSL_PRINT_TICKET_FLAGS(level, flags)
#endif
#endif /* MBEDTLS_DEBUG_C */
#endif /* MBEDTLS_SSL_DEBUG_HELPERS_H */

View File

@@ -0,0 +1,251 @@
/* Automatically generated by generate_ssl_debug_helpers.py. DO NOT EDIT. */
/**
* \file ssl_debug_helpers_generated.c
*
* \brief Automatically generated helper functions for debugging
*/
/*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*
*/
#include "ssl_misc.h"
#if defined(MBEDTLS_DEBUG_C)
#include "ssl_debug_helpers.h"
const char *mbedtls_ssl_named_group_to_str( uint16_t in )
{
switch( in )
{
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP192K1:
return "secp192k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP192R1:
return "secp192r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP224K1:
return "secp224k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP224R1:
return "secp224r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP256K1:
return "secp256k1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1:
return "secp256r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1:
return "secp384r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_SECP521R1:
return "secp521r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP256R1:
return "bp256r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP384R1:
return "bp384r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_BP512R1:
return "bp512r1";
case MBEDTLS_SSL_IANA_TLS_GROUP_X25519:
return "x25519";
case MBEDTLS_SSL_IANA_TLS_GROUP_X448:
return "x448";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE2048:
return "ffdhe2048";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE3072:
return "ffdhe3072";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE4096:
return "ffdhe4096";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE6144:
return "ffdhe6144";
case MBEDTLS_SSL_IANA_TLS_GROUP_FFDHE8192:
return "ffdhe8192";
};
return "UNKNOWN";
}
const char *mbedtls_ssl_sig_alg_to_str( uint16_t in )
{
switch( in )
{
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA256:
return "rsa_pkcs1_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA384:
return "rsa_pkcs1_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA512:
return "rsa_pkcs1_sha512";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256:
return "ecdsa_secp256r1_sha256";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP384R1_SHA384:
return "ecdsa_secp384r1_sha384";
case MBEDTLS_TLS1_3_SIG_ECDSA_SECP521R1_SHA512:
return "ecdsa_secp521r1_sha512";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA256:
return "rsa_pss_rsae_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA384:
return "rsa_pss_rsae_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_RSAE_SHA512:
return "rsa_pss_rsae_sha512";
case MBEDTLS_TLS1_3_SIG_ED25519:
return "ed25519";
case MBEDTLS_TLS1_3_SIG_ED448:
return "ed448";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA256:
return "rsa_pss_pss_sha256";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA384:
return "rsa_pss_pss_sha384";
case MBEDTLS_TLS1_3_SIG_RSA_PSS_PSS_SHA512:
return "rsa_pss_pss_sha512";
case MBEDTLS_TLS1_3_SIG_RSA_PKCS1_SHA1:
return "rsa_pkcs1_sha1";
case MBEDTLS_TLS1_3_SIG_ECDSA_SHA1:
return "ecdsa_sha1";
case MBEDTLS_TLS1_3_SIG_NONE:
return "none";
};
return "UNKNOWN";
}
const char *mbedtls_ssl_states_str( mbedtls_ssl_states in )
{
switch (in) {
case MBEDTLS_SSL_HELLO_REQUEST:
return "MBEDTLS_SSL_HELLO_REQUEST";
case MBEDTLS_SSL_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_HELLO:
return "MBEDTLS_SSL_SERVER_HELLO";
case MBEDTLS_SSL_SERVER_CERTIFICATE:
return "MBEDTLS_SSL_SERVER_CERTIFICATE";
case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
return "MBEDTLS_SSL_SERVER_KEY_EXCHANGE";
case MBEDTLS_SSL_CERTIFICATE_REQUEST:
return "MBEDTLS_SSL_CERTIFICATE_REQUEST";
case MBEDTLS_SSL_SERVER_HELLO_DONE:
return "MBEDTLS_SSL_SERVER_HELLO_DONE";
case MBEDTLS_SSL_CLIENT_CERTIFICATE:
return "MBEDTLS_SSL_CLIENT_CERTIFICATE";
case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
return "MBEDTLS_SSL_CLIENT_KEY_EXCHANGE";
case MBEDTLS_SSL_CERTIFICATE_VERIFY:
return "MBEDTLS_SSL_CERTIFICATE_VERIFY";
case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
return "MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC";
case MBEDTLS_SSL_CLIENT_FINISHED:
return "MBEDTLS_SSL_CLIENT_FINISHED";
case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
return "MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC";
case MBEDTLS_SSL_SERVER_FINISHED:
return "MBEDTLS_SSL_SERVER_FINISHED";
case MBEDTLS_SSL_FLUSH_BUFFERS:
return "MBEDTLS_SSL_FLUSH_BUFFERS";
case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
return "MBEDTLS_SSL_HANDSHAKE_WRAPUP";
case MBEDTLS_SSL_NEW_SESSION_TICKET:
return "MBEDTLS_SSL_NEW_SESSION_TICKET";
case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT:
return "MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT";
case MBEDTLS_SSL_HELLO_RETRY_REQUEST:
return "MBEDTLS_SSL_HELLO_RETRY_REQUEST";
case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS:
return "MBEDTLS_SSL_ENCRYPTED_EXTENSIONS";
case MBEDTLS_SSL_END_OF_EARLY_DATA:
return "MBEDTLS_SSL_END_OF_EARLY_DATA";
case MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY:
return "MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY";
case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED:
return "MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED";
case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO:
return "MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO";
case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO:
return "MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO";
case MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST:
return "MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST";
case MBEDTLS_SSL_HANDSHAKE_OVER:
return "MBEDTLS_SSL_HANDSHAKE_OVER";
case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET:
return "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET";
case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:
return "MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH";
default:
return "UNKNOWN_VALUE";
}
}
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
const char *mbedtls_ssl_early_data_status_str( mbedtls_ssl_early_data_status in )
{
switch (in) {
case MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_INDICATED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_INDICATED";
case MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED";
case MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED:
return "MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED";
default:
return "UNKNOWN_VALUE";
}
}
#endif /* defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C) */
const char *mbedtls_ssl_protocol_version_str( mbedtls_ssl_protocol_version in )
{
switch (in) {
case MBEDTLS_SSL_VERSION_UNKNOWN:
return "MBEDTLS_SSL_VERSION_UNKNOWN";
case MBEDTLS_SSL_VERSION_TLS1_2:
return "MBEDTLS_SSL_VERSION_TLS1_2";
case MBEDTLS_SSL_VERSION_TLS1_3:
return "MBEDTLS_SSL_VERSION_TLS1_3";
default:
return "UNKNOWN_VALUE";
}
}
const char *mbedtls_tls_prf_types_str( mbedtls_tls_prf_types in )
{
switch (in) {
case MBEDTLS_SSL_TLS_PRF_NONE:
return "MBEDTLS_SSL_TLS_PRF_NONE";
case MBEDTLS_SSL_TLS_PRF_SHA384:
return "MBEDTLS_SSL_TLS_PRF_SHA384";
case MBEDTLS_SSL_TLS_PRF_SHA256:
return "MBEDTLS_SSL_TLS_PRF_SHA256";
case MBEDTLS_SSL_HKDF_EXPAND_SHA384:
return "MBEDTLS_SSL_HKDF_EXPAND_SHA384";
case MBEDTLS_SSL_HKDF_EXPAND_SHA256:
return "MBEDTLS_SSL_HKDF_EXPAND_SHA256";
default:
return "UNKNOWN_VALUE";
}
}
const char *mbedtls_ssl_key_export_type_str( mbedtls_ssl_key_export_type in )
{
switch (in) {
case MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET";
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_EARLY_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_EARLY_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_EARLY_EXPORTER_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_EARLY_EXPORTER_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET";
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET:
return "MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET";
#endif
default:
return "UNKNOWN_VALUE";
}
}
#endif /* MBEDTLS_DEBUG_C */
/* End of automatically generated file. */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

10187
lib/mbedtls_ssl/src/ssl_tls.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,668 @@
/*
* TLS 1.3 key schedule
*
* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
*/
#if !defined(MBEDTLS_SSL_TLS1_3_KEYS_H)
#define MBEDTLS_SSL_TLS1_3_KEYS_H
/* This requires MBEDTLS_SSL_TLS1_3_LABEL( idx, name, string ) to be defined at
* the point of use. See e.g. the definition of mbedtls_ssl_tls13_labels_union
* below. */
#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \
MBEDTLS_SSL_TLS1_3_LABEL(finished, "finished") \
MBEDTLS_SSL_TLS1_3_LABEL(resumption, "resumption") \
MBEDTLS_SSL_TLS1_3_LABEL(traffic_upd, "traffic upd") \
MBEDTLS_SSL_TLS1_3_LABEL(exporter, "exporter") \
MBEDTLS_SSL_TLS1_3_LABEL(key, "key") \
MBEDTLS_SSL_TLS1_3_LABEL(iv, "iv") \
MBEDTLS_SSL_TLS1_3_LABEL(c_hs_traffic, "c hs traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(c_ap_traffic, "c ap traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(c_e_traffic, "c e traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_hs_traffic, "s hs traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_ap_traffic, "s ap traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(s_e_traffic, "s e traffic") \
MBEDTLS_SSL_TLS1_3_LABEL(e_exp_master, "e exp master") \
MBEDTLS_SSL_TLS1_3_LABEL(res_master, "res master") \
MBEDTLS_SSL_TLS1_3_LABEL(exp_master, "exp master") \
MBEDTLS_SSL_TLS1_3_LABEL(ext_binder, "ext binder") \
MBEDTLS_SSL_TLS1_3_LABEL(res_binder, "res binder") \
MBEDTLS_SSL_TLS1_3_LABEL(derived, "derived") \
MBEDTLS_SSL_TLS1_3_LABEL(client_cv, "TLS 1.3, client CertificateVerify") \
MBEDTLS_SSL_TLS1_3_LABEL(server_cv, "TLS 1.3, server CertificateVerify")
#define MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED 0
#define MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED 1
#define MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL 0
#define MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION 1
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
/* We need to tell the compiler that we meant to leave out the null character. */
#define MBEDTLS_SSL_TLS1_3_LABEL(name, string) \
const unsigned char name [sizeof(string) - 1] MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING;
union mbedtls_ssl_tls13_labels_union {
MBEDTLS_SSL_TLS1_3_LABEL_LIST
};
struct mbedtls_ssl_tls13_labels_struct {
MBEDTLS_SSL_TLS1_3_LABEL_LIST
};
#undef MBEDTLS_SSL_TLS1_3_LABEL
extern const struct mbedtls_ssl_tls13_labels_struct mbedtls_ssl_tls13_labels;
#define MBEDTLS_SSL_TLS1_3_LBL_LEN(LABEL) \
sizeof(mbedtls_ssl_tls13_labels.LABEL)
#define MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN(LABEL) \
mbedtls_ssl_tls13_labels.LABEL, \
MBEDTLS_SSL_TLS1_3_LBL_LEN(LABEL)
/* Maximum length of the label field in the HkdfLabel struct defined in
* RFC 8446, Section 7.1, excluding the "tls13 " prefix. */
#define MBEDTLS_SSL_TLS1_3_HKDF_LABEL_MAX_LABEL_LEN 249
/* The maximum length of HKDF contexts used in the TLS 1.3 standard.
* Since contexts are always hashes of message transcripts, this can
* be approximated from above by the maximum hash size. */
#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN \
PSA_HASH_MAX_SIZE
/* Maximum desired length for expanded key material generated
* by HKDF-Expand-Label. This algorithm can output up to 255 * hash_size
* bytes of key material where hash_size is the output size of the
* underlying hash function. */
#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN \
(255 * MBEDTLS_TLS1_3_MD_MAX_SIZE)
/**
* \brief The \c HKDF-Expand-Label function from
* the TLS 1.3 standard RFC 8446.
*
* <tt>
* HKDF-Expand-Label( Secret, Label, Context, Length ) =
* HKDF-Expand( Secret, HkdfLabel, Length )
* </tt>
*
* \param hash_alg The identifier for the hash algorithm to use.
* \param secret The \c Secret argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length
* \p secret_len Bytes.
* \param secret_len The length of \p secret in Bytes.
* \param label The \c Label argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length
* \p label_len Bytes.
* \param label_len The length of \p label in Bytes.
* \param ctx The \c Context argument to \c HKDF-Expand-Label.
* This must be a readable buffer of length \p ctx_len Bytes.
* \param ctx_len The length of \p context in Bytes.
* \param buf The destination buffer to hold the expanded secret.
* This must be a writable buffer of length \p buf_len Bytes.
* \param buf_len The desired size of the expanded secret in Bytes.
*
* \returns \c 0 on success.
* \return A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_hkdf_expand_label(
psa_algorithm_t hash_alg,
const unsigned char *secret, size_t secret_len,
const unsigned char *label, size_t label_len,
const unsigned char *ctx, size_t ctx_len,
unsigned char *buf, size_t buf_len);
/**
* \brief This function is part of the TLS 1.3 key schedule.
* It extracts key and IV for the actual client/server traffic
* from the client/server traffic secrets.
*
* From RFC 8446:
*
* <tt>
* [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
* [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length)*
* </tt>
*
* \param hash_alg The identifier for the hash algorithm to be used
* for the HKDF-based expansion of the secret.
* \param client_secret The client traffic secret.
* This must be a readable buffer of size
* \p secret_len Bytes
* \param server_secret The server traffic secret.
* This must be a readable buffer of size
* \p secret_len Bytes
* \param secret_len Length of the secrets \p client_secret and
* \p server_secret in Bytes.
* \param key_len The desired length of the key to be extracted in Bytes.
* \param iv_len The desired length of the IV to be extracted in Bytes.
* \param keys The address of the structure holding the generated
* keys and IVs.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_make_traffic_keys(
psa_algorithm_t hash_alg,
const unsigned char *client_secret,
const unsigned char *server_secret, size_t secret_len,
size_t key_len, size_t iv_len,
mbedtls_ssl_key_set *keys);
/**
* \brief The \c Derive-Secret function from the TLS 1.3 standard RFC 8446.
*
* <tt>
* Derive-Secret( Secret, Label, Messages ) =
* HKDF-Expand-Label( Secret, Label,
* Hash( Messages ),
* Hash.Length ) )
* </tt>
*
* \param hash_alg The identifier for the hash function used for the
* applications of HKDF.
* \param secret The \c Secret argument to the \c Derive-Secret function.
* This must be a readable buffer of length
* \p secret_len Bytes.
* \param secret_len The length of \p secret in Bytes.
* \param label The \c Label argument to the \c Derive-Secret function.
* This must be a readable buffer of length
* \p label_len Bytes.
* \param label_len The length of \p label in Bytes.
* \param ctx The hash of the \c Messages argument to the
* \c Derive-Secret function, or the \c Messages argument
* itself, depending on \p ctx_hashed.
* \param ctx_len The length of \p ctx in Bytes.
* \param ctx_hashed This indicates whether the \p ctx contains the hash of
* the \c Messages argument in the application of the
* \c Derive-Secret function
* (value MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED), or whether
* it is the content of \c Messages itself, in which case
* the function takes care of the hashing
* (value MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED).
* \param dstbuf The target buffer to write the output of
* \c Derive-Secret to. This must be a writable buffer of
* size \p dtsbuf_len Bytes.
* \param dstbuf_len The length of \p dstbuf in Bytes.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_secret(
psa_algorithm_t hash_alg,
const unsigned char *secret, size_t secret_len,
const unsigned char *label, size_t label_len,
const unsigned char *ctx, size_t ctx_len,
int ctx_hashed,
unsigned char *dstbuf, size_t dstbuf_len);
/**
* \brief Derive TLS 1.3 early data key material from early secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels.
*
* <tt>
* Early Secret
* |
* +-----> Derive-Secret(., "c e traffic", ClientHello)
* | = client_early_traffic_secret
* |
* +-----> Derive-Secret(., "e exp master", ClientHello)
* . = early_exporter_master_secret
* .
* .
* </tt>
*
* \note To obtain the actual key and IV for the early data traffic,
* the client secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \note The binder key, which is also generated from the early secret,
* is omitted here. Its calculation is part of the separate routine
* mbedtls_ssl_tls13_create_psk_binder().
*
* \param hash_alg The hash algorithm associated with the PSK for which
* early data key material is being derived.
* \param early_secret The early secret from which the early data key material
* should be derived. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p md_size.
* \param transcript The transcript of the handshake so far, calculated with
* respect to \p hash_alg. This must be a readable buffer
* whose length is the digest size of the hash algorithm
* represented by \p md_size.
* \param derived The address of the structure in which to store
* the early data key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_early_secrets(
psa_algorithm_t hash_alg,
unsigned char const *early_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_early_secrets *derived);
/**
* \brief Derive TLS 1.3 handshake key material from the handshake secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* <tt>
* Handshake Secret
* |
* +-----> Derive-Secret( ., "c hs traffic",
* | ClientHello...ServerHello )
* | = client_handshake_traffic_secret
* |
* +-----> Derive-Secret( ., "s hs traffic",
* . ClientHello...ServerHello )
* . = server_handshake_traffic_secret
* .
* </tt>
*
* \note To obtain the actual key and IV for the encrypted handshake traffic,
* the client and server secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \param hash_alg The hash algorithm associated with the ciphersuite
* that's being used for the connection.
* \param handshake_secret The handshake secret from which the handshake key
* material should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake so far, calculated
* with respect to \p hash_alg. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param derived The address of the structure in which to
* store the handshake key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_handshake_secrets(
psa_algorithm_t hash_alg,
unsigned char const *handshake_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_handshake_secrets *derived);
/**
* \brief Derive TLS 1.3 application key material from the master secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* <tt>
* Master Secret
* |
* +-----> Derive-Secret( ., "c ap traffic",
* | ClientHello...server Finished )
* | = client_application_traffic_secret_0
* |
* +-----> Derive-Secret( ., "s ap traffic",
* | ClientHello...Server Finished )
* | = server_application_traffic_secret_0
* |
* +-----> Derive-Secret( ., "exp master",
* . ClientHello...server Finished)
* . = exporter_master_secret
* .
* </tt>
*
* \note To obtain the actual key and IV for the (0-th) application traffic,
* the client and server secret derived by this function need to be
* further processed by mbedtls_ssl_tls13_make_traffic_keys().
*
* \param hash_alg The hash algorithm associated with the ciphersuite
* that's being used for the connection.
* \param master_secret The master secret from which the application key
* material should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake up to and including
* the ServerFinished message, calculated with respect
* to \p hash_alg. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p hash_alg.
* \param derived The address of the structure in which to
* store the application key material.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_application_secrets(
psa_algorithm_t hash_alg,
unsigned char const *master_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_application_secrets *derived);
/**
* \brief Derive TLS 1.3 resumption master secret from the master secret.
*
* This is a small wrapper invoking mbedtls_ssl_tls13_derive_secret()
* with the appropriate labels from the standard.
*
* \param hash_alg The hash algorithm used in the application for which
* key material is being derived.
* \param application_secret The application secret from which the resumption master
* secret should be derived. This must be a readable
* buffer whose length is the digest size of the hash
* algorithm represented by \p md_size.
* \param transcript The transcript of the handshake up to and including
* the ClientFinished message, calculated with respect
* to \p hash_alg. This must be a readable buffer whose
* length is the digest size of the hash algorithm
* represented by \p hash_alg.
* \param transcript_len The length of \p transcript in Bytes.
* \param derived The address of the structure in which to
* store the resumption master secret.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_derive_resumption_master_secret(
psa_algorithm_t hash_alg,
unsigned char const *application_secret,
unsigned char const *transcript, size_t transcript_len,
mbedtls_ssl_tls13_application_secrets *derived);
/**
* \brief Compute the next secret in the TLS 1.3 key schedule
*
* The TLS 1.3 key schedule proceeds as follows to compute
* the three main secrets during the handshake: The early
* secret for early data, the handshake secret for all
* other encrypted handshake messages, and the master
* secret for all application traffic.
*
* <tt>
* 0
* |
* v
* PSK -> HKDF-Extract = Early Secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* (EC)DHE -> HKDF-Extract = Handshake Secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* 0 -> HKDF-Extract = Master Secret
* </tt>
*
* Each of the three secrets in turn is the basis for further
* key derivations, such as the derivation of traffic keys and IVs;
* see e.g. mbedtls_ssl_tls13_make_traffic_keys().
*
* This function implements one step in this evolution of secrets:
*
* <tt>
* old_secret
* |
* v
* Derive-Secret( ., "derived", "" )
* |
* v
* input -> HKDF-Extract = new_secret
* </tt>
*
* \param hash_alg The identifier for the hash function used for the
* applications of HKDF.
* \param secret_old The address of the buffer holding the old secret
* on function entry. If not \c NULL, this must be a
* readable buffer whose size matches the output size
* of the hash function represented by \p hash_alg.
* If \c NULL, an all \c 0 array will be used instead.
* \param input The address of the buffer holding the additional
* input for the key derivation (e.g., the PSK or the
* ephemeral (EC)DH secret). If not \c NULL, this must be
* a readable buffer whose size \p input_len Bytes.
* If \c NULL, an all \c 0 array will be used instead.
* \param input_len The length of \p input in Bytes.
* \param secret_new The address of the buffer holding the new secret
* on function exit. This must be a writable buffer
* whose size matches the output size of the hash
* function represented by \p hash_alg.
* This may be the same as \p secret_old.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_evolve_secret(
psa_algorithm_t hash_alg,
const unsigned char *secret_old,
const unsigned char *input, size_t input_len,
unsigned char *secret_new);
/**
* \brief Calculate a TLS 1.3 PSK binder.
*
* \param ssl The SSL context. This is used for debugging only and may
* be \c NULL if MBEDTLS_DEBUG_C is disabled.
* \param hash_alg The hash algorithm associated to the PSK \p psk.
* \param psk The buffer holding the PSK for which to create a binder.
* \param psk_len The size of \p psk in bytes.
* \param psk_type This indicates whether the PSK \p psk is externally
* provisioned (#MBEDTLS_SSL_TLS1_3_PSK_EXTERNAL) or a
* resumption PSK (#MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION).
* \param transcript The handshake transcript up to the point where the
* PSK binder calculation happens. This must be readable,
* and its size must be equal to the digest size of
* the hash algorithm represented by \p hash_alg.
* \param result The address at which to store the PSK binder on success.
* This must be writable, and its size must be equal to the
* digest size of the hash algorithm represented by
* \p hash_alg.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_create_psk_binder(mbedtls_ssl_context *ssl,
const psa_algorithm_t hash_alg,
unsigned char const *psk, size_t psk_len,
int psk_type,
unsigned char const *transcript,
unsigned char *result);
/**
* \bref Setup an SSL transform structure representing the
* record protection mechanism used by TLS 1.3
*
* \param transform The SSL transform structure to be created. This must have
* been initialized through mbedtls_ssl_transform_init() and
* not used in any other way prior to calling this function.
* In particular, this function does not clean up the
* transform structure prior to installing the new keys.
* \param endpoint Indicates whether the transform is for the client
* (value #MBEDTLS_SSL_IS_CLIENT) or the server
* (value #MBEDTLS_SSL_IS_SERVER).
* \param ciphersuite The numerical identifier for the ciphersuite to use.
* This must be one of the identifiers listed in
* ssl_ciphersuites.h.
* \param traffic_keys The key material to use. No reference is stored in
* the SSL transform being generated, and the caller
* should destroy the key material afterwards.
* \param ssl (Debug-only) The SSL context to use for debug output
* in case of failure. This parameter is only needed if
* #MBEDTLS_DEBUG_C is set, and is ignored otherwise.
*
* \return \c 0 on success. In this case, \p transform is ready to
* be used with mbedtls_ssl_transform_decrypt() and
* mbedtls_ssl_transform_encrypt().
* \return A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_populate_transform(mbedtls_ssl_transform *transform,
int endpoint,
int ciphersuite,
mbedtls_ssl_key_set const *traffic_keys,
mbedtls_ssl_context *ssl);
/*
* TLS 1.3 key schedule evolutions
*
* Early -> Handshake -> Application
*
* Small wrappers around mbedtls_ssl_tls13_evolve_secret().
*/
/**
* \brief Begin TLS 1.3 key schedule by calculating early secret.
*
* The TLS 1.3 key schedule can be viewed as a simple state machine
* with states Initial -> Early -> Handshake -> Application, and
* this function represents the Initial -> Early transition.
*
* \param ssl The SSL context to operate on.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_key_schedule_stage_early(mbedtls_ssl_context *ssl);
/**
* \brief Compute TLS 1.3 resumption master secret.
*
* \param ssl The SSL context to operate on. This must be in
* key schedule stage \c Application, see
* mbedtls_ssl_tls13_key_schedule_stage_application().
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_resumption_master_secret(mbedtls_ssl_context *ssl);
/**
* \brief Calculate the verify_data value for the client or server TLS 1.3
* Finished message.
*
* \param ssl The SSL context to operate on. This must be in
* key schedule stage \c Handshake, see
* mbedtls_ssl_tls13_key_schedule_stage_application().
* \param dst The address at which to write the verify_data value.
* \param dst_len The size of \p dst in bytes.
* \param actual_len The address at which to store the amount of data
* actually written to \p dst upon success.
* \param which The message to calculate the `verify_data` for:
* - #MBEDTLS_SSL_IS_CLIENT for the Client's Finished message
* - #MBEDTLS_SSL_IS_SERVER for the Server's Finished message
*
* \note Both client and server call this function twice, once to
* generate their own Finished message, and once to verify the
* peer's Finished message.
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_calculate_verify_data(mbedtls_ssl_context *ssl,
unsigned char *dst,
size_t dst_len,
size_t *actual_len,
int which);
#if defined(MBEDTLS_SSL_EARLY_DATA)
/**
* \brief Compute TLS 1.3 early transform
*
* \param ssl The SSL context to operate on.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*
* \warning The function does not compute the early master secret. Call
* mbedtls_ssl_tls13_key_schedule_stage_early() before to
* call this function to generate the early master secret.
* \note For a client/server endpoint, the function computes only the
* encryption/decryption part of the transform as the decryption/
* encryption part is not defined by the specification (no early
* traffic from the server to the client).
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_early_transform(mbedtls_ssl_context *ssl);
#endif /* MBEDTLS_SSL_EARLY_DATA */
/**
* \brief Compute TLS 1.3 handshake transform
*
* \param ssl The SSL context to operate on. The early secret must have been
* computed.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_handshake_transform(mbedtls_ssl_context *ssl);
/**
* \brief Compute TLS 1.3 application transform
*
* \param ssl The SSL context to operate on. The early secret must have been
* computed.
*
* \returns \c 0 on success.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_compute_application_transform(mbedtls_ssl_context *ssl);
#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
/**
* \brief Export TLS 1.3 PSK from handshake context
*
* \param[in] ssl The SSL context to operate on.
* \param[out] psk PSK output pointer.
* \param[out] psk_len Length of PSK.
*
* \returns \c 0 if there is a configured PSK and it was exported
* successfully.
* \returns A negative error code on failure.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_export_handshake_psk(mbedtls_ssl_context *ssl,
unsigned char **psk,
size_t *psk_len);
#endif
/**
* \brief Calculate TLS-Exporter function as defined in RFC 8446, Section 7.5.
*
* \param[in] hash_alg The hash algorithm.
* \param[in] secret The secret to use. (Should be the exporter master secret.)
* \param[in] secret_len Length of secret.
* \param[in] label The label of the exported key.
* \param[in] label_len The length of label.
* \param[out] out The output buffer for the exported key. Must have room for at least out_len bytes.
* \param[in] out_len Length of the key to generate.
*/
int mbedtls_ssl_tls13_exporter(const psa_algorithm_t hash_alg,
const unsigned char *secret, const size_t secret_len,
const unsigned char *label, const size_t label_len,
const unsigned char *context_value, const size_t context_len,
uint8_t *out, const size_t out_len);
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
#endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */

View File

@@ -145,6 +145,7 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num) {
return 0;
};
void ledcAttachPin(uint8_t pin, uint8_t chan) {};
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num) {};
void ledcWrite(uint8_t chan, uint32_t duty) {};
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) {};

View File

@@ -72,6 +72,7 @@ void analogSetAttenuation(adc_attenuation_t attenuation);
void dacWrite(uint8_t pin, uint8_t value);
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num);
void ledcAttachPin(uint8_t pin, uint8_t chan);
void ledcAttach(uint8_t pin, uint8_t chan, uint8_t bit_num);
void ledcWrite(uint8_t chan, uint32_t duty);
void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);
void rgbLedWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val);

View File

@@ -15,5 +15,5 @@
"itty-router": "^5.0.22",
"prettier": "^3.8.1"
},
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
"packageManager": "pnpm@10.29.3+sha512.498e1fb4cca5aa06c1dcf2611e6fafc50972ffe7189998c409e90de74566444298ffe43e6cd2acdc775ba1aa7cc5e092a8b7054c811ba8c5770f84693d33d2dc"
}

View File

@@ -30,8 +30,8 @@ packages:
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.29.0':
resolution: {integrity: sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==}
'@babel/generator@7.29.1':
resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
engines: {node: '>=6.9.0'}
'@babel/helper-globals@7.28.0':
@@ -183,7 +183,7 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/generator@7.29.0':
'@babel/generator@7.29.1':
dependencies:
'@babel/parser': 7.29.0
'@babel/types': 7.29.0
@@ -210,7 +210,7 @@ snapshots:
'@babel/traverse@7.29.0':
dependencies:
'@babel/code-frame': 7.29.0
'@babel/generator': 7.29.0
'@babel/generator': 7.29.1
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.29.0
'@babel/template': 7.28.6
@@ -248,7 +248,7 @@ snapshots:
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.1)':
dependencies:
'@babel/generator': 7.29.0
'@babel/generator': 7.29.1
'@babel/parser': 7.29.0
'@babel/traverse': 7.29.0
'@babel/types': 7.29.0

View File

@@ -15,14 +15,13 @@ description = EMS-ESP Firmware for the ESP32
src_dir = src
lib_dir = lib
boards_dir = boards
; build_cache_dir = .pio/build_cache
extra_configs =
factory_settings.ini
pio_local.ini
[common]
core_build_flags = -std=c++17 -std=gnu++17 -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format
core_build_flags = -std=c++17 -std=gnu++17 -O3 -flto=auto -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format -Wno-missing-field-initializers
core_unbuild_flags = -std=gnu++11 -fno-lto
my_build_flags =
@@ -54,13 +53,21 @@ build_flags =
unbuild_flags =
${common.core_unbuild_flags}
; 4MB Flash variants
[espressif32_base_4M]
framework = arduino
board_build.partitions = partitions/esp32_partition_4M.csv
board_upload.flash_size = 4MB
board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
; 16MB Flash variants
[espressif32_base_16M]
framework = arduino
board_build.partitions = partitions/esp32_partition_16M.csv
board_upload.flash_size = 16MB
board_build.app_partition_name = app0
platform = espressif32@6.12.0 ; Arduino Core 2.0.17 / IDF 4.4.7
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
; 32MB Flash variants
[espressif32_base_32M]
@@ -68,29 +75,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_32M.csv
board_upload.flash_size = 32MB
board_build.app_partition_name = app0
platform = espressif32@6.12.0 ; Arduino Core 2.0.17 / IDF 4.4.7
; use Tasmota's library for 4MB Flash variants.
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
[espressif32_base_T_4M]
framework = arduino
board_build.partitions = partitions/esp32_partition_4M.csv
board_upload.flash_size = 4MB
board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
; use Tasmota's library for 16MB Flash variants.
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
[espressif32_base_T_16M]
framework = arduino
board_build.partitions = partitions/esp32_partition_16M.csv
board_upload.flash_size = 16MB
board_build.app_partition_name = app0
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ; Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8
; Tasmota Arduino Core 3.1.3.250302 based on IDF 5.3.2.250228
; platform = https://github.com/tasmota/platform-espressif32/releases/download/2025.03.30/platform-espressif32.zip
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.02.30/platform-espressif32.zip ; Tasmota Arduino Core 3.1.10 based on IDF 5.3.4.20260127
[env]
build_flags =
@@ -106,9 +91,8 @@ board_build.filesystem = littlefs
lib_deps =
bblanchon/ArduinoJson @ 7.4.2
ESP32Async/AsyncTCP @ 3.4.10
ESP32Async/ESPAsyncWebServer @ 3.9.6
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
ESP32Async/ESPAsyncWebServer @ 3.10.0
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
; builds the web interface only, not the firmware
[env:build_webUI]
@@ -120,18 +104,17 @@ build_src_filter = -<*>
;
; Builds for different board types
; We use Tasmota for boards without PSRAM as this framework has mbedtls removed to save memory.
; If you're building for a single target environment, we recommend creating a pio_local.ini (see example file)
;
[env:s_4M]
; 4MB ESP32 - no SSL, no PSRAM - like a BBQKees older S32 and E32 models - uses Tasmota
extends = espressif32_base_T_4M
; 4MB ESP32 - no SSL, no PSRAM - like a BBQKees older S32 and E32 models
extends = espressif32_base_4M
board = s_4M
[env:s_16M]
; 16MB ESP32 - no PSRAM - like a BBQKees later S32 V2 models - uses Tasmota
extends = espressif32_base_T_16M
; 16MB ESP32 - no PSRAM - like a BBQKees later S32 V2 models
extends = espressif32_base_16M
board = s_16M
[env:s_16M_P]
@@ -150,19 +133,19 @@ extends = espressif32_base_32M
board = s3_32M_P
[env:s2_4M_P]
; based on lolin_s2_mini 4MB with 2MB PSRAM - uses Tasmota
extends = espressif32_base_T_4M
; based on lolin_s2_mini 4MB with 2MB PSRAM
extends = espressif32_base_4M
board = s2_4M_P
[env:c3_mini_4M]
; based on lolin_c3_mini 4MB, no PSRAM - uses Tasmota
extends = espressif32_base_T_4M
; based on lolin_c3_mini 4MB, no PSRAM
extends = espressif32_base_4M
board = c3_mini_4M
; lolin C3 mini v1 needs special wifi initialization
; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
[env:c3_miniv1_4M]
extends = espressif32_base_T_4M
extends = espressif32_base_4M
board = c3_mini_4M
build_flags =
${common.build_flags}
@@ -174,8 +157,7 @@ framework = arduino
board_build.partitions = partitions/esp32_partition_4M.csv
board_upload.flash_size = 4MB
board_build.app_partition_name = app0
platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.21-2/platform-espressif32.zip ; Arduino Release v3.2.1 based on ESP-IDF v5.4.2
; platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip ; Arduino Release v3.3.0 based on ESP-IDF v5.5.0
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip ; Arduino Release v3.3.0 based on ESP-IDF v5.5.0
board = seeed_xiao_esp32c6
build_flags =
${common.build_flags}
@@ -190,6 +172,7 @@ build_flags =
build_src_flags =
-DEMSESP_STANDALONE -DEMSESP_TEST
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
-DNO_TLS_SUPPORT
-std=gnu++17 -Og -ggdb
-Wall -Wextra
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
@@ -212,6 +195,8 @@ build_src_filter =
-<../lib/uuid-syslog>
-<../lib/eModbus>
-<../lib/OneWire>
-<../lib/mbedtls_ssl/src>
-<../src/core/ModuleLibrary.cpp>
lib_ldf_mode = off
lib_deps =
@@ -228,6 +213,7 @@ build_src_flags =
-DEMSESP_STANDALONE -DEMSESP_TEST
-DEMSESP_UNITY
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
-DNO_TLS_SUPPORT
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
-std=gnu++17 -Og -ggdb
-Wall -Wextra
@@ -254,6 +240,8 @@ build_src_filter =
-<../lib/uuid-syslog>
-<../lib/eModbus>
-<../lib/OneWire>
-<../lib/mbedtls_ssl/src>
-<../src/core/ModuleLibrary.cpp>
lib_ldf_mode = off
lib_deps = Unity
test_testing_command =

View File

@@ -1324,3 +1324,4 @@ zyxwvutsrqponmlkjihgfedcba
ACAO
ACAH
ACAC
coolingtype

View File

@@ -10,7 +10,6 @@ APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityM
, _reconfigureAp(false)
, _connected(0) {
addUpdateHandler([this] { reconfigureAP(); }, false);
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
}
void APSettingsService::begin() {
@@ -19,39 +18,27 @@ void APSettingsService::begin() {
// reconfigureAP();
}
// wait 10 sec on STA disconnect before starting AP
void APSettingsService::WiFiEvent(WiFiEvent_t event) {
const uint8_t was_connected = _connected;
switch (event) {
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
_connected &= ~1U;
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
_connected &= ~2U;
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
_connected |= 1U;
break;
case ARDUINO_EVENT_ETH_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP6:
_connected |= 2U;
break;
default:
return;
}
// wait 10 sec before starting AP
if (was_connected && !_connected) {
_lastManaged = uuid::get_uptime();
}
}
void APSettingsService::reconfigureAP() {
_lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY;
_reconfigureAp = true;
}
void APSettingsService::loop() {
const uint8_t was_connected = _connected;
if (WiFi.isConnected()) {
_connected |= 1U;
} else {
_connected &= ~1U;
}
if (ETH.connected()) {
_connected |= 2U;
} else {
_connected &= ~2U;
}
// wait 10 sec before starting AP
if (was_connected && !_connected) {
_lastManaged = uuid::get_uptime();
}
const unsigned long currentMillis = uuid::get_uptime();
if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) {
_lastManaged = currentMillis;
@@ -76,11 +63,7 @@ void APSettingsService::manageAP() {
}
void APSettingsService::startAP() {
#if ESP_IDF_VERSION_MAJOR < 5
WiFi.softAPenableIpV6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
#else
WiFi.softAPenableIPv6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
#endif
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);

View File

@@ -104,7 +104,6 @@ class APSettingsService : public StatefulService<APSettings> {
void startAP();
void stopAP();
void handleDNS();
void WiFiEvent(WiFiEvent_t event);
};
#endif

View File

@@ -66,21 +66,16 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) {
}
/*
* ESP32 uses mbedtls, with decent HMAC implementations supporting sha256, as well as others.
* No need to pull in additional crypto libraries - lets use what we already have.
* HMAC-SHA256 using mbedtls
*/
String ArduinoJsonJWT::sign(String & payload) {
std::array<unsigned char, 32> hmacResult{};
{
mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
mbedtls_md_hmac_starts(&ctx, reinterpret_cast<const unsigned char *>(_secret.c_str()), _secret.length());
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length());
mbedtls_md_hmac_finish(&ctx, hmacResult.data());
mbedtls_md_free(&ctx);
}
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
reinterpret_cast<const unsigned char *>(_secret.c_str()),
_secret.length(),
reinterpret_cast<const unsigned char *>(payload.c_str()),
payload.length(),
hmacResult.data());
return encode(reinterpret_cast<const char *>(hmacResult.data()), hmacResult.size());
}

View File

@@ -84,4 +84,5 @@ void ESP32React::loop() {
_networkSettingsService.loop();
_apSettingsService.loop();
_mqttSettingsService.loop();
_ntpSettingsService.loop();
}

View File

@@ -9,7 +9,6 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
, _disconnectedAt(0)
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
, _mqttClient(nullptr) {
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
addUpdateHandler([this] { onConfigUpdated(); }, false);
}
@@ -29,6 +28,7 @@ MqttSettingsService::~MqttSettingsService() {
void MqttSettingsService::begin() {
_fsPersistence.readFromFS();
startClient();
_reconfigureMqtt = true;
}
void MqttSettingsService::startClient() {
@@ -41,7 +41,7 @@ void MqttSettingsService::startClient() {
delete _mqttClient;
_mqttClient = nullptr;
}
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
if (_state.enableTLS) {
isSecure = true;
if (emsesp::EMSESP::system_.PSram() == 0) {
@@ -79,6 +79,10 @@ void MqttSettingsService::startClient() {
}
void MqttSettingsService::loop() {
if (_state.enabled && _mqttClient && _mqttClient->connected() && !emsesp::EMSESP::system_.network_connected()) {
// emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client");
_mqttClient->disconnect(true);
}
if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
// reconfigure MQTT client
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
@@ -142,28 +146,6 @@ void MqttSettingsService::onConfigUpdated() {
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
}
void MqttSettingsService::WiFiEvent(WiFiEvent_t event) {
switch (event) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP6:
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
if (_state.enabled && !_mqttClient->connected()) {
onConfigUpdated();
}
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
case ARDUINO_EVENT_ETH_DISCONNECTED:
if (_state.enabled) {
_mqttClient->disconnect(true);
}
break;
default:
break;
}
}
bool MqttSettingsService::configureMqtt() {
// disconnect if already connected
if (_mqttClient->connected()) {
@@ -182,7 +164,7 @@ bool MqttSettingsService::configureMqtt() {
}
_reconfigureMqtt = false;
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
if (_state.enableTLS) {
if (_state.rootCA == "insecure") {
emsesp::EMSESP::logger().debug("Start insecure MQTT");
@@ -219,7 +201,7 @@ bool MqttSettingsService::configureMqtt() {
}
void MqttSettings::read(MqttSettings & settings, JsonObject root) {
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
root["enableTLS"] = settings.enableTLS;
root["rootCA"] = settings.rootCA;
#endif
@@ -256,9 +238,9 @@ void MqttSettings::read(MqttSettings & settings, JsonObject root) {
StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) {
MqttSettings newSettings;
bool changed = false;
bool changed = false;
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
newSettings.enableTLS = root["enableTLS"];
newSettings.rootCA = root["rootCA"] | "";
#else
@@ -316,6 +298,10 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
changed = true;
}
if (newSettings.ha_number_mode != settings.ha_number_mode) {
changed = true;
}
if (newSettings.entity_format != settings.entity_format) {
changed = true;
}
@@ -385,7 +371,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
}
#ifndef TASMOTA_SDK
#ifndef NO_TLS_SUPPORT
// strip down to certificate only
newSettings.rootCA.replace("\r", "");
newSettings.rootCA.replace("\n", "");

View File

@@ -134,7 +134,6 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
// the MQTT client instance
MqttClient * _mqttClient;
void WiFiEvent(WiFiEvent_t event);
void onMqttConnect(bool sessionPresent);
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
void

View File

@@ -11,7 +11,6 @@ NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, Securit
configureTime(request, json);
});
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
addUpdateHandler([this] { configureNTP(); }, false);
}
@@ -20,27 +19,10 @@ void NTPSettingsService::begin() {
configureNTP();
}
// handles both WiFI and Ethernet
void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
switch (event) {
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
case ARDUINO_EVENT_ETH_DISCONNECTED:
if (_connected && emsesp::EMSESP::system_.ntp_connected()) {
emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP");
_connected = false;
configureNTP();
}
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP:
// emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization");
_connected = true;
void NTPSettingsService::loop() {
if (_connected != emsesp::EMSESP::system_.network_connected()) {
_connected = emsesp::EMSESP::system_.network_connected();
configureNTP();
break;
default:
break;
}
}
@@ -55,7 +37,9 @@ void NTPSettingsService::configureNTP() {
} else {
setenv("TZ", _state.tzFormat.c_str(), 1);
tzset();
esp_sntp_stop();
if (esp_sntp_enabled()) {
esp_sntp_stop();
}
}
}

View File

@@ -44,6 +44,7 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
void begin();
void loop();
static void ntp_received(struct timeval * tv);
private:
@@ -51,7 +52,6 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
FSPersistence<NTPSettings> _fsPersistence;
volatile bool _connected;
void WiFiEvent(WiFiEvent_t event);
void configureNTP();
void configureTime(AsyncWebServerRequest * request, JsonVariant json);
};

View File

@@ -9,7 +9,7 @@ NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs,
, _stopping(false) {
addUpdateHandler([this] { reconfigureWiFiConnection(); }, false);
// Eth is also bound to the WifiGeneric event handler
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event, info); });
// Network.onEvent([this](arduino_event_id_t event, arduino_event_info_t info) { WiFiEvent(event, info); });
}
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
@@ -62,24 +62,68 @@ void NetworkSettingsService::loop() {
_lastConnectionAttempt = currentMillis;
manageSTA();
}
static uint8_t connect = 0;
enum uint8_t { CONNECT_IDLE = 0, CONNECT_WAIT_ETH, CONNECT_ETH_ACTIVE, CONNECT_WIFI_ACTIVE };
switch (connect) {
default:
connect = CONNECT_IDLE;
break;
case CONNECT_IDLE:
if (ETH.started() && _state.ssid.length() == 0) {
emsesp::EMSESP::logger().info("ETH started");
connect = CONNECT_WAIT_ETH;
ETH.enableIPv6(true);
if (_state.staticIPConfig) {
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
}
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
}
if (WiFi.isConnected()) {
emsesp::EMSESP::logger().info("Wifi connected");
connect = CONNECT_WIFI_ACTIVE;
if (_state.tx_power == 0) {
setWiFiPowerOnRSSI();
}
mDNS_start();
}
break;
case CONNECT_WAIT_ETH:
if (ETH.connected()) {
emsesp::EMSESP::logger().info("ETH connected");
connect = CONNECT_ETH_ACTIVE;
emsesp::EMSESP::system_.ethernet_connected(true);
mDNS_start();
}
break;
case CONNECT_ETH_ACTIVE:
if (!ETH.connected()) {
emsesp::EMSESP::logger().info("ETH disconnected");
emsesp::EMSESP::system_.ethernet_connected(false);
connect = CONNECT_IDLE;
}
break;
case CONNECT_WIFI_ACTIVE:
if (!WiFi.isConnected()) {
emsesp::EMSESP::logger().info("WiFi disconnected");
connect = CONNECT_IDLE;
if (_stopping) {
_lastConnectionAttempt = 0;
_stopping = false;
}
}
break;
}
}
void NetworkSettingsService::manageSTA() {
// Abort if already connected, or if we have no SSID
if (WiFi.isConnected() || _state.ssid.length() == 0) {
#if ESP_IDF_VERSION_MAJOR >= 5
if (_state.ssid.length() == 0) {
ETH.enableIPv6(true);
}
#endif
return;
}
// Connect or reconnect as required
if ((WiFi.getMode() & WIFI_STA) == 0) {
#if ESP_IDF_VERSION_MAJOR >= 5
WiFi.enableIPv6(true);
#endif
if (_state.staticIPConfig) {
WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); // configure for static IP
}
@@ -293,7 +337,7 @@ const char * NetworkSettingsService::disconnectReason(uint8_t code) {
}
// handles both WiFI and Ethernet
void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
void NetworkSettingsService::WiFiEvent(arduino_event_id_t event, arduino_event_info_t info) {
#ifndef EMSESP_STANDALONE
switch (event) {
@@ -305,7 +349,7 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
connectcount_++; // count the number of WiFi reconnects
connectcount_ = connectcount_ + 1; // count the number of WiFi reconnects
emsesp::EMSESP::logger().warning("WiFi disconnected (#%d). Reason: %s (%d)",
connectcount_,
disconnectReason(info.wifi_sta_disconnected.reason),
@@ -360,25 +404,15 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
if (_state.tx_power == 0) {
setWiFiPowerOnRSSI();
}
#if ESP_IDF_VERSION_MAJOR < 5
WiFi.enableIpV6(); // force ipv6
#endif
break;
case ARDUINO_EVENT_ETH_CONNECTED:
#if ESP_IDF_VERSION_MAJOR < 5
ETH.enableIpV6(); // force ipv6
#endif
break;
// IPv6 specific - WiFi/Eth
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
case ARDUINO_EVENT_ETH_GOT_IP6: {
#if !TASMOTA_SDK && ESP_IDF_VERSION_MAJOR < 5
auto ip6 = IPv6Address((uint8_t *)info.got_ip6.ip6_info.ip.addr).toString();
#else
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
#endif
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
const char * link = event == ARDUINO_EVENT_ETH_GOT_IP6 ? "Eth" : "WiFi";
if (ip6.startsWith("fe80")) {
emsesp::EMSESP::logger().info("IPv6 (%s) local: %s", link, ip6.c_str());

View File

@@ -107,7 +107,7 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
volatile uint16_t connectcount_ = 0; // number of wifi reconnects
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
void WiFiEvent(arduino_event_id_t event, arduino_event_info_t info);
void mDNS_start() const;
const char * disconnectReason(uint8_t code);
void reconfigureWiFiConnection();

View File

@@ -2,7 +2,7 @@
#include <emsesp.h>
#ifdef TASMOTA_SDK
#ifdef NO_TLS_SUPPORT
#include "lwip/dns.h"
#endif
@@ -31,22 +31,13 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
// for both connections show ethernet
if (ethernet_connected) {
// Ethernet
root["local_ip"] = ETH.localIP().toString();
#if ESP_IDF_VERSION_MAJOR < 5
root["local_ipv6"] = ETH.localIPv6().toString();
#else
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
#endif
root["local_ip"] = ETH.localIP().toString();
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
root["mac_address"] = ETH.macAddress();
root["subnet_mask"] = ETH.subnetMask().toString();
root["gateway_ip"] = ETH.gatewayIP().toString();
#ifdef TASMOTA_SDK
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
#else
IPAddress dnsIP1 = ETH.dnsIP(0);
IPAddress dnsIP2 = ETH.dnsIP(1);
#endif
IPAddress dnsIP1 = ETH.dnsIP(0);
IPAddress dnsIP2 = ETH.dnsIP(1);
if (IPUtils::isSet(dnsIP1)) {
root["dns_ip_1"] = dnsIP1.toString();
}
@@ -54,12 +45,8 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
root["dns_ip_2"] = dnsIP2.toString();
}
} else if (wifi_status == WL_CONNECTED) {
root["local_ip"] = WiFi.localIP().toString();
#if ESP_IDF_VERSION_MAJOR < 5
root["local_ipv6"] = WiFi.localIPv6().toString();
#else
root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
#endif
root["local_ip"] = WiFi.localIP().toString();
root["local_ipv6"] = WiFi.linkLocalIPv6().toString();
root["mac_address"] = WiFi.macAddress();
root["rssi"] = WiFi.RSSI();
root["ssid"] = WiFi.SSID();
@@ -71,14 +58,8 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
if (WiFi.gatewayIP() != INADDR_NONE) {
root["gateway_ip"] = WiFi.gatewayIP().toString();
}
#ifdef TASMOTA_SDK
IPAddress dnsIP1 = IPAddress(dns_getserver(0));
IPAddress dnsIP2 = IPAddress(dns_getserver(1));
#else
IPAddress dnsIP1 = WiFi.dnsIP(0);
IPAddress dnsIP2 = WiFi.dnsIP(1);
#endif
if (dnsIP1 != INADDR_NONE) {
root["dns_ip_1"] = dnsIP1.toString();
}

View File

@@ -0,0 +1,31 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include <emsesp.h>
void ModuleLibrary::list(JsonObject output) {};
void ModuleLibrary::loop() {};
void ModuleLibrary::start(emsesp::EMSESP * emsesp_main, bool test_mode) {};
bool ModuleLibrary::enable(const char * key, const char * license, bool enable) {
return true;
};

52
src/core/ModuleLibrary.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MODULELIBRARY_H
#define MODULELIBRARY_H
#include <Arduino.h>
#include <memory>
#include <vector>
#include <emsesp.h>
class ModuleLibrary {
public:
class Modules {
public:
Modules(const char * key, std::unique_ptr<Module> module)
: key(key)
, module(std::move(module)) {
}
const char * key;
std::unique_ptr<Module> module;
};
void start(emsesp::EMSESP * emsesp_main, bool test_mode = false);
void loop();
void list(JsonObject output);
bool enable(const char * key, const char * license, bool enable);
static uuid::log::Logger logger_;
private:
std::vector<Modules> modules_;
};
#endif

View File

@@ -346,23 +346,13 @@ void AnalogSensor::reload(bool get_nvs) {
sensor.polltime_ = sensor.value() != 0 ? uuid::get_uptime() + (sensor.factor() * 1000) : 0;
} else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) {
LOG_DEBUG("PWM output on GPIO %02d", sensor.gpio());
#if ESP_IDF_VERSION_MAJOR >= 5
ledcAttach(sensor.gpio(), sensor.factor(), 13);
#else
uint8_t channel = sensor.type() - AnalogType::PWM_0;
ledcSetup(channel, sensor.factor(), 13);
ledcAttachPin(sensor.gpio(), channel);
#endif
if (sensor.offset() > 100) {
sensor.set_offset(100);
} else if (sensor.offset() < 0) {
sensor.set_offset(0);
}
#if ESP_IDF_VERSION_MAJOR >= 5
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
#else
ledcWrite(channel, (uint32_t)(sensor.offset() * 8191 / 100));
#endif
sensor.set_value(sensor.offset());
sensor.set_uom(DeviceValueUOM::PERCENT);
publish_sensor(sensor);
@@ -1002,12 +992,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) {
}
sensor.set_offset(val);
sensor.set_value(val);
#if ESP_IDF_VERSION_MAJOR >= 5
ledcWrite(sensor.gpio(), (uint32_t)(sensor.offset() * 8191 / 100));
#else
uint8_t channel = sensor.type() - AnalogType::PWM_0;
ledcWrite(channel, (uint32_t)(val * 8191 / 100));
#endif
} else {
return false;
}

View File

@@ -86,6 +86,6 @@ using string_vector = std::vector<const char *>;
// Translation count - dynamically calculated at compile-time
enum { EMSESP_TRANSLATION_COUNT_END = __COUNTER__ };
static constexpr uint16_t EMSESP_TRANSLATION_COUNT = EMSESP_TRANSLATION_COUNT_END - EMSESP_TRANSLATION_COUNT_START - 1;
static constexpr uint16_t EMSESP_TRANSLATION_COUNT = static_cast<int>(EMSESP_TRANSLATION_COUNT_END) - static_cast<int>(EMSESP_TRANSLATION_COUNT_START) - 1;
#endif

View File

@@ -293,12 +293,9 @@ enum {
#ifndef STRINGIZE
#define STRINGIZE(s) #s
#endif
#ifdef TASMOTA_SDK
#define ARDUINO_VERSION_STR(major, minor, patch) "Tasmota Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
#else
#define ARDUINO_VERSION_STR(major, minor, patch) "ESP32 Arduino v" STRINGIZE(major) "." STRINGIZE(minor) "." STRINGIZE(patch)
#endif
#define ARDUINO_VERSION ARDUINO_VERSION_STR(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
#endif
#endif
#endif

View File

@@ -72,6 +72,21 @@ const char * EMSdevice::tag_to_mqtt(int8_t tag) {
return (DeviceValue::DeviceValueTAG_mqtt[tag > DeviceValue::NUM_TAGS ? 0 : tag]);
}
uint8_t EMSdevice::tag_to_flag(const uint8_t tag) {
if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) {
return CommandFlag::CMD_FLAG_HC;
} else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) {
return CommandFlag::CMD_FLAG_DHW;
} else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) {
return CommandFlag::CMD_FLAG_HS;
} else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) {
return CommandFlag::CMD_FLAG_AHS;
} else if (tag >= DeviceValueTAG::TAG_SRC1 && tag <= DeviceValueTAG::TAG_SRC16) {
return CommandFlag::CMD_FLAG_SRC;
}
return 0;
}
// convert UOM to a char string - translating only for hours/minutes/seconds
const char * EMSdevice::uom_to_string(uint8_t uom) {
switch (uom) {
@@ -90,6 +105,9 @@ const char * EMSdevice::uom_to_string(uint8_t uom) {
}
const char * EMSdevice::brand_to_char() {
if (!custom_brand().empty()) {
return custom_brand().c_str();
}
switch (brand_) {
case EMSdevice::Brand::BOSCH:
return F_(bosch);
@@ -316,7 +334,7 @@ std::string EMSdevice::to_string() {
return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
}
if (brand_ == Brand::NO_BRAND) {
if (brand_ == Brand::NO_BRAND && custom_brand().empty()) {
return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")";
}
@@ -332,7 +350,7 @@ std::string EMSdevice::to_string_version() {
// returns out brand + device name
// translated
std::string EMSdevice::to_string_short() {
if (brand_ == Brand::NO_BRAND) {
if (brand_ == Brand::NO_BRAND && custom_brand().empty()) {
return std::string(device_type_2_device_name_translated()) + ": " + name();
}
@@ -650,25 +668,21 @@ void EMSdevice::add_device_value(int8_t tag, // to b
// add a new command if it has a function attached
if (has_cmd) {
uint8_t flags = CommandFlag::ADMIN_ONLY; // executing commands require admin privileges
if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) {
flags |= CommandFlag::CMD_FLAG_HC;
} else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) {
flags |= CommandFlag::CMD_FLAG_DHW;
} else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) {
flags |= CommandFlag::CMD_FLAG_HS;
} else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) {
flags |= CommandFlag::CMD_FLAG_AHS;
} else if (tag >= DeviceValueTAG::TAG_SRC1 && tag <= DeviceValueTAG::TAG_SRC16) {
flags |= CommandFlag::CMD_FLAG_SRC;
}
uint8_t flags = CommandFlag::ADMIN_ONLY | tag_to_flag(tag); // executing commands require admin privileges
// add the command to our library
Command::add(device_type_, device_id_, short_name, f, fullname, flags);
}
}
void EMSdevice::erase_device_values() {
for (auto & dv : devicevalues_) {
if (dv.has_cmd) {
Command::erase_command(device_type_, dv.short_name, tag_to_flag(dv.tag));
}
}
devicevalues_.clear();
}
// single list of options
void EMSdevice::register_device_value(int8_t tag,
void * value_p,
@@ -2121,7 +2135,7 @@ void EMSdevice::mqtt_ha_entity_config_create() {
if (needs_update) {
const char * const ** mode_options = nullptr;
for (auto & d : devicevalues_) {
for (const auto & d : devicevalues_) {
// make sure mode in same circuit is DeviceValueType::ENUM
if ((d.tag == dv.tag) && (d.type == DeviceValueType::ENUM) && !strcmp(d.short_name, FL_(mode)[0]) && (d.options_size > 0)) {
// get options
@@ -2146,26 +2160,32 @@ void EMSdevice::mqtt_ha_entity_config_create() {
if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && dv.has_state(DeviceValueState::DV_ACTIVE)
&& !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) {
// create_device_config is only done once for the EMS device. It can added to any entity, so we take the first
if (Mqtt::publish_ha_sensor_config_dv(dv, name().c_str(), brand_to_char(), to_string_version().c_str(), false, create_device_config)) {
if (Mqtt::publish_ha_sensor_config_dv(dv, name().c_str(), std::string(brand_to_char()).c_str(), to_string_version().c_str(), false, create_device_config)) {
dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED);
create_device_config = false; // only create the main config once
count++;
}
// SRC thermostats mapped to connect/src1/... always contains mode, seltemp, currtemp
if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(mode)[0])) {
// add icon if we have one
const char * icon = nullptr;
for (auto & d : devicevalues_) {
if (d.tag == dv.tag && !strcmp(d.short_name, FL_(icon)[0]) && (dv.type == DeviceValueType::ENUM)) {
if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(seltemp)[0])) {
// add modes and icon if we have one
const char * icon = nullptr;
const char * const ** mode_options = nullptr;
for (const auto & d : devicevalues_) {
if ((d.tag != dv.tag) || (d.type != DeviceValueType::ENUM)) {
continue;
}
if (!strcmp(d.short_name, FL_(mode)[0]) && (d.options_size > 0)) {
mode_options = d.options;
}
if (!strcmp(d.short_name, FL_(icon)[0])) {
uint8_t val = *(uint8_t *)(d.value_p);
if (val != 0 && val < d.options_size) {
icon = d.options[val][0];
}
break;
}
}
Mqtt::publish_ha_climate_config(dv, true, dv.options, false, icon);
Mqtt::publish_ha_climate_config(dv, true, mode_options, false, icon);
count++;
}

View File

@@ -55,6 +55,7 @@ class EMSdevice {
static const char * tag_to_mqtt(int8_t tag);
static uint8_t decode_brand(uint8_t value);
static bool export_values(uint8_t device_type, JsonObject output, const int8_t id, const uint8_t output_target);
static uint8_t tag_to_flag(const uint8_t tag);
// non static functions
@@ -124,6 +125,14 @@ class EMSdevice {
return custom_name_;
}
// set custom brand
void custom_brand(std::string const & custom_brand) {
custom_brand_ = custom_brand;
}
std::string custom_brand() const {
return custom_brand_;
}
// set device model
void model(std::string const & model) {
model_ = model;
@@ -282,6 +291,8 @@ class EMSdevice {
int16_t min,
uint32_t max);
void erase_device_values();
void
register_device_value(int8_t tag, void * value_p, uint8_t type, const char * const ** options, const char * const * name, uint8_t uom, const cmd_function_p f);
@@ -524,12 +535,13 @@ class EMSdevice {
uint8_t device_id_ = 0;
uint8_t product_id_ = 0;
char version_[6];
const char * default_name_; // the fixed name the EMS model taken from the device library
std::string custom_name_ = ""; // custom name
std::string model_ = ""; // model, taken from the 0x01 telegram. see process_deviceName()
uint8_t flags_ = 0;
uint8_t brand_ = Brand::NO_BRAND;
bool active_ = true;
const char * default_name_; // the fixed name the EMS model taken from the device library
std::string custom_name_ = ""; // custom name
std::string custom_brand_ = ""; // custom brand
std::string model_ = ""; // model, taken from the 0x01 telegram. see process_deviceName()
uint8_t flags_ = 0;
uint8_t brand_ = Brand::NO_BRAND;
bool active_ = true;
bool ha_config_done_ = false;
bool has_update_ = false;

View File

@@ -1310,6 +1310,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
if (product_id == 0 || (*it)->product_id() != 0) { // update only with valid product_id
return true;
}
(*it)->erase_device_values();
emsdevices.erase(it); // erase the old device without product_id and re detect
break;
}
@@ -1450,6 +1451,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
if ((e.device_id == device_id) && (e.product_id == product_id)) {
LOG_DEBUG("Have customizations for %s with deviceID 0x%02X productID %d", e.custom_name.c_str(), device_id, product_id);
emsdevices.back()->custom_name(e.custom_name);
emsdevices.back()->custom_brand(e.custom_brand);
break;
}
}
@@ -1760,7 +1762,7 @@ void EMSESP::start() {
nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs
}
LOG_DEBUG("NVS device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str());
LOG_DEBUG("Fuse device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str());
webSettingsService.begin(); // load EMS-ESP Application settings

View File

@@ -1545,9 +1545,7 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool crea
// add mf (manufacturer/brand), mdl (model), sw (software version) and via_device
dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP";
if (model != nullptr) {
dev_json["mdl"] = model;
}
dev_json["mdl"] = model != nullptr ? model : "EMS-ESP";
dev_json["sw"] = version != nullptr ? version : "v" + std::string(EMSESP_APP_VERSION);
dev_json["via_device"] = Mqtt::basename();
}

View File

@@ -604,20 +604,11 @@ void System::start() {
appfree_ = esp_ota_get_running_partition()->size / 1024 - appused_;
refreshHeapMem(); // refresh free heap and max alloc heap
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR < 5
temp_sensor_config_t temp_sensor = TSENS_CONFIG_DEFAULT();
temp_sensor_get_config(&temp_sensor);
temp_sensor.dac_offset = TSENS_DAC_DEFAULT; // DEFAULT: range:-10℃ ~ 80℃, error < 1℃.
temp_sensor_set_config(temp_sensor);
temp_sensor_start();
temp_sensor_read_celsius(&temperature_);
#else
temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
temperature_sensor_install(&temp_sensor_config, &temperature_handle_);
temperature_sensor_enable(temperature_handle_);
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
#endif
#endif
#endif
EMSESP::esp32React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
@@ -838,16 +829,9 @@ void System::send_info_mqtt() {
doc["IPv4 gateway"] = uuid::printable_to_string(WiFi.gatewayIP());
doc["IPv4 nameserver"] = uuid::printable_to_string(WiFi.dnsIP());
#if ESP_IDF_VERSION_MAJOR < 5
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
doc["IPv6 address"] = uuid::printable_to_string(WiFi.localIPv6());
}
#else
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
doc["IPv6 address"] = uuid::printable_to_string(WiFi.linkLocalIPv6());
}
#endif
}
#endif
Mqtt::queue_publish_retain(F_(info), doc.as<JsonObject>()); // topic called "info" and it's Retained
@@ -956,13 +940,8 @@ void System::network_init() {
delay(500);
digitalWrite(eth_power_, HIGH);
}
#if ESP_IDF_VERSION_MAJOR < 5
eth_present_ = ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
#else
eth_present_ = ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode);
#endif
#endif
}
// check health of system, done every 5 seconds
@@ -973,13 +952,9 @@ void System::system_check() {
#ifndef EMSESP_STANDALONE
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR < 5
temp_sensor_read_celsius(&temperature_);
#else
temperature_sensor_get_celsius(temperature_handle_, &temperature_);
#endif
#endif
#endif
#ifdef EMSESP_PINGTEST
static uint64_t ping_count = 0;
@@ -1265,16 +1240,9 @@ void System::show_system(uuid::console::Shell & shell) {
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str());
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(WiFi.gatewayIP()).c_str());
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(WiFi.dnsIP()).c_str());
#if ESP_IDF_VERSION_MAJOR < 5
if (WiFi.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.localIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.localIPv6()).c_str());
}
#else
if (WiFi.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && WiFi.linkLocalIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(WiFi.linkLocalIPv6()).c_str());
}
#endif
break;
case WL_CONNECT_FAILED:
@@ -1305,15 +1273,9 @@ void System::show_system(uuid::console::Shell & shell) {
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str());
shell.printfln(" IPv4 gateway: %s", uuid::printable_to_string(ETH.gatewayIP()).c_str());
shell.printfln(" IPv4 nameserver: %s", uuid::printable_to_string(ETH.dnsIP()).c_str());
#if ESP_IDF_VERSION_MAJOR < 5
if (ETH.localIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.localIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.localIPv6()).c_str());
}
#else
if (ETH.linkLocalIPv6().toString() != "0000:0000:0000:0000:0000:0000:0000:0000" && ETH.linkLocalIPv6().toString() != "::") {
shell.printfln(" IPv6 address: %s", uuid::printable_to_string(ETH.linkLocalIPv6()).c_str());
}
#endif
}
shell.println();

View File

@@ -37,11 +37,7 @@
#include <uuid/log.h>
#include <PButton.h>
#if ESP_ARDUINO_VERSION_MAJOR < 3
#define EMSESP_RGB_WRITE neopixelWrite
#else
#define EMSESP_RGB_WRITE rgbLedWrite
#endif
#if CONFIG_IDF_TARGET_ESP32
// there is no official API available on the original ESP32
@@ -49,12 +45,8 @@ extern "C" {
uint8_t temprature_sens_read();
}
#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR < 5
#include "driver/temp_sensor.h"
#else
#include "driver/temperature_sensor.h"
#endif
#endif
using uuid::console::Shell;
@@ -501,9 +493,7 @@ class System {
uint32_t appfree_;
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
#if ESP_IDF_VERSION_MAJOR >= 5
temperature_sensor_handle_t temperature_handle_ = NULL;
#endif
#endif
float temperature_ = 0;
};

View File

@@ -129,15 +129,20 @@ void Connect::process_roomThermostat(std::shared_ptr<const Telegram> telegram) {
}
has_update(telegram, rc->temp_, 0);
has_update(telegram, rc->humidity_, 2); // could show -3 if not set
has_update(telegram, rc->seltemp_, 3);
// make sure we have read mode and icon, needed for ha climate
if (!Mqtt::ha_enabled() || (Helpers::hasValue(rc->mode_) && Helpers::hasValue(rc->icon_))) {
has_update(telegram, rc->seltemp_, 3);
}
// calculate dew temperature
const float k2 = 17.62;
const float k3 = 243.12;
const float t = (float)rc->temp_ / 10;
const float h = (float)rc->humidity_ / 100;
int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h)));
has_update(rc->dewtemp_, dt);
if (rc->humidity_ >= 0 && rc->humidity_ <= 100) {
const float k2 = 17.62;
const float k3 = 243.12;
const float t = (float)rc->temp_ / 10;
const float h = (float)rc->humidity_ / 100;
int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h)));
has_update(rc->dewtemp_, dt);
}
}
// gateway(0x48) W gateway(0x50), ?(0x0B42), data: 01 // icon in offset 0
@@ -221,8 +226,9 @@ bool Connect::set_seltemp(const char * value, const int8_t id) {
}
float v;
if (Helpers::value2float(value, v)) {
// write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
write_command(0xBB5 + rc->room(), rc->mode_ == 0 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
// depends on mode, auto (2 for enum_mode2, 0 for enum_mode8) set in offset 1
write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
// write_command(0xBB5 + rc->room(), rc->mode_ == 0 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
return true;
}
return false;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.8.2-dev.3"
#define EMSESP_APP_VERSION "3.8.2-dev.6"

View File

@@ -52,7 +52,7 @@ void EMSuart::uart_event_task(void * pvParameters) {
uart_read_bytes(EMSUART_NUM, telegram, length, portMAX_DELAY);
EMSESP::incoming_telegram(telegram, (uint8_t)(length - 1));
} else { // flush buffer up to break
uint8_t buf[UART_FIFO_LEN];
uint8_t buf[SOC_UART_FIFO_LEN];
uart_read_bytes(EMSUART_NUM, buf, length, portMAX_DELAY);
}
length = 0;
@@ -74,12 +74,8 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_APB
#if ESP_ARDUINO_VERSION_MAJOR >= 3
,
.flags = {0, 0}
#endif
};
.source_clk = UART_SCLK_APB,
.flags = {0}};
#if defined(EMSUART_RX_INVERT)
inverse_mask |= UART_SIGNAL_RXD_INV;
#endif
@@ -89,7 +85,7 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t
uart_param_config(EMSUART_NUM, &uart_config);
uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_set_line_inverse(EMSUART_NUM, inverse_mask);
uart_driver_install(EMSUART_NUM, UART_FIFO_LEN + 1, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
uart_driver_install(EMSUART_NUM, SOC_UART_FIFO_LEN + 1, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo
uart_set_rx_full_threshold(EMSUART_NUM, 1);
uart_set_rx_timeout(EMSUART_NUM, 0); // disable

View File

@@ -76,10 +76,11 @@ void WebCustomization::read(WebCustomization & customizations, JsonObject root)
// Masked entities customization and custom device name (optional)
JsonArray masked_entitiesJson = root["masked_entities"].to<JsonArray>();
for (const EntityCustomization & entityCustomization : customizations.entityCustomizations) {
JsonObject entityJson = masked_entitiesJson.add<JsonObject>();
entityJson["product_id"] = entityCustomization.product_id;
entityJson["device_id"] = entityCustomization.device_id;
entityJson["custom_name"] = entityCustomization.custom_name;
JsonObject entityJson = masked_entitiesJson.add<JsonObject>();
entityJson["product_id"] = entityCustomization.product_id;
entityJson["device_id"] = entityCustomization.device_id;
entityJson["custom_name"] = entityCustomization.custom_name;
entityJson["custom_brand"] = entityCustomization.custom_brand;
// entries are in the form <XX><shortname>[optional customname] e.g "08heatingactive|heating is on"
JsonArray masked_entityJson = entityJson["entity_ids"].to<JsonArray>();
@@ -134,7 +135,7 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c
analog.type = analogJson["type"];
analog.is_system = analogJson["is_system"] | false;
if (_start && analog.type == EMSESP::analogsensor_.AnalogType::DIGITAL_OUT && analog.uom > DeviceValue::DeviceValueUOM::NONE) {
analog.offset = analog.uom - 1;
analog.offset = analog.uom > 1 ? 1 : 0;
}
customizations.analogCustomizations.push_back(analog); // add to list
}
@@ -146,10 +147,11 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c
if (root["masked_entities"].is<JsonArray>()) {
auto masked_entities = root["masked_entities"].as<JsonArray>();
for (const JsonObject masked_entity : masked_entities) {
auto emsEntity = EntityCustomization();
emsEntity.product_id = masked_entity["product_id"];
emsEntity.device_id = masked_entity["device_id"];
emsEntity.custom_name = masked_entity["custom_name"] | "";
auto emsEntity = EntityCustomization();
emsEntity.product_id = masked_entity["product_id"];
emsEntity.device_id = masked_entity["device_id"];
emsEntity.custom_name = masked_entity["custom_name"] | "";
emsEntity.custom_brand = masked_entity["custom_brand"] | "";
auto masked_entity_ids = masked_entity["entity_ids"].as<JsonArray>();
for (const JsonVariant masked_entity_id : masked_entity_ids) {
@@ -242,17 +244,19 @@ void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, J
uint8_t unique_device_id = json["id"];
// find product id and device id using the unique id
if (emsdevice->unique_id() == unique_device_id) {
uint8_t product_id = emsdevice->product_id();
uint8_t device_id = emsdevice->device_id();
auto custom_name = json["name"].as<std::string>();
uint8_t product_id = emsdevice->product_id();
uint8_t device_id = emsdevice->device_id();
std::string custom_name = json["name"] | "";
std::string custom_brand = json["brand"] | "";
// updates current record or creates a new one
bool entry_exists = false;
update([&](WebCustomization & settings) {
for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) {
if ((*it).product_id == product_id && (*it).device_id == device_id) {
(*it).custom_name = custom_name;
entry_exists = true;
(*it).custom_name = custom_name;
(*it).custom_brand = custom_brand;
entry_exists = true;
break;
} else {
++it;
@@ -262,9 +266,10 @@ void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, J
// if we don't have any customization for this device, create a new entry
if (!entry_exists) {
EntityCustomization new_entry;
new_entry.product_id = product_id;
new_entry.device_id = device_id;
new_entry.custom_name = custom_name;
new_entry.product_id = product_id;
new_entry.device_id = device_id;
new_entry.custom_name = custom_name;
new_entry.custom_brand = custom_brand;
settings.entityCustomizations.push_back(new_entry);
}
@@ -273,6 +278,7 @@ void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, J
// update the EMS Device record real-time
emsdevice->custom_name(custom_name);
emsdevice->custom_brand(custom_brand);
}
}
}
@@ -459,10 +465,11 @@ void WebCustomizationService::load_test_data() {
// EMS entities, mark some as favorites
webCustomization.entityCustomizations.clear();
auto emsEntity = EntityCustomization();
emsEntity.product_id = 123;
emsEntity.device_id = 8;
emsEntity.custom_name = "My Custom Boiler";
auto emsEntity = EntityCustomization();
emsEntity.product_id = 123;
emsEntity.device_id = 8;
emsEntity.custom_name = "My Custom Boiler";
emsEntity.custom_brand = "";
emsEntity.entity_ids.push_back("08heatingactive|is my heating on?");
emsEntity.entity_ids.push_back("08tapwateractive");
emsEntity.entity_ids.push_back("08selflowtemp|<90");
@@ -472,6 +479,7 @@ void WebCustomizationService::load_test_data() {
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice->is_device_id(emsEntity.device_id)) {
emsdevice->custom_name(emsEntity.custom_name);
emsdevice->custom_brand(emsEntity.custom_brand);
break;
}
}

View File

@@ -63,10 +63,11 @@ class AnalogCustomization {
// we use product_id and device_id to make the device unique
class EntityCustomization {
public:
uint8_t product_id; // device's product id
uint8_t device_id; // device's device id
std::string custom_name; // custom device name
std::vector<std::string> entity_ids; // array of entity ids with masks and optional custom fullname
uint8_t product_id; // device's product id
uint8_t device_id; // device's device id
std::string custom_name; // custom device name
std::string custom_brand; // custom brand name
std::vector<std::string> entity_ids; // array of entity ids with masks and optional custom fullname
};
class WebCustomization {

View File

@@ -458,23 +458,14 @@ void WebSettings::set_board_profile(WebSettings & settings) {
#if CONFIG_IDF_TARGET_ESP32
// check for no PSRAM, could be a E32 or S32?
if (!ESP.getPsramSize()) {
#if ESP_ARDUINO_VERSION_MAJOR < 3
if (ETH.begin(1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) {
#else
if (ETH.begin(ETH_PHY_LAN8720, 1, 23, 18, 16, ETH_CLOCK_GPIO0_IN)) {
#endif
settings.board_profile = "E32"; // Ethernet without PSRAM
} else {
settings.board_profile = "S32"; // ESP32 standard WiFi without PSRAM
}
} else {
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
#if ESP_ARDUINO_VERSION_MAJOR < 3
if (ETH.begin(0, 15, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_OUT)) {
#else
// check for boards with PSRAM, could be a E32V2 otherwise default back to the S32
if (ETH.begin(ETH_PHY_LAN8720, 0, 23, 18, 15, ETH_CLOCK_GPIO0_OUT)) {
#endif
if (analogReadMilliVolts(39) > 700) { // core voltage > 2.6V
settings.board_profile = "E32V2_2"; // Ethernet, PSRAM, internal sensors
} else {